1package Pisg::HTMLGenerator; 2 3# $Id: HTMLGenerator.pm,v 1.189 2007/09/07 23:17:23 df7cb Exp $ 4# 5# Copyright and license, as well as documentation(POD) for this module is 6# found at the end of the file. 7 8use strict; 9$^W = 1; 10 11# test for Text::Iconv 12my $have_iconv = 1; 13eval 'use Text::Iconv'; 14$have_iconv = 0 if $@; 15 16sub new 17{ 18 my $type = shift; 19 my %args = @_; 20 my $self = { 21 cfg => $args{cfg}, 22 stats => $args{stats}, 23 users => $args{users}, 24 tmps => $args{tmps}, 25 topactive => {}, 26 }; 27 28 # Import common functions in Pisg::Common 29 require Pisg::Common; 30 Pisg::Common->import(); 31 32 bless($self, $type); 33 return $self; 34} 35 36sub create_output 37{ 38 # This subroutine calls all the subroutines which create their 39 # individual stats. The name of the functions is somewhat saying - if 40 # you don't understand it, most subs have a better explanation in the 41 # sub itself. 42 43 my $self = shift; 44 $self->{cfg}->{lang} = shift; 45 46 # save table width as multiplie files would just increase tablewidth 47 my $tablewidth_original = $self->{cfg}->{tablewidth}; 48 49 # remove old iconv if it exist as it could mess up recode. 50 delete $self->{iconv} if $self->{iconv}; 51 52 my $lang_charset = $self->{tmps}->{$self->{cfg}->{lang}}{lang_charset}; 53 if($lang_charset and $lang_charset ne $self->{cfg}->{charset}) { 54 if($have_iconv) { 55 # convert from template charset to our 56 $self->{iconv} = Text::Iconv->new($lang_charset, $self->{cfg}->{charset}); 57 } else { 58 print "Text::Iconv is not installed, skipping charset conversion of language templates\n" 59 unless ($self->{cfg}->{silent}); 60 } 61 } 62 63 $self->_topactive(); 64 65 if($self->{cfg}->{bignumbersthreshold} =~ /^sqrt/) { 66 $self->{cfg}->{bignumbersthreshold} = int(sqrt($self->{stats}->{topactive_lines})); 67 } 68 69 my $fname = $self->{cfg}->{outputfile}; 70 $fname =~ s/\%t/$self->{cfg}->{outputtag}/g; 71 $fname =~ s/\%l/$self->{cfg}->{lang}/g; 72 print "Now generating HTML ($self->{cfg}->{lang}) in $fname...\n" 73 unless ($self->{cfg}->{silent}); 74 75 open (OUTPUT, "> $fname") or 76 die("$0: Unable to open outputfile($fname): $!\n"); 77 78 if ($self->{cfg}->{showlines}) { 79 $self->{cfg}->{tablewidth} += 40; 80 } 81 if ($self->{cfg}->{showtime}) { 82 $self->{cfg}->{tablewidth} += 40; 83 } 84 if ($self->{cfg}->{showlinetime}) { 85 $self->{cfg}->{tablewidth} += 100; 86 } 87 if ($self->{cfg}->{showwordtime}) { 88 $self->{cfg}->{tablewidth} += 100; 89 } 90 if ($self->{cfg}->{showwords}) { 91 $self->{cfg}->{tablewidth} += 40; 92 } 93 if ($self->{cfg}->{showwpl}) { 94 $self->{cfg}->{tablewidth} += 40; 95 } 96 if ($self->{cfg}->{showcpl}) { 97 $self->{cfg}->{tablewidth} += 40; 98 } 99 if ($self->{cfg}->{userpics}) { 100 $self->{cfg}->{tablewidth} += $self->{cfg}->{userpics} * ($self->{cfg}->{picwidth} || 60); 101 } 102 $self->{cfg}->{headwidth} = $self->{cfg}->{tablewidth} - 4; 103 $self->_htmlheader(); 104 $self->_pageheader() 105 if ($self->{cfg}->{pagehead} ne 'none'); 106 107 if ($self->{cfg}->{dailyactivity}) { 108 $self->_activedays(); 109 } 110 111 if ($self->{cfg}->{showactivetimes}) { 112 $self->_activetimes(); 113 } 114 115 if ($self->{cfg}->{showactivenicks}) { 116 $self->_activenicks(); 117 } 118 119 if ($self->{cfg}->{showmostactivebyhour}) { 120 $self->_mostactivebyhour(); 121 } 122 123 if ($self->{cfg}->{showbignumbers}) { 124 $self->_headline($self->_template_text('bignumtopic')); 125 _html("<table width=\"$self->{cfg}->{tablewidth}\">"); # Needed for sections 126 $self->_questions(); 127 $self->_shoutpeople(); 128 $self->_capspeople(); 129 $self->_violent(); 130 $self->_mostsmiles(); 131 $self->_mostsad(); 132 $self->_linelengths(); 133 $self->_mostwords(); 134 $self->_mostwordsperline(); 135 _html("</table>"); # Needed for sections 136 } 137 138 if ($self->{cfg}->{showmostnicks}) { 139 $self->_mostnicks(); 140 } 141 142 if ($self->{cfg}->{showactivegenders}) { 143 $self->_activegenders(); 144 } 145 146 if ($self->{cfg}->{showmuw}) { 147 $self->_mostusedword(); 148 } 149 150 if ($self->{cfg}->{showmrn}) { 151 $self->_mostreferencednicks(); 152 } 153 154 if ($self->{cfg}->{showsmileys}) { 155 $self->_smileys(); 156 } 157 158 if ($self->{cfg}->{showkarma}) { 159 $self->_karma(); 160 } 161 162 if ($self->{cfg}->{showmru}) { 163 $self->_mosturls(); 164 } 165 166 if ($self->{cfg}->{showcharts}) { 167 $self->_charts(); 168 } 169 170 if ($self->{cfg}->{showbignumbers}) { 171 $self->_headline($self->_template_text('othernumtopic')); 172 _html("<table width=\"$self->{cfg}->{tablewidth}\">"); # Needed for sections 173 $self->_gotkicks(); 174 $self->_mostkicks(); 175 $self->_mostop() if $self->{cfg}->{showops}; 176 $self->_mosthalfop() if $self->{cfg}->{showhalfops}; 177 $self->_mostvoice() if $self->{cfg}->{showvoices}; 178 $self->_mostactions(); 179 $self->_mostmonologues(); 180 $self->_mostjoins(); 181 $self->_mostfoul(); 182 _html("</table>"); # Needed for sections 183 } 184 185 if ($self->{cfg}->{showtopics}) { 186 $self->_headline($self->_template_text('latesttopic')); 187 _html("<table width=\"$self->{cfg}->{tablewidth}\">"); # Needed for sections 188 189 $self->_lasttopics(); 190 191 _html("</table>"); # Needed for sections 192 } 193 194 my %hash = ( lines => $self->{stats}->{parsedlines} ); 195 _html($self->_template_text('totallines', %hash) . "<br /><br />"); 196 197 $self->_pagefooter() 198 if ($self->{cfg}->{pagefoot} ne 'none'); 199 200 $self->_htmlfooter(); 201 202 close(OUTPUT); 203 204 # restore tablewidth 205 $self->{cfg}->{tablewidth} = $tablewidth_original; 206} 207 208sub _htmlheader 209{ 210 my $self = shift; 211 my %hash = ( 212 network => $self->{cfg}->{network}, 213 maintainer => $self->{cfg}->{maintainer}, 214 days => $self->{stats}->{days}, 215 nicks => scalar keys %{ $self->{stats}->{lines} } 216 ); 217 218 my $CSS; 219 if($self->{cfg}->{colorscheme} =~ /([^\/.]+)\.[^\/]+$/) { # use external CSS file 220 $CSS = "<link rel=\"stylesheet\" type=\"text/css\" title=\"$1\" href=\"$self->{cfg}->{colorscheme}\" />"; 221 } elsif($self->{cfg}->{colorscheme} ne "none") { # read the chosen CSS file 222 my $css_file = $self->{cfg}->{cssdir} . $self->{cfg}->{colorscheme} . ".css"; 223 open(FILE, $css_file) or open (FILE, $self->{cfg}->{search_path} . "/$css_file") or die("$0: Unable to open stylesheet $css_file: $!\n"); 224 { 225 local $/; # enable "slurp" mode 226 $CSS = "<style type=\"text/css\" title=\"$self->{cfg}->{colorscheme}\">\n". <FILE>. "</style>"; 227 $CSS =~ s/\/\*/\/\* <!--/g; 228 $CSS =~ s/\*\//--> \*\//g; 229 } 230 close FILE; 231 } 232 233 # use alternate CSS file 234 if($self->{cfg}->{altcolorscheme} ne "none" and $self->{cfg}->{altcolorscheme} =~ /[^\w]/) { 235 foreach (split /\s+/, $self->{cfg}->{altcolorscheme}) { 236 /([^\/.]+)\.[^\/]+$/; 237 $CSS .= "\n<link rel=\"alternate stylesheet\" type=\"text/css\" title=\"$1\" href=\"$_\" />"; 238 } 239 } 240 241 my $title = $self->_template_text('pagetitle1', %hash); 242 if($self->{cfg}->{colorscheme} ne "none") { 243 _html( <<HTML ); 244<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 245<html> 246<head> 247<meta http-equiv="Content-Type" content="text/html; charset=$self->{cfg}->{charset}" /> 248<title>$title</title> 249$CSS 250</head> 251<body> 252<div align="center"> 253HTML 254 } 255 _html("<span class=\"title\">$title</span><br />"); 256 _html("<br />"); 257 _html($self->_template_text('pagetitle2', %hash) . " " . $self->get_time()); 258 259 _html("<br />" . $self->_template_text('pagetitle3', %hash) . "<br /><br />"); 260 261} 262 263sub get_time 264{ 265 my $self = shift; 266 my ($tday, %hash); 267 268 my $month = $self->_template_text('month', %hash); 269 my $day = $self->_template_text('day', %hash); 270 271 my @month = split(" ", $month); 272 my @day = split(" ", $day); 273 274 # Get the Date from the users computer 275 my $timezone = $self->{cfg}->{timeoffset} * 3600; 276 my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(time+$timezone); 277 278 $year += 1900; # Y2K Patch 279 280 $min =~ s/^(.)$/0$1/; # Fixes the display of mins/secs below 281 $sec =~ s/^(.)$/0$1/; # it displays 03 instead of 3 282 283 if ($hour > '23') { # Checks to see if it Midnight 284 $hour = 12; # Makes it display the hour 12 285 $tday = "AM"; # Display AM 286 } elsif($hour > '12') { # Get rid of the Military time and 287 $hour -= 12; # put it into normal time 288 $tday = "PM"; # If past Noon and before Midnight set 289 } else { 290 $tday = "AM"; # If it's past Midnight and before Noon 291 } # set the time as AM 292 293 # Use 24 hours pr. day 294 if ($tday eq "PM" && $hour < '12') { 295 $hour += 12; 296 } 297 298 return "$day[$wday] $mday $month[$mon] $year - $hour:$min:$sec"; 299} 300 301 302sub _htmlfooter 303{ 304 my $self = shift; 305 306 my %hash; 307 308 my $pisg_hp = $self->_template_text('pisghomepage'); 309 $hash{pisg_url} = "<a href=\"http://pisg.sourceforge.net/\" title=\"$pisg_hp\" class=\"background\">pisg</a>"; 310 311 my $author_hp = $self->_template_text('authorhomepage'); 312 $hash{author_url} = "<a href=\"http://mbrix.dk/\" title=\"$author_hp\" class=\"background\">Morten Brix Pedersen</a>"; 313 314 $hash{version} = $self->{cfg}->{version}; 315 316 my $hours = $self->_template_text('hours'); 317 my $mins = $self->_template_text('minutes'); 318 my $secs = $self->_template_text('seconds'); 319 my $and = $self->_template_text('and'); 320 321 my $h = $self->{stats}->{processtime}{hours}; 322 my $m = $self->{stats}->{processtime}{mins}; 323 my $s = $self->{stats}->{processtime}{secs}; 324 $hash{time} = "$h $hours $m $mins $and $s $secs"; 325 326 my $stats_gen = $self->_template_text('stats_gen_by', %hash); 327 my $author_text = $self->_template_text('author', %hash); 328 my $stats_text = $self->_template_text('stats_gen_in', %hash); 329 330 _html( <<HTML ); 331<span class="small"> 332$stats_gen<br /> 333$author_text<br /> 334$stats_text 335</span> 336HTML 337 338 _html( sprintf( qq(<!-- NFiles = "%s"; Format = "%s"; Lang = "%s"; LangFile = "%s"; Charset = "%s"; LogCharset = "%s"; LogCharsetFallback = "%s"; LogPrefix = "%s"; LogSuffix = "%s"; NickTracking = "%s"; TimeOffset = "%s" -->), 339 $self->{cfg}->{nfiles}, 340 $self->{cfg}->{format}, 341 $self->{cfg}->{lang}, 342 $self->{cfg}->{langfile}, 343 $self->{cfg}->{charset}, 344 $self->{cfg}->{logcharset}, 345 $self->{cfg}->{logcharsetfallback}, 346 $self->{cfg}->{logprefix}, 347 $self->{cfg}->{logsuffix}, 348 $self->{cfg}->{nicktracking}, 349 $self->{cfg}->{timeoffset} 350 )); 351 352 if($self->{cfg}->{colorscheme} ne "none") { 353 _html( <<HTML ); 354</div> 355</body> 356</html> 357HTML 358 } 359} 360 361sub _headline 362{ 363 my $self = shift; 364 my ($title) = (@_); 365 _html( <<HTML ); 366 <br /> 367 <table width="$self->{cfg}->{headwidth}" cellpadding="1" cellspacing="0" border="0"> 368 <tr> 369 <td class="headlinebg"> 370 <table width="100%" cellpadding="2" cellspacing="0" border="0"> 371 <tr> 372 <td class="headtext">$title</td> 373 </tr> 374 </table> 375 </td> 376 </tr> 377 </table> 378HTML 379} 380 381sub _pageheader 382{ 383 my $self = shift; 384 unless(open(PAGEHEAD, $self->{cfg}->{pagehead})) { 385 warn("$0: Unable to open $self->{cfg}->{pagehead} for reading: $!\n"); 386 return; 387 } 388 while (<PAGEHEAD>) { 389 chomp; 390 _html($_); 391 } 392 close(PAGEHEAD); 393} 394 395sub _pagefooter 396{ 397 my $self = shift; 398 unless(open(PAGEFOOT, $self->{cfg}->{pagefoot})) { 399 warn("$0: Unable to open $self->{cfg}->{pagefoot} for reading: $!\n"); 400 return; 401 } 402 while (<PAGEFOOT>) { 403 chomp; 404 _html($_); 405 } 406 close(PAGEFOOT); 407} 408 409sub _activedays 410{ 411 # The most actives days on the channel 412 my $self = shift; 413 my $days = $self->{stats}->{days}; 414 my $ndays = $self->{cfg}->{dailyactivity}; 415 416 my $highest_value = 1; 417 for (my $day = $days; $day > $days - $ndays ; $day--) { 418 if (defined($self->{stats}->{day_lines}->[$day])) { 419 if ($self->{stats}->{day_lines}->[$day] > $highest_value) { 420 $highest_value = $self->{stats}->{day_lines}->[$day]; 421 } 422 } else { 423 #there are only $days - $day days :) 424 $ndays = $days - $day; 425 last; 426 } 427 } 428 429 my %hash = ( 430 n => $ndays 431 ); 432 $self->_headline($self->_template_text('dailyactivitytopic', %hash)); 433 434 _html("<table border=\"0\"><tr>"); 435 436 for (my $day = $days - $ndays + 1; $day <= $days ; $day++) { 437 my $lines = $self->{stats}->{day_lines}[$day]; 438 _html("<td align=\"center\" valign=\"bottom\" class=\"asmall\">$lines<br />"); 439 for (my $time = 4; $time >= 0; $time--) { 440 if (defined($self->{stats}->{day_times}[$day][$time])) { 441 my $size = int(($self->{stats}->{day_times}[$day][$time] / $highest_value) * 100); 442 443 my $image = "pic_v_".$time*6; 444 $image = $self->{cfg}->{$image}; 445 _html("<img src=\"$self->{cfg}->{piclocation}/$image\" width=\"15\" height=\"$size\" alt=\"$size\" title=\"$size\" /><br />") if $size; 446 447 } 448 } 449 _html("</td>"); 450 } 451 452 _html("</tr><tr>"); 453 454 for (my $day = $ndays - 1; $day >= 0 ; $day--) { 455 _html("<td class=\"rankc10center\" align=\"center\">$day</td>"); 456 } 457 458 _html("</tr></table>"); 459 460 if($self->{cfg}->{showlegend} == 1) { 461 $self->_legend(); 462 } 463} 464 465sub _activetimes 466{ 467 # The most actives times on the channel 468 my $self = shift; 469 470 my (%output); 471 472 $self->_headline($self->_template_text('activetimestopic')); 473 474 my @toptime = sort { $self->{stats}->{times}{$b} <=> $self->{stats}->{times}{$a} } keys %{ $self->{stats}->{times} }; 475 476 my $highest_value = $self->{stats}->{times}{$toptime[0]}; 477 478 for my $hour (sort keys %{ $self->{stats}->{times} }) { 479 480 my $size = int(($self->{stats}->{times}{$hour} / $highest_value) * 100); 481 my $percent = sprintf("%.1f", ($self->{stats}->{times}{$hour} / $self->{stats}->{parsedlines}) * 100); 482 my $lines_per_hour = $self->{stats}->{times}{$hour}; 483 484 my $image = "pic_v_".(int($hour/6)*6); 485 $image = $self->{cfg}->{$image}; 486 487 $output{$hour} = "<td align=\"center\" valign=\"bottom\" class=\"asmall\">$percent%<br /><img src=\"$self->{cfg}->{piclocation}/$image\" width=\"15\" height=\"$size\" alt=\"$lines_per_hour\" title=\"$lines_per_hour\"/></td>" if $size; 488 } 489 490 _html("<table border=\"0\"><tr>"); 491 492 for ($b = 0; $b < 24; $b++) { 493 $a = sprintf("%02d", $b); 494 495 if (!defined($output{$a})) { 496 _html("<td align=\"center\" valign=\"bottom\" class=\"asmall\">0%</td>"); 497 } else { 498 _html($output{$a}); 499 } 500 } 501 502 _html("</tr><tr>"); 503 504 # Remove leading zero 505 $toptime[0] =~ s/^0//; 506 507 for ($b = 0; $b < 24; $b++) { 508 # Highlight the top time 509 my $class = $toptime[0] == $b ? 'hirankc10center' : 'rankc10center'; 510 _html("<td class=\"$class\" align=\"center\">$b</td>"); 511 } 512 513 _html("</tr></table>"); 514 515 if($self->{cfg}->{showlegend} == 1) { 516 $self->_legend(); 517 } 518} 519 520sub _activenicks 521{ 522 # The most active nicks (those who wrote most lines) 523 my $self = shift; 524 525 $self->_headline($self->_template_text('activenickstopic')); 526 527 my $output = ""; 528 $output .= "<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"; 529 $output .= "<td> </td>"; 530 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('nick') . "</b></td>"; 531 532 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('numberlines') . "</b></td>" if ($self->{cfg}->{showlines}); 533 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('show_time') . "</b></td>" if ($self->{cfg}->{showtime}); 534 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('show_words') . "</b></td>" if ($self->{cfg}->{showwords}); 535 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('show_wpl') . "</b></td>" if ($self->{cfg}->{showwpl}); 536 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('show_cpl') . "</b></td>" if ($self->{cfg}->{showcpl}); 537 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('show_lastseen') . "</b></td>" if ($self->{cfg}->{showlastseen}); 538 $output .= "<td class=\"tdtop\"><b>" . $self->_template_text('randquote') . "</b></td>" if ($self->{cfg}->{showrandquote}); 539 540 $output .= "\n"; 541 542 my @active; 543 my $nicks; 544 if ($self->{cfg}->{sortbywords}) { 545 @active = sort { $self->{stats}->{words}{$b} <=> $self->{stats}->{words}{$a} } keys %{ $self->{stats}->{words} }; 546 $nicks = scalar keys %{ $self->{stats}->{words} }; 547 } else { 548 @active = sort { $self->{stats}->{lines}{$b} <=> $self->{stats}->{lines}{$a} } keys %{ $self->{stats}->{lines} }; 549 $nicks = scalar keys %{ $self->{stats}->{lines} }; 550 } 551 552 if ($self->{cfg}->{activenicks} > $nicks) { $self->{cfg}->{activenicks} = $nicks; } 553 554 for (my $c = 0; $c < $self->{cfg}->{activenicks}; $c++) { 555 last unless $self->{cfg}->{userpics}; 556 my $nick = $active[$c]; 557 if ($self->{users}->{userpics}{$nick} or $self->{cfg}->{defaultpic}) { 558 $output .= "<td class=\"tdtop\""; 559 $output .= " colspan=\"$self->{cfg}->{userpics}\"" if ($self->{cfg}->{userpics} > 1); 560 $output .= "><b>" . $self->_template_text('userpic') ."</b></td>"; 561 last; 562 } 563 } 564 565 $output .= "\n</tr>"; 566 _html($output); 567 undef $output; 568 569 for (my $i = 0; $i < $self->{cfg}->{activenicks}; $i++) { 570 my $c = $i + 1; 571 my $nick = $active[$i]; 572 my $visiblenick; 573 574 my $randomline; 575 if (not defined $self->{stats}->{sayings}{$nick}) { 576 if ($self->{stats}->{actions}{$nick}) { 577 $randomline = $self->{stats}->{actionlines}{$nick}; 578 } else { 579 $randomline = ""; 580 } 581 } else { 582 $randomline = $self->{stats}->{sayings}{$nick}; 583 } 584 585 if ($randomline) { 586 $randomline = $self->_format_line($randomline); 587 } 588 589 # Add a link to the nick if there is any and quote nick 590 if ($self->{users}->{userlinks}{$nick}) { 591 $visiblenick = $self->_format_word($self->{users}->{userlinks}{$nick}, $nick); 592 } else { 593 $visiblenick = $self->_format_word($nick); 594 } 595 596 my $style = $self->generate_colors($c); 597 598 my $class = 'rankc'; 599 if ($c == 1) { 600 $class = 'hirankc'; 601 } 602 603 my $lastseen; 604 605 if ($self->{cfg}->{showlastseen}) { 606 $lastseen = $self->{stats}->{days} - $self->{stats}->{lastvisited}{$nick}; 607 my %hash = ( days => $lastseen ); 608 if ($lastseen == 0) { 609 $lastseen = $self->_template_text('today'); 610 } elsif ($lastseen == 1) { 611 $lastseen = $self->_template_text('lastseen1', %hash); 612 } else { 613 $lastseen = $self->_template_text('lastseen2', %hash); 614 } 615 } 616 617 _html("<tr><td class=\"$class\" align=\"left\">$c</td>"); 618 619 my $line = $self->{stats}->{lines}{$nick}; 620 my $w = $self->{stats}->{words}{$nick} ? $self->{stats}->{words}{$nick} : 0; 621 my $ch = $self->{stats}->{lengths}{$nick}; 622 my $sex = $self->{users}->{sex}{$nick}; 623 624 my $output = ""; 625 $output .= "<td $style>"; 626 627 # Hilight nick with gendercolors 628 if ($sex and $sex eq 'm') { 629 $output .= "<span class=\"male\">"; 630 } elsif ($sex and $sex eq 'f') { 631 $output .= "<span class=\"female\">"; 632 } elsif ($sex and $sex eq 'b') { 633 $output .= "<span class=\"bot\">"; 634 } else { 635 $output .= "<span>"; 636 } 637 $output .= $visiblenick; 638 $output .= "</span></td>"; 639 640 if ($self->{cfg}->{showlines}) { 641 if ($self->{cfg}->{showlinetime}) { 642 $output .= "<td $style nowrap=\"nowrap\">" . $self->_user_linetimes($nick,$active[0]) . "</td>"; 643 } else { 644 $output .= "<td $style>$line</td>"; 645 } 646 } 647 648 $output .= "<td $style>" . $self->_user_times($nick) . "</td>" if ($self->{cfg}->{showtime}); 649 650 if ($self->{cfg}->{showwords}) { 651 if ($self->{cfg}->{showwordtime}) { 652 $output .= "<td $style nowrap=\"nowrap\">" . $self->_user_wordtimes($nick,$active[0]) . "</td>"; 653 } else { 654 $output .= "<td $style>$w</td>"; 655 } 656 } 657 658 $output .= "<td $style>" . sprintf("%.1f", $w/$line) . "</td>" if ($self->{cfg}->{showwpl}); 659 $output .= "<td $style>" . sprintf("%.1f", $ch/$line) . "</td>" if ($self->{cfg}->{showcpl}); 660 $output .= "<td $style>$lastseen</td>" if ($self->{cfg}->{showlastseen}); 661 $output .= "<td $style>\"$randomline\"</td>" if ($self->{cfg}->{showrandquote}); 662 663 _html($output); 664 undef $output; 665 666 667 if ($self->{cfg}->{userpics} && $i % $self->{cfg}->{userpics} == 0) { 668 for my $ii (0 .. $self->{cfg}->{userpics} - 1) { 669 last if $i + $ii >= $self->{cfg}->{activenicks}; 670 $self->_user_pic($active[$i + $ii], $style); 671 } 672 } 673 _html("</tr>"); 674 } 675 676 _html("</table><br />"); 677 678 # Almost as active nicks ('These didn't make it to the top..') 679 680 my $toshow = $self->{cfg}->{activenicks2} - $self->{cfg}->{activenicks}; 681 my $remain = $self->{cfg}->{activenicks} + $toshow; 682 683 unless ($toshow > $nicks) { 684 $remain = $self->{cfg}->{activenicks} + $self->{cfg}->{activenicks2}; 685 if ($remain > $nicks) { 686 $remain = $nicks; 687 } 688 689 if ($self->{cfg}->{activenicks} < $remain) { 690 _html("<br /><b><i>" . $self->_template_text('nottop') . "</i></b><table><tr>"); 691 for (my $i = $self->{cfg}->{activenicks}; $i < $remain; $i++) { 692 my $visiblenick; 693 my $nick = $active[$i]; 694 if ($i != $self->{cfg}->{activenicks} and ($i - $self->{cfg}->{activenicks}) % 5 == 0) { 695 _html("</tr><tr>"); 696 } 697 my $items; 698 if ($self->{users}->{userlinks}{$nick}) { 699 $visiblenick = $self->_format_word($self->{users}->{userlinks}{$nick}, $nick); 700 } else { 701 $visiblenick = $self->_format_word($nick); 702 } 703 if ($self->{cfg}->{sortbywords}) { 704 $items = $self->{stats}->{words}{$active[$i]}; 705 } else { 706 $items = $self->{stats}->{lines}{$active[$i]}; 707 } 708 my $sex = $self->{users}->{sex}{$active[$i]}; 709 710 my $output = ""; 711 $output .= "<td class=\"rankc10\">"; 712 713 if ($sex and $sex eq 'm') { 714 $output .= "<span class=\"male\">"; 715 } elsif ($sex and $sex eq 'f') { 716 $output .= "<span class=\"female\">"; 717 } elsif ($sex and $sex eq 'b') { 718 $output .= "<span class=\"bot\">"; 719 } else { 720 $output .= "<span>"; 721 } 722 $output .= "$visiblenick ($items)"; 723 $output .= "</span></td>"; 724 725 _html($output); 726 undef $output; 727 728 } 729 _html("</tr></table>"); 730 } 731 } 732 733 my %hash; 734 $hash{totalnicks} = $nicks - $remain; 735 if ($hash{totalnicks} > 0) { 736 _html("<br /><b>" . $self->_template_text('totalnicks', %hash) . "</b><br />"); 737 } 738} 739 740sub generate_colors 741{ 742 my $self = shift; 743 my $c = shift; 744 745 # if hicell or hicell2 is "", do not print the class as it could mess up the gendercode 746 return "" if not (length $self->{cfg}->{hicell} and length $self->{cfg}->{hicell2}); 747 748 my $h = $self->{cfg}->{hicell} or return "class=\"hicell\""; 749 $h =~ s/^#//; 750 $h = hex $h; 751 my $h2 = $self->{cfg}->{hicell2} or return "class=\"hicell\""; 752 $h2 =~ s/^#//; 753 $h2 = hex $h2; 754 my $f_b = $h & 0xff; 755 my $f_g = ($h & 0xff00) >> 8; 756 my $f_r = ($h & 0xff0000) >> 16; 757 my $t_b = $h2 & 0xff; 758 my $t_g = ($h2 & 0xff00) >> 8; 759 my $t_r = ($h2 & 0xff0000) >> 16; 760 my $blue = sprintf "%0.2x", abs int(((($t_b - $f_b) / $self->{cfg}->{activenicks}) * +$c) + $f_b); 761 my $green = sprintf "%0.2x", abs int(((($t_g - $f_g) / $self->{cfg}->{activenicks}) * +$c) + $f_g); 762 my $red = sprintf "%0.2x", abs int(((($t_r - $f_r) / $self->{cfg}->{activenicks}) * +$c) + $f_r); 763 764 return "style=\"background-color: #$red$green$blue\""; 765} 766 767sub _html 768{ 769 my $html = shift; 770 print OUTPUT "$html\n" or die "Could not write to disk: $!\n"; 771} 772 773sub _questions 774{ 775 # Persons who asked the most questions 776 my $self = shift; 777 778 my %qpercent; 779 780 foreach my $nick (sort keys %{ $self->{stats}->{questions} }) { 781 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 782 if ($self->{stats}->{lines}{$nick} > $self->{cfg}->{bignumbersthreshold}) { 783 $qpercent{$nick} = sprintf("%.1f", ($self->{stats}->{questions}{$nick} / $self->{stats}->{lines}{$nick}) * 100); 784 } 785 } 786 } 787 788 my @question = sort { $qpercent{$b} <=> $qpercent{$a} } keys %qpercent; 789 790 if (@question) { 791 my %hash = ( 792 nick => $question[0], 793 per => $qpercent{$question[0]} 794 ); 795 796 my $text = $self->_template_text('question1', %hash); 797 _html("<tr><td class=\"hicell\">$text"); 798 if (@question >= 2) { 799 my %hash = ( 800 nick => $question[1], 801 per => $qpercent{$question[1]} 802 ); 803 804 my $text = $self->_template_text('question2', %hash); 805 _html("<br /><span class=\"small\">$text</span>"); 806 } 807 _html("</td></tr>"); 808 809 } else { 810 _html("<tr><td class=\"hicell\">" . $self->_template_text('question3') . "</td></tr>"); 811 } 812} 813 814sub _shoutpeople 815{ 816 # The ones who speak with exclamation marks! 817 my $self = shift; 818 819 my %spercent; 820 821 foreach my $nick (sort keys %{ $self->{stats}->{shouts} }) { 822 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 823 if ($self->{stats}->{lines}{$nick} > $self->{cfg}->{bignumbersthreshold}) { 824 $spercent{$nick} = sprintf("%.1f", ($self->{stats}->{shouts}{$nick} / $self->{stats}->{lines}{$nick}) * 100); 825 } 826 } 827 } 828 829 my @shout = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent; 830 831 if (@shout) { 832 my %hash = ( 833 nick => $shout[0], 834 per => $spercent{$shout[0]} 835 ); 836 837 my $text = $self->_template_text('shout1', %hash); 838 _html("<tr><td class=\"hicell\">$text"); 839 if (@shout >= 2) { 840 my %hash = ( 841 nick => $shout[1], 842 per => $spercent{$shout[1]} 843 ); 844 845 my $text = $self->_template_text('shout2', %hash); 846 _html("<br /><span class=\"small\">$text</span>"); 847 } 848 _html("</td></tr>"); 849 850 } else { 851 my $text = $self->_template_text('shout3'); 852 _html("<tr><td class=\"hicell\">$text</td></tr>"); 853 } 854 855} 856 857sub _capspeople 858{ 859 # The ones who speak ALL CAPS. 860 my $self = shift; 861 862 my %cpercent; 863 864 foreach my $nick (sort keys %{ $self->{stats}->{allcaps} }) { 865 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 866 if ($self->{stats}->{lines}{$nick} > $self->{cfg}->{bignumbersthreshold}) { 867 $cpercent{$nick} = sprintf("%.1f", $self->{stats}->{allcaps}{$nick} / $self->{stats}->{lines}{$nick} * 100); 868 } 869 } 870 } 871 872 my @caps = sort { $cpercent{$b} <=> $cpercent{$a} } keys %cpercent; 873 874 if (@caps) { 875 my %hash = ( 876 nick => $caps[0], 877 per => $cpercent{$caps[0]}, 878 line => $self->_format_line($self->{stats}->{allcaplines}{$caps[0]}) 879 ); 880 881 my $text = $self->_template_text('allcaps1', %hash); 882 if($self->{cfg}->{showshoutline}) { 883 my $exttext = $self->_template_text('allcapstext', %hash); 884 _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span>"); 885 } else { 886 _html("<tr><td class=\"hicell\">$text"); 887 } 888 if (@caps >= 2) { 889 my %hash = ( 890 nick => $caps[1], 891 per => $cpercent{$caps[1]} 892 ); 893 894 my $text = $self->_template_text('allcaps2', %hash); 895 _html("<br /><span class=\"small\">$text</span>"); 896 } 897 _html("</td></tr>"); 898 899 } else { 900 my $text = $self->_template_text('allcaps3'); 901 _html("<tr><td class=\"hicell\">$text</td></tr>"); 902 } 903} 904 905sub _violent 906{ 907 # They attacked others (words defined by $self->{cfg}->{violent}) 908 my $self = shift; 909 910 my @aggressors = sort { $self->{stats}->{violence}{$b} <=> $self->{stats}->{violence}{$a} } 911 keys %{ $self->{stats}->{violence} }; 912 913 @aggressors = $self->_istoponly(@aggressors); 914 915 if(@aggressors) { 916 my %hash = ( 917 nick => $aggressors[0], 918 attacks => $self->{stats}->{violence}{$aggressors[0]}, 919 line => $self->_format_line($self->{stats}->{violencelines}{$aggressors[0]}) 920 ); 921 my $text = $self->_template_text('violent1', %hash); 922 if($self->{cfg}->{showviolentlines}) { 923 my $exttext = $self->_template_text('violenttext', %hash); 924 _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span>"); 925 } else { 926 _html("<tr><td class=\"hicell\">$text"); 927 } 928 if (@aggressors >= 2) { 929 my %hash = ( 930 nick => $aggressors[1], 931 attacks => $self->{stats}->{violence}{$aggressors[1]} 932 ); 933 934 my $text = $self->_template_text('violent2', %hash); 935 _html("<br /><span class=\"small\">$text</span>"); 936 } 937 _html("</td></tr>"); 938 } else { 939 my $text = $self->_template_text('violent3'); 940 _html("<tr><td class=\"hicell\">$text</td></tr>"); 941 } 942 943 944 # They got attacked 945 my @victims = sort { $self->{stats}->{attacked}{$b} <=> $self->{stats}->{attacked}{$a} } 946 keys %{ $self->{stats}->{attacked} }; 947 948 @victims = $self->_istoponly(@victims); 949 950 if(@victims) { 951 my %hash = ( 952 nick => $victims[0], 953 attacks => $self->{stats}->{attacked}{$victims[0]}, 954 line => $self->_format_line($self->{stats}->{attackedlines}{$victims[0]}) 955 ); 956 my $text = $self->_template_text('attacked1', %hash); 957 if($self->{cfg}->{showviolentlines}) { 958 my $exttext = $self->_template_text('attackedtext', %hash); 959 _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span>"); 960 } else { 961 _html("<tr><td class=\"hicell\">$text"); 962 } 963 if (@victims >= 2) { 964 my %hash = ( 965 nick => $victims[1], 966 attacks => $self->{stats}->{attacked}{$victims[1]} 967 ); 968 969 my $text = $self->_template_text('attacked2', %hash); 970 _html("<br /><span class=\"small\">$text</span>"); 971 } 972 _html("</td></tr>"); 973 } 974} 975 976sub _gotkicks 977{ 978 # The persons who got kicked the most 979 my $self = shift; 980 981 my @gotkick = sort { $self->{stats}->{gotkicked}{$b} <=> $self->{stats}->{gotkicked}{$a} } 982 keys %{ $self->{stats}->{gotkicked} }; 983 984 @gotkick = $self->_istoponly(@gotkick); 985 986 if (@gotkick) { 987 my %hash = ( 988 nick => $gotkick[0], 989 kicks => $self->{stats}->{gotkicked}{$gotkick[0]}, 990 line => $self->_format_line($self->{stats}->{kicklines}{$gotkick[0]}) 991 ); 992 993 my $text = $self->_template_text('gotkick1', %hash); 994 995 if ($self->{cfg}->{showkickline}) { 996 my $exttext = $self->_template_text('kicktext', %hash); 997 _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span>"); 998 } else { 999 _html("<tr><td class=\"hicell\">$text"); 1000 } 1001 1002 if (@gotkick >= 2) { 1003 my %hash = ( 1004 nick => $gotkick[1], 1005 kicks => $self->{stats}->{gotkicked}{$gotkick[1]} 1006 ); 1007 1008 my $text = $self->_template_text('gotkick2', %hash); 1009 _html("<br /><span class=\"small\">$text</span>"); 1010 } 1011 _html("</td></tr>"); 1012 } 1013} 1014 1015sub _mostjoins 1016{ 1017 my $self = shift; 1018 1019 my @joins = sort { $self->{stats}->{joins}{$b} <=> $self->{stats}->{joins}{$a} } 1020 keys %{ $self->{stats}->{joins} }; 1021 1022 @joins = $self->_istoponly(@joins); 1023 1024 if (@joins) { 1025 my %hash = ( 1026 nick => $joins[0], 1027 joins => $self->{stats}->{joins}{$joins[0]} 1028 ); 1029 1030 my $text = $self->_template_text('joins', %hash); 1031 1032 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1033 } 1034} 1035 1036sub _mostwords 1037{ 1038 # The person who got words the most 1039 my $self = shift; 1040 1041 my @words = sort { $self->{stats}->{words}{$b} <=> $self->{stats}->{words}{$a} } 1042 keys %{ $self->{stats}->{words} }; 1043 1044 @words = $self->_istoponly(@words); 1045 1046 if (@words) { 1047 my %hash = ( 1048 nick => $words[0], 1049 words => $self->{stats}->{words}{$words[0]} 1050 ); 1051 1052 my $text = $self->_template_text('words1', %hash); 1053 _html("<tr><td class=\"hicell\">$text"); 1054 1055 if (@words >= 2) { 1056 my %hash = ( 1057 oldnick => $words[0], 1058 nick => $words[1], 1059 words => $self->{stats}->{words}{$words[1]} 1060 ); 1061 1062 my $text = $self->_template_text('words2', %hash); 1063 _html("<br /><span class=\"small\">$text</span>"); 1064 } 1065 _html("</td></tr>"); 1066 } else { 1067 my $text = $self->_template_text('words3'); 1068 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1069 } 1070} 1071 1072sub _mostkicks 1073{ 1074 # The person who kicked the most 1075 my $self = shift; 1076 1077 my @kicked = sort { $self->{stats}->{kicked}{$b} <=> $self->{stats}->{kicked}{$a} } 1078 keys %{ $self->{stats}->{kicked} }; 1079 1080 @kicked = $self->_istoponly(@kicked); 1081 1082 if (@kicked) { 1083 my %hash = ( 1084 nick => $kicked[0], 1085 kicked => $self->{stats}->{kicked}{$kicked[0]} 1086 ); 1087 1088 my $text = $self->_template_text('kick1', %hash); 1089 _html("<tr><td class=\"hicell\">$text"); 1090 1091 if (@kicked >= 2) { 1092 my %hash = ( 1093 oldnick => $kicked[0], 1094 nick => $kicked[1], 1095 kicked => $self->{stats}->{kicked}{$kicked[1]} 1096 ); 1097 1098 my $text = $self->_template_text('kick2', %hash); 1099 _html("<br /><span class=\"small\">$text</span>"); 1100 } 1101 _html("</td></tr>"); 1102 } else { 1103 my $text = $self->_template_text('kick3'); 1104 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1105 } 1106} 1107 1108sub _mostmonologues 1109{ 1110 # The person who had the most monologues (speaking to himself) 1111 my $self = shift; 1112 1113 my @monologue = sort { $self->{stats}->{monologues}{$b} <=> $self->{stats}->{monologues}{$a} } 1114 keys %{ $self->{stats}->{monologues} }; 1115 1116 @monologue = $self->_istoponly(@monologue); 1117 1118 if (@monologue) { 1119 my %hash = ( 1120 nick => $monologue[0], 1121 monos => $self->{stats}->{monologues}{$monologue[0]} 1122 ); 1123 1124 my $text = $self->_template_text('mono1', %hash); 1125 1126 _html("<tr><td class=\"hicell\">$text"); 1127 if (@monologue >= 2) { 1128 my %hash = ( 1129 nick => $monologue[1], 1130 monos => $self->{stats}->{monologues}{$monologue[1]} 1131 ); 1132 1133 my $text = $self->_template_text('mono2', %hash); 1134 _html("<br /><span class=\"small\">$text</span>"); 1135 } 1136 _html("</td></tr>"); 1137 } 1138} 1139 1140sub _linelengths 1141{ 1142 # The person(s) who wrote the longest lines 1143 my $self = shift; 1144 1145 my %len; 1146 1147 foreach my $nick (sort keys %{ $self->{stats}->{lengths} }) { 1148 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 1149 if ($self->{stats}->{lines}{$nick} > $self->{cfg}->{bignumbersthreshold}) { 1150 $len{$nick} = sprintf("%.1f", $self->{stats}->{lengths}{$nick} / $self->{stats}->{lines}{$nick}); 1151 } 1152 } 1153 } 1154 1155 my @len = sort { $len{$b} <=> $len{$a} } keys %len; 1156 1157 my $all_lines = 0; 1158 my $totallength; 1159 foreach my $nick (keys %{ $self->{stats}->{lines} }) { 1160 $all_lines += $self->{stats}->{lines}{$nick}; 1161 $totallength += $self->{stats}->{lengths}{$nick}; 1162 } 1163 1164 my $totalaverage; 1165 1166 if ($all_lines > 0) { 1167 $totalaverage = sprintf("%.1f", $totallength / $all_lines); 1168 } 1169 1170 if (@len) { 1171 my %hash = ( 1172 nick => $len[0], 1173 letters => $len{$len[0]} 1174 ); 1175 1176 my $text = $self->_template_text('long1', %hash); 1177 _html("<tr><td class=\"hicell\">$text<br />"); 1178 1179 if (@len >= 2) { 1180 %hash = ( 1181 avg => $totalaverage 1182 ); 1183 1184 $text = $self->_template_text('long2', %hash); 1185 _html("<span class=\"small\">$text</span></td></tr>"); 1186 } else { 1187 _html("</td></tr>"); 1188 } 1189 } 1190 1191 # The person(s) who wrote the shortest lines 1192 1193 if (@len) { 1194 my %hash = ( 1195 nick => $len[$#len], 1196 letters => $len{$len[$#len]} 1197 ); 1198 1199 my $text = $self->_template_text('short1', %hash); 1200 _html("<tr><td class=\"hicell\">$text<br />"); 1201 1202 if (@len >= 2) { 1203 %hash = ( 1204 nick => $len[$#len - 1], 1205 letters => $len{$len[$#len - 1]} 1206 ); 1207 1208 $text = $self->_template_text('short2', %hash); 1209 _html("<span class=\"small\">$text</span></td></tr>"); 1210 } else { 1211 _html("</td></tr>"); 1212 } 1213 } 1214} 1215 1216sub _mostfoul 1217{ 1218 my $self = shift; 1219 1220 my %spercent; 1221 1222 foreach my $nick (sort keys %{ $self->{stats}->{foul} }) { 1223 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 1224 if ($self->{stats}->{lines}{$nick} > 15) { 1225 my $dec = $self->{cfg}->{showfouldecimals}; 1226 $dec = 1 if($dec < 0); # default to 1 1227 $spercent{$nick} = sprintf("%.${dec}f", $self->{stats}->{foul}{$nick} / $self->{stats}->{words}{$nick} * 100); 1228 } 1229 } 1230 } 1231 1232 my @foul = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent; 1233 1234 if (@foul) { 1235 1236 my %hash = ( 1237 nick => $foul[0], 1238 per => $spercent{$foul[0]}, 1239 line => $self->_format_line($self->{stats}{foullines}{$foul[0]}), 1240 ); 1241 1242 my $text = $self->_template_text('foul1', %hash); 1243 1244 if($self->{cfg}->{showfoulline}) { 1245 my $exttext = $self->_template_text('foultext', %hash); 1246 _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span>"); 1247 } else { 1248 _html("<tr><td class=\"hicell\">$text"); 1249 } 1250 1251 if (@foul >= 2) { 1252 my %hash = ( 1253 nick => $foul[1], 1254 per => $spercent{$foul[1]} 1255 ); 1256 1257 my $text = $self->_template_text('foul2', %hash); 1258 _html("<br /><span class=\"small\">$text</span>"); 1259 } 1260 1261 _html("</td></tr>"); 1262 } else { 1263 my $text = $self->_template_text('foul3'); 1264 1265 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1266 } 1267} 1268 1269 1270sub _mostsad 1271{ 1272 my $self = shift; 1273 1274 my %spercent; 1275 1276 foreach my $nick (sort keys %{ $self->{stats}->{frowns} }) { 1277 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 1278 if ($self->{stats}->{lines}{$nick} > $self->{cfg}->{bignumbersthreshold}) { 1279 $spercent{$nick} = sprintf("%.1f", $self->{stats}->{frowns}{$nick} / $self->{stats}->{lines}{$nick} * 100); 1280 } 1281 } 1282 } 1283 1284 my @sadface = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent; 1285 1286 1287 if (@sadface) { 1288 my %hash = ( 1289 nick => $sadface[0], 1290 per => $spercent{$sadface[0]} 1291 ); 1292 1293 my $text = $self->_template_text('sad1', %hash); 1294 _html("<tr><td class=\"hicell\">$text"); 1295 1296 if (@sadface >= 2) { 1297 my %hash = ( 1298 nick => $sadface[1], 1299 per => $spercent{$sadface[1]} 1300 ); 1301 1302 my $text = $self->_template_text('sad2', %hash); 1303 1304 _html("<br /><span class=\"small\">$text</span>"); 1305 } 1306 _html("</td></tr>"); 1307 } else { 1308 my $text = $self->_template_text('sad3'); 1309 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1310 } 1311} 1312 1313 1314sub _mostop 1315{ 1316 my $self = shift; 1317 1318 my @ops = sort { $self->{stats}->{gaveops}{$b} <=> $self->{stats}->{gaveops}{$a} } 1319 keys %{ $self->{stats}->{gaveops} }; 1320 1321 @ops = $self->_istoponly(@ops); 1322 1323 my @deops = sort { $self->{stats}->{tookops}{$b} <=> $self->{stats}->{tookops}{$a} } 1324 keys %{ $self->{stats}->{tookops} }; 1325 1326 @deops = $self->_istoponly(@deops); 1327 1328 if (@ops) { 1329 my %hash = ( 1330 nick => $ops[0], 1331 ops => $self->{stats}->{gaveops}{$ops[0]} 1332 ); 1333 1334 my $text = $self->_template_text('mostop1', %hash); 1335 1336 _html("<tr><td class=\"hicell\">$text"); 1337 1338 if (@ops >= 2) { 1339 my %hash = ( 1340 nick => $ops[1], 1341 ops => $self->{stats}->{gaveops}{$ops[1]} 1342 ); 1343 1344 my $text = $self->_template_text('mostop2', %hash); 1345 _html("<br /><span class=\"small\">$text</span>"); 1346 } 1347 _html("</td></tr>"); 1348 } else { 1349 my $text = $self->_template_text('mostop3'); 1350 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1351 } 1352 1353 if (@deops) { 1354 my %hash = ( 1355 nick => $deops[0], 1356 deops => $self->{stats}->{tookops}{$deops[0]} 1357 ); 1358 my $text = $self->_template_text('mostdeop1', %hash); 1359 1360 _html("<tr><td class=\"hicell\">$text"); 1361 1362 if (@deops >= 2) { 1363 my %hash = ( 1364 nick => $deops[1], 1365 deops => $self->{stats}->{tookops}{$deops[1]} 1366 ); 1367 my $text = $self->_template_text('mostdeop2', %hash); 1368 1369 _html("<br /><span class=\"small\">$text</span>"); 1370 } 1371 _html("</td></tr>"); 1372 } else { 1373 my $text = $self->_template_text('mostdeop3'); 1374 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1375 } 1376} 1377 1378sub _mostvoice 1379{ 1380 my $self = shift; 1381 1382 my @voice = sort { $self->{stats}->{gavevoice}{$b} <=> $self->{stats}->{gavevoice}{$a} } 1383 keys %{ $self->{stats}->{gavevoice} }; 1384 1385 @voice = $self->_istoponly(@voice); 1386 1387 my @devoice = sort { $self->{stats}->{tookvoice}{$b} <=> $self->{stats}->{tookvoice}{$a} } 1388 keys %{ $self->{stats}->{tookvoice} }; 1389 1390 @devoice = $self->_istoponly(@devoice); 1391 1392 if (@voice) { 1393 my %hash = ( 1394 nick => $voice[0], 1395 voices => $self->{stats}->{gavevoice}{$voice[0]} 1396 ); 1397 1398 my $text = $self->_template_text('mostvoice1', %hash); 1399 1400 _html("<tr><td class=\"hicell\">$text"); 1401 1402 if (@voice >= 2) { 1403 my %hash = ( 1404 nick => $voice[1], 1405 voices => $self->{stats}->{gavevoice}{$voice[1]} 1406 ); 1407 1408 my $text = $self->_template_text('mostvoice2', %hash); 1409 _html("<br /><span class=\"small\">$text</span>"); 1410 } 1411 _html("</td></tr>"); 1412 } else { 1413 my $text = $self->_template_text('mostvoice3'); 1414 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1415 } 1416 1417 if (@devoice) { 1418 my %hash = ( 1419 nick => $devoice[0], 1420 devoices => $self->{stats}->{tookvoice}{$devoice[0]} 1421 ); 1422 my $text = $self->_template_text('mostdevoice1', %hash); 1423 1424 _html("<tr><td class=\"hicell\">$text"); 1425 1426 if (@devoice >= 2) { 1427 my %hash = ( 1428 nick => $devoice[1], 1429 devoices => $self->{stats}->{tookvoice}{$devoice[1]} 1430 ); 1431 my $text = $self->_template_text('mostdevoice2', %hash); 1432 1433 _html("<br /><span class=\"small\">$text</span>"); 1434 } 1435 _html("</td></tr>"); 1436 } else { 1437 my $text = $self->_template_text('mostdevoice3'); 1438 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1439 } 1440 1441} 1442 1443sub _mosthalfop 1444{ 1445 my $self = shift; 1446 1447 my @halfops = sort { $self->{stats}->{gavehalfops}{$b} <=> $self->{stats}->{gavehalfops}{$a} } 1448 keys %{ $self->{stats}->{gavehalfops} }; 1449 1450 @halfops = $self->_istoponly(@halfops); 1451 1452 my @dehalfops = sort { $self->{stats}->{tookhalfops}{$b} <=> $self->{stats}->{tookhalfops}{$a} } 1453 keys %{ $self->{stats}->{tookhalfops} }; 1454 1455 @dehalfops = $self->_istoponly(@dehalfops); 1456 1457 if (@halfops) { 1458 my %hash = ( 1459 nick => $halfops[0], 1460 halfops => $self->{stats}->{gavehalfops}{$halfops[0]} 1461 ); 1462 1463 my $text = $self->_template_text('mosthalfop1', %hash); 1464 1465 _html("<tr><td class=\"hicell\">$text"); 1466 1467 if (@halfops >= 2) { 1468 my %hash = ( 1469 nick => $halfops[1], 1470 halfops => $self->{stats}->{gavehalfops}{$halfops[1]} 1471 ); 1472 1473 my $text = $self->_template_text('mosthalfop2', %hash); 1474 _html("<br /><span class=\"small\">$text</span>"); 1475 } 1476 _html("</td></tr>"); 1477 } else { 1478 my $text = $self->_template_text('mosthalfop3'); 1479 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1480 } 1481 1482 if (@dehalfops) { 1483 my %hash = ( 1484 nick => $dehalfops[0], 1485 dehalfops => $self->{stats}->{tookhalfops}{$dehalfops[0]} 1486 ); 1487 my $text = $self->_template_text('mostdehalfop1', %hash); 1488 1489 _html("<tr><td class=\"hicell\">$text"); 1490 1491 if (@dehalfops >= 2) { 1492 my %hash = ( 1493 nick => $dehalfops[1], 1494 dehalfops => $self->{stats}->{tookhalfops}{$dehalfops[1]} 1495 ); 1496 my $text = $self->_template_text('mostdehalfop2', %hash); 1497 1498 _html("<br /><span class=\"small\">$text</span>"); 1499 } 1500 _html("</td></tr>"); 1501 } else { 1502 my $text = $self->_template_text('mostdehalfop3'); 1503 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1504 } 1505} 1506 1507sub _mostactions 1508{ 1509 # The person who did the most /me's 1510 my $self = shift; 1511 1512 my @actions = sort { $self->{stats}->{actions}{$b} <=> $self->{stats}->{actions}{$a} } 1513 keys %{ $self->{stats}->{actions} }; 1514 1515 @actions = $self->_istoponly(@actions); 1516 1517 if (@actions) { 1518 my %linehash = 1519 my %hash = ( 1520 nick => $actions[0], 1521 actions => $self->{stats}->{actions}{$actions[0]}, 1522 line => $self->_format_line($self->{stats}->{actionlines}{$actions[0]}) 1523 ); 1524 my $text = $self->_template_text('action1', %hash); 1525 if($self->{cfg}->{showactionline}) { 1526 my $exttext = $self->_template_text('actiontext', %hash); 1527 _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span>"); 1528 } else { 1529 _html("<tr><td class=\"hicell\">$text"); 1530 } 1531 1532 if (@actions >= 2) { 1533 my %hash = ( 1534 nick => $actions[1], 1535 actions => $self->{stats}->{actions}{$actions[1]} 1536 ); 1537 1538 my $text = $self->_template_text('action2', %hash); 1539 _html("<br /><span class=\"small\">$text</span>"); 1540 } 1541 _html("</td></tr>"); 1542 } else { 1543 my $text = $self->_template_text('action3'); 1544 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1545 } 1546} 1547 1548 1549sub _mostsmiles 1550{ 1551 # The person(s) who smiled the most :-) 1552 my $self = shift; 1553 1554 my %spercent; 1555 1556 foreach my $nick (sort keys %{ $self->{stats}->{smiles} }) { 1557 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 1558 if ($self->{stats}->{lines}{$nick} > $self->{cfg}->{bignumbersthreshold}) { 1559 $spercent{$nick} = sprintf("%.1f", $self->{stats}->{smiles}{$nick} / $self->{stats}->{lines}{$nick} * 100); 1560 } 1561 } 1562 } 1563 1564 my @smiles = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent; 1565 1566 1567 if (@smiles) { 1568 my %hash = ( 1569 nick => $smiles[0], 1570 per => $spercent{$smiles[0]} 1571 ); 1572 1573 my $text = $self->_template_text('smiles1', %hash); 1574 1575 _html("<tr><td class=\"hicell\">$text"); 1576 if (@smiles >= 2) { 1577 my %hash = ( 1578 nick => $smiles[1], 1579 per => $spercent{$smiles[1]} 1580 ); 1581 1582 my $text = $self->_template_text('smiles2', %hash); 1583 _html("<br /><span class=\"small\">$text</span>"); 1584 } 1585 _html("</td></tr>"); 1586 1587 } else { 1588 1589 my $text = $self->_template_text('smiles3'); 1590 _html("<tr><td class=\"hicell\">$text</td></tr>"); 1591 } 1592} 1593 1594sub _lasttopics 1595{ 1596 my $self = shift; 1597 1598 if ($self->{stats}->{topics}) { 1599 1600 my %topic_seen; 1601 1602 my %hash = ( 1603 total => scalar @{ $self->{stats}->{topics} } 1604 ); 1605 1606 my $ltopic = $#{ $self->{stats}->{topics} }; 1607 my $tlimit = 0; 1608 1609 $self->{cfg}->{topichistory} -= 1; 1610 1611 if ($ltopic > $self->{cfg}->{topichistory}) { 1612 $tlimit = $ltopic - $self->{cfg}->{topichistory}; 1613 } 1614 1615 for (my $i = $ltopic; $i >= $tlimit; $i--) { 1616 my $topic = $self->{stats}->{topics}[$i]{topic}; 1617 # This code makes sure that we don't see the same topic twice 1618 next if ($topic_seen{$topic}); 1619 $topic_seen{$topic} = 1; 1620 1621 # Strip off the quotes (') 1622 $topic =~ s/^\'(.*)\'$/$1/; 1623 1624 my $nick = $self->{stats}->{topics}[$i]{nick}; 1625 my $hour = $self->{stats}->{topics}[$i]{hour}; 1626 my $min = $self->{stats}->{topics}[$i]{min}; 1627 1628 $hash{nick} = $nick; 1629 $hash{time} = "$hour:$min"; 1630 $hash{days} = $self->{stats}->{days} - $self->{stats}->{topics}[$i]{days}; 1631 if ($hash{days} == 0) { 1632 $hash{date} = $self->_template_text('today'); 1633 } elsif ($hash{days} == 1) { 1634 $hash{date} = $self->_template_text('lastseen1', %hash); 1635 } else { 1636 $hash{date} = $self->_template_text('lastseen2', %hash); 1637 } 1638 1639 _html('<tr><td class="hicell"><i>' . $self->_format_line($topic) . '</i></td>'); 1640 _html('<td class="hicell"><b>' . $self->_template_text('bylinetopic', %hash) . '</b></td></tr>'); 1641 } 1642 _html("<tr><td align=\"center\" colspan=\"2\" class=\"asmall\">" . $self->_template_text('totaltopic', %hash) . "</td></tr>"); 1643 } else { 1644 _html("<tr><td class=\"hicell\">" . $self->_template_text('notopic') ."</td></tr>"); 1645 } 1646} 1647 1648sub _template_text 1649{ 1650 # This function is for the homemade template system. It receives a name 1651 # of a template and a hash with the fields in the template to update to 1652 # its corresponding value 1653 my $self = shift; 1654 my $template = shift; 1655 my %hash = @_; 1656 1657 my $text; 1658 1659 unless ($text = $self->{tmps}->{$self->{cfg}->{lang}}{$template}) { 1660 # Fall back to English if the language template doesn't exist 1661 1662 if ($text = $self->{tmps}->{EN}{$template}) { 1663 print "Note: No translation in '$self->{cfg}->{lang}' for '$template' - falling back to English.\n" 1664 unless ($self->{cfg}->{silent}); 1665 } else { 1666 die("No template for '$template' in language file.\n"); 1667 } 1668 } 1669 if($self->{iconv}) { 1670 $text = $self->{iconv}->convert($text); 1671 die("Could not convert charset for template '$template'.\n") unless $text; 1672 } 1673 1674 $hash{channel} = $self->{cfg}->{channel}; 1675 # the nick is sanitized here, everything else outside of _template_text 1676 $hash{nick} = $self->_format_word($hash{nick}) if $hash{nick}; 1677 1678 foreach my $key (sort keys %hash) { 1679 $text =~ s/\[:$key\]/$hash{$key}/; 1680 } 1681 1682 if ($text =~ /\[:[^:]*?:[^:]*?:[^:]*?:\]/o) { 1683 $text =~ s/\[:([^:]*?):([^:]*?):([^:]*?):\]/$self->_get_subst($1,$2,$3,\%hash)/geo; 1684 } 1685 if ($text =~ /\[:[^:]*?:[^:]*?:]/o) { 1686 $text =~ s/\[:([^:]*?):([^:]*?):]/$self->_get_subst($1,$2,undef,\%hash)/geo; 1687 } 1688 1689 return $text; 1690} 1691 1692sub _format_word 1693{ 1694 # This function formats a word -- should ONLY be called on words used alone (EG: not whole line printed) 1695 my ($self, $word, $nick) = @_; # nick is only defined for user links in top table 1696 1697 $word = htmlentities($word, $self->{cfg}->{charset}); 1698 $word = $self->_replace_links($word, $nick); 1699 return $word; 1700} 1701 1702sub _format_line 1703{ 1704 # This function formats a action/normal line to be more readable, and calls any other function 1705 # that should be executed on every line. 1706 my ($self, $line) = @_; 1707 my $hashref; 1708 if ($hashref = $self->{cfg}->{analyzer}->{parser}->normalline($line)) { 1709 $line = '<' . $hashref->{nick} . '> ' . $hashref->{saying}; 1710 } elsif ($hashref = $self->{cfg}->{analyzer}->{parser}->actionline($line)) { 1711 $line = '* ' . $hashref->{nick} . ' ' . $hashref->{saying}; 1712 } elsif ($hashref = $self->{cfg}->{analyzer}->{parser}->thirdline($line)) { 1713 if (defined($hashref->{kicker})) { 1714 $line = '*** ' . $hashref->{nick} . ' was kicked by ' . $hashref->{kicker}; 1715 $line .= ' (' . $hashref->{kicktext} . ')' 1716 if (defined($hashref->{kicktext})); 1717 } elsif (defined($hashref->{newtopic})) { 1718 $line = '*** ' . $hashref->{nick} . ' changes topic to \'' . $hashref->{newtopic} . '\''; 1719 } elsif (defined($hashref->{newmode})) { 1720 $line = '*** ' . $hashref->{nick} . ' sets mode ' . $hashref->{newmode}; 1721 $line .= ' ' . $hashref->{modechanges} 1722 if (defined($hashref->{kicktext})); 1723 } elsif (defined($hashref->{newjoin})) { 1724 $line = '*** Joins: ' . $hashref->{nick}; 1725 } elsif (defined($hashref->{newnick})) { 1726 $line = '*** ' . $hashref->{nick} . ' is now known as ' . $hashref->{newnick}; 1727 } elsif (defined($hashref->{newtopic})) { 1728 $line = '*** ' . $hashref->{nick} . ' changes topic to: ' . $hashref->{newtopic}; 1729 } 1730 } 1731 $line = htmlentities($line, $self->{cfg}->{charset}); 1732 $line = $self->_replace_links($line); 1733 return $line; 1734} 1735 1736sub _get_subst 1737{ 1738 # This function looks at the user definition and see if there is sex 1739 # defined. If yes, return the appropriate value. If no, just return the 1740 # default he/she value. 1741 my $self = shift; 1742 my ($m,$f,$d,$hash) = @_; 1743 if ($hash->{nick} && $self->{users}->{sex}{$hash->{nick}}) { 1744 if ($self->{users}->{sex}{$hash->{nick}} eq 'm') { 1745 return $m; 1746 } elsif ($self->{users}->{sex}{$hash->{nick}} eq 'f') { 1747 return $f; 1748 } 1749 } 1750 return defined($d) ? $d : "$m/$f"; 1751} 1752 1753sub _mostusedword 1754{ 1755 # Word usage statistics 1756 my $self = shift; 1757 1758 my %usages; 1759 1760 foreach my $word (keys %{ $self->{stats}->{wordcounts} }) { 1761 # Skip people's nicks. 1762 next if is_nick($word, $self->{cfg}->{cachedir}); 1763 next if (length($word) < $self->{cfg}->{wordlength}); 1764 $usages{$word} = $self->{stats}->{wordcounts}{$word}; 1765 } 1766 1767 1768 my @popular = sort { $usages{$b} <=> $usages{$a} } keys %usages; 1769 1770 if (@popular) { 1771 $self->_headline($self->_template_text('mostwordstopic')); 1772 1773 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 1774 _html("<td> </td><td class=\"tdtop\"><b>" . $self->_template_text('word') . "</b></td>"); 1775 _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>"); 1776 _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>"); 1777 1778 1779 my $count = 0; 1780 for(my $i = 0; $count < $self->{cfg}->{wordhistory}; $i++) { 1781 last unless $i < $#popular; 1782 # Skip nicks. It's far more efficient to do this here than when 1783 # @popular is created. 1784 next if is_ignored($popular[$i]); 1785 1786 my $a = $count + 1; 1787 my $popular = $self->_format_word($self->{stats}->{word_upcase}{$popular[$i]}); 1788 my $wordcount = $self->{stats}->{wordcounts}{$popular[$i]}; 1789 my $lastused = $self->_format_word($self->{stats}->{wordnicks}{$popular[$i]}); 1790 my $class; 1791 if ($a == 1) { 1792 $class = 'hirankc'; 1793 } else { 1794 $class = 'rankc'; 1795 } 1796 _html("<tr><td class=\"$class\">$a</td>"); 1797 _html("<td class=\"hicell\">$popular</td>"); 1798 _html("<td class=\"hicell\">$wordcount</td>"); 1799 _html("<td class=\"hicell\">$lastused</td>"); 1800 _html("</tr>"); 1801 $count++; 1802 } 1803 1804 _html("</table>"); 1805 } 1806} 1807 1808sub _mostwordsperline 1809{ 1810 # The person who got the most words per line 1811 my $self = shift; 1812 1813 my %wpl = (); 1814 my $numlines = 0; 1815 my ($avg, $numwords); 1816 foreach my $nick (keys %{ $self->{stats}->{words} }) { 1817 if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) { 1818 $wpl{$nick} = sprintf("%.2f", $self->{stats}->{words}{$nick}/$self->{stats}->{lines}{$nick}); 1819 $numlines += $self->{stats}->{lines}{$nick}; 1820 $numwords += $self->{stats}->{words}{$nick}; 1821 } 1822 } 1823 if ($numlines > 0) { 1824 $avg = sprintf("%.2f", $numwords/$numlines); 1825 } 1826 1827 my @wpl = sort { $wpl{$b} <=> $wpl{$a} } keys %wpl; 1828 1829 if (@wpl) { 1830 my %hash = ( 1831 nick => $wpl[0], 1832 wpl => $wpl{$wpl[0]} 1833 ); 1834 1835 my $text = $self->_template_text('wpl1', %hash); 1836 _html("<tr><td class=\"hicell\">$text"); 1837 1838 $hash{avg} = $avg; 1839 1840 $text = $self->_template_text('wpl2', %hash); 1841 _html("<br /><span class=\"small\">$text</span>"); 1842 _html("</td></tr>"); 1843 } 1844} 1845 1846sub _mostreferencednicks 1847{ 1848 # List showing the most referenced nicks 1849 my $self = shift; 1850 1851 my %usages; 1852 1853 foreach my $word (sort keys %{ $self->{stats}->{wordcounts} }) { 1854 next if is_ignored($word); 1855 my $nick = is_nick($word) or next; 1856 next if !exists $self->{stats}->{lines}{$nick}; 1857 $usages{$word} = $self->{stats}->{wordcounts}{$word}; 1858 } 1859 1860 my @popular = sort { $usages{$b} <=> $usages{$a} } keys %usages; 1861 1862 if (@popular) { 1863 1864 $self->_headline($self->_template_text('referencetopic')); 1865 1866 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 1867 _html("<td> </td><td class=\"tdtop\"><b>" . $self->_template_text('nick') . "</b></td>"); 1868 _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>"); 1869 _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>"); 1870 1871 for(my $i = 0; $i < $self->{cfg}->{nickhistory}; $i++) { 1872 last if $i >= @popular; 1873 my $a = $i + 1; 1874 my $popular = $self->_format_word(is_nick($popular[$i])); 1875 my $wordcount = $self->{stats}->{wordcounts}{$popular[$i]}; 1876 my $lastused = $self->_format_word($self->{stats}->{wordnicks}{$popular[$i]} || ""); 1877 # this is undefined when a nick is referenced before being used 1878 # first (this is a minor bug we ignore here, see test/01.cfg) 1879 1880 my $class; 1881 if ($a == 1) { 1882 $class = 'hirankc'; 1883 } else { 1884 $class = 'rankc'; 1885 } 1886 _html("<tr><td class=\"$class\">$a</td>"); 1887 _html("<td class=\"hicell\">$popular</td>"); 1888 _html("<td class=\"hicell\">$wordcount</td>"); 1889 _html("<td class=\"hicell\">$lastused</td>"); 1890 _html("</tr>"); 1891 } 1892 _html("</table>"); 1893 } 1894} 1895 1896sub _smileys 1897{ 1898 my $self = shift; 1899 1900 my %usages; 1901 foreach my $smiley (sort keys %{ $self->{stats}->{smileys} }) { 1902 $usages{$smiley} = $self->{stats}->{smileys}{$smiley}; 1903 } 1904 my @popular = sort { $usages{$b} <=> $usages{$a} } keys %usages; 1905 return unless @popular; 1906 1907 $self->_headline($self->_template_text('smileytopic')); 1908 1909 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 1910 _html("<td> </td><td class=\"tdtop\"><b>" . $self->_template_text('smiley') . "</b></td>"); 1911 _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>"); 1912 _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>"); 1913 1914 for(my $i = 0; $i < $self->{cfg}->{smileyhistory}; $i++) { 1915 last if $i >= @popular; 1916 my $a = $i + 1; 1917 my $popular = $self->_format_word($popular[$i]); 1918 my $count = $self->{stats}->{smileys}{$popular[$i]}; 1919 my $lastused = $self->_format_word($self->{stats}->{smileynicks}{$popular[$i]} || ""); 1920 1921 my $class = ($a == 1) ? 'hirankc' : 'rankc'; 1922 _html("<tr><td class=\"$class\">$a</td>"); 1923 _html("<td class=\"hicell\">$popular</td>"); 1924 _html("<td class=\"hicell\">$count</td>"); 1925 _html("<td class=\"hicell\">$lastused</td>"); 1926 _html("</tr>"); 1927 } 1928 _html("</table>"); 1929} 1930 1931sub _karma 1932{ 1933 # List showing the most referenced nicks 1934 my $self = shift; 1935 1936 my %karma; 1937 1938 foreach my $thing (sort keys %{ $self->{stats}->{karma} }) { 1939 my $Thing = lc(is_nick($thing) || $thing); # FIXME: this is ugly 1940 foreach my $nick (keys %{ $self->{stats}->{karma}{$thing} }) { 1941 $karma{$Thing} += $self->{stats}->{karma}{$thing}{$nick}; 1942 } 1943 } 1944 1945 my @popular = sort { $karma{$b} <=> $karma{$a} } keys %karma; 1946 return unless @popular; 1947 1948 $self->_headline($self->_template_text('karmatopic')); 1949 1950 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 1951 _html("<td> </td><td class=\"tdtop\"><b>" . $self->_template_text('nick') . "</b></td>"); 1952 _html("<td class=\"tdtop\"><b>" . $self->_template_text('karma') . "</b></td>"); 1953 _html("<td class=\"tdtop\"><b>" . $self->_template_text('goodkarma') . "</b></td>"); 1954 _html("<td class=\"tdtop\"><b>" . $self->_template_text('badkarma') . "</b></td></tr>"); 1955 1956 my @goodpos = grep { $karma{$_} > 0 } @popular; 1957 splice @goodpos, $self->{cfg}->{karmahistory}, @goodpos 1958 if @goodpos > $self->{cfg}->{karmahistory}; 1959 my @badpos = grep { $karma{$_} < 0 } @popular; 1960 splice @badpos, 0, @badpos - $self->{cfg}->{karmahistory} 1961 if @badpos > $self->{cfg}->{karmahistory}; 1962 1963 my $pos = 0; 1964 foreach my $thing (@goodpos) { 1965 my $class = ($pos++ == 0) ? 'hirankc' : 'rankc'; 1966 my $Thing = $self->_format_word(is_nick($thing) || $thing); # ugliness #2 1967 _html("<tr><td class=\"$class\">$pos</td>"); 1968 _html("<td class=\"hicell\">$Thing</td>"); 1969 _html("<td class=\"hicell\">$karma{$thing}</td>"); 1970 1971 my @k = grep { $self->{stats}->{karma}{$thing}{$_} > 0 } 1972 (keys %{ $self->{stats}->{karma}{$thing} }); 1973 @k = $self->_trimlist(@k); 1974 my $n = join ', ', map { $self->_format_word($_) } @k; 1975 _html("<td class=\"hicell\">$n</td>"); 1976 1977 @k = grep { $self->{stats}->{karma}{$thing}{$_} < 0 } 1978 (keys %{ $self->{stats}->{karma}{$thing} }); 1979 @k = $self->_trimlist(@k); 1980 $n = join ', ', map { $self->_format_word($_) } @k; 1981 _html("<td class=\"hicell\">$n</td>"); 1982 _html("</tr>"); 1983 } 1984 1985 if (@goodpos and @badpos) { 1986 _html("<tr><td class=\"rankc\"></td>"); 1987 _html("<td class=\"hicell\" colspan=\"4\"></td>"); 1988 _html("</tr>"); 1989 } 1990 1991 $pos = @badpos; 1992 foreach my $thing (@badpos) { 1993 my $class = ($pos == 1) ? 'hirankc' : 'rankc'; 1994 my $Thing = $self->_format_word(is_nick($thing) || $thing); 1995 _html("<tr><td class=\"$class\">". ($pos--) ."</td>"); 1996 _html("<td class=\"hicell\">$Thing</td>"); 1997 _html("<td class=\"hicell\">$karma{$thing}</td>"); 1998 1999 my @k = grep { $self->{stats}->{karma}{$thing}{$_} > 0 } 2000 (keys %{ $self->{stats}->{karma}{$thing} }); 2001 @k = $self->_trimlist(@k); 2002 my $n = join ', ', map { $self->_format_word($_) } @k; 2003 _html("<td class=\"hicell\">$n</td>"); 2004 2005 @k = grep { $self->{stats}->{karma}{$thing}{$_} < 0 } 2006 (keys %{ $self->{stats}->{karma}{$thing} }); 2007 @k = $self->_trimlist(@k); 2008 $n = join ', ', map { $self->_format_word($_) } @k; 2009 _html("<td class=\"hicell\">$n</td>"); 2010 _html("</tr>"); 2011 } 2012 _html("</table>"); 2013} 2014 2015sub _mosturls 2016{ 2017 # List showing the most referenced URLs 2018 my $self = shift; 2019 2020 my @sorturls = sort { $self->{stats}->{urlcounts}{$b} <=> $self->{stats}->{urlcounts}{$a} } 2021 keys %{ $self->{stats}->{urlcounts} }; 2022 2023 if (@sorturls) { 2024 2025 $self->_headline($self->_template_text('urlstopic')); 2026 2027 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 2028 _html("<td> </td><td class=\"tdtop\"><b>" . $self->_template_text('url') . "</b></td>"); 2029 _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>"); 2030 _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>"); 2031 2032 for(my $i = 0; $i < $self->{cfg}->{urlhistory}; $i++) { 2033 last unless $i < @sorturls; 2034 my $a = $i + 1; 2035 my $urlcount = $self->{stats}->{urlcounts}{$sorturls[$i]}; 2036 my $lastused = $self->{stats}->{urlnicks}{$sorturls[$i]}; 2037 my $printurl = $sorturls[$i]; 2038 if ($printurl and length($printurl) > 60) { 2039 $printurl = substr($printurl, 0, 60); 2040 } 2041 $printurl = htmlentities($printurl, $self->{cfg}->{charset}); 2042 my $linkurl = urlencode($sorturls[$i]); 2043 my $class = ($a == 1) ? 'hirankc' : 'rankc'; 2044 _html("<tr><td class=\"$class\">$a</td>"); 2045 _html("<td class=\"hicell\"><a href=\"$linkurl\">$printurl</a></td>"); 2046 _html("<td class=\"hicell\">$urlcount</td>"); 2047 _html("<td class=\"hicell\">$lastused</td>"); 2048 _html("</tr>"); 2049 } 2050 _html("</table>"); 2051 } 2052} 2053 2054sub _charts 2055{ 2056 # List showing the most played songs 2057 my $self = shift; 2058 2059 my @sortcharts = sort { $self->{stats}->{chartcounts}{$b} <=> $self->{stats}->{chartcounts}{$a} } 2060 keys %{ $self->{stats}->{chartcounts} }; 2061 2062 if (@sortcharts) { 2063 2064 $self->_headline($self->_template_text('chartstopic')); 2065 2066 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 2067 _html("<td> </td><td class=\"tdtop\"><b>" . $self->_template_text('song') . "</b></td>"); 2068 _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberplayed') . "</b></td>"); 2069 _html("<td class=\"tdtop\"><b>" . $self->_template_text('playedby') . "</b></td></tr>"); 2070 2071 for(my $i = 0; $i < $self->{cfg}->{chartshistory}; $i++) { 2072 last unless $i < @sortcharts; 2073 my $a = $i + 1; 2074 my $song = $sortcharts[$i]; 2075 my $chartcount = $self->{stats}->{chartcounts}{$song}; 2076 my $lastused = $self->{stats}->{chartnicks}{$song}; 2077 $song = $self->{stats}->{word_upcase}{$song}; 2078 $song = substr($song, 0, 60) if (length($song) > 60); 2079 $song = $self->_format_word($song); 2080 my $class = ($a == 1) ? 'hirankc' : 'rankc'; 2081 _html("<tr><td class=\"$class\">$a</td>"); 2082 _html("<td class=\"hicell\">$song</td>"); 2083 _html("<td class=\"hicell\">$chartcount</td>"); 2084 _html("<td class=\"hicell\">$lastused</td>"); 2085 _html("</tr>"); 2086 } 2087 _html("</table>"); 2088 } 2089} 2090 2091sub _legend 2092{ 2093 # A legend showing the timebars and their associated time. 2094 my $self = shift; 2095 _html("<table align=\"center\" border=\"0\" width=\"520\"><tr>"); 2096 _html("<td align=\"center\" class=\"asmall\"><img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{pic_h_0}\" width=\"40\" height=\"15\" align=\"middle\" alt=\"0-5\" /> = 0-5</td>"); 2097 _html("<td align=\"center\" class=\"asmall\"><img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{pic_h_6}\" width=\"40\" height=\"15\" align=\"middle\" alt=\"6-11\" /> = 6-11</td>"); 2098 _html("<td align=\"center\" class=\"asmall\"><img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{pic_h_12}\" width=\"40\" height=\"15\" align=\"middle\" alt=\"12-17\" /> = 12-17</td>"); 2099 _html("<td align=\"center\" class=\"asmall\"><img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{pic_h_18}\" width=\"40\" height=\"15\" align=\"middle\" alt=\"18-23\" /> = 18-23</td>"); 2100 _html("</tr></table>"); 2101} 2102 2103 2104sub _replace_url # used internally by _replace_links 2105{ 2106 my ($self, $url, $www, $ftp, $text) = @_; 2107 $url = "http://$url" if $www; 2108 $url = "ftp://$url" if $ftp; 2109 my $texturl = $self->_template_text("newwindow"); 2110 return "<a href=\"$url\" target=\"_blank\" title=\"$texturl $url\">" . $self->_split_long_text($text) . '</a>'; 2111} 2112 2113 2114sub _replace_email # used internally by _replace_links 2115{ 2116 my ($self, $mailto, $user, $domain, $nick) = @_; 2117 $mailto = '' if $nick or not $mailto; 2118 $nick ||= "$user@$domain"; # obfuscate mail address 2119 my $textmail = $self->_template_text("mailto"); 2120 return "<a href=\"mailto:$user@$domain\" title=\"$textmail $nick\">" . $self->_split_long_text($mailto . $nick) . "<\/a>"; 2121} 2122 2123 2124sub _replace_links 2125{ 2126 # replace URLs and email addresses by links 2127 my ($self, $str, $nick) = @_; # nick is only defined for user links in top table 2128 2129 # Regular expressions are taken from match_urls() and match_email() in 2130 # Common.pm 2131 2132 my (@str) = split(/ /,$str); 2133 2134 foreach (@str) { 2135 s/((?:(?:https?|ftp|telnet|news):\/\/|(?:(?:(www)|(ftp))[\w-]*\.))[-\w\/~\@:]+\.\S+[\w\/])/$self->_replace_url($1, $2, $3, $nick || $1)/egio 2136 or s/(mailto:)?([-\w.]+)@([-\w]+\.[-\w.]+)/$self->_replace_email($1, $2, $3, $nick)/egio 2137 or $_ = $self->_split_long_text($_); 2138 } 2139 2140 return join(' ', @str); 2141} 2142 2143sub _split_long_text 2144{ 2145 my ($self, $str) = @_; 2146 $str =~ s/(\S{$self->{cfg}->{quotewidth}})(?!\s)/$1-<br \/>/og; 2147 2148 return($str); 2149} 2150 2151sub _user_linetimes 2152{ 2153 my $self = shift; 2154 my $nick = shift; 2155 my $top = shift; 2156 2157 my $bar = ""; 2158 my $len = ($self->{stats}->{lines}{$nick} / $self->{stats}->{lines}{$top}) * 100; 2159 2160 for (my $i = 0; $i <= 3; $i++) { 2161 my $l = $self->{stats}->{line_times}{$nick}[$i]; 2162 next if not defined $l; 2163 my $w = int(($l / $self->{stats}->{lines}{$nick}) * $len); 2164 if ($w) { 2165 my $pic = 'pic_h_'.(6*$i); 2166 $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"$l\" title=\"$l\" />"; 2167 } 2168 } 2169 return "$bar $self->{stats}->{lines}{$nick}"; 2170} 2171 2172sub _user_wordtimes 2173{ 2174 my $self = shift; 2175 my $nick = shift; 2176 my $top = shift; 2177 2178 $self->{stats}->{words}{$nick} ||= 0; 2179 my $len = ($self->{stats}->{words}{$nick} / $self->{stats}->{words}{$top}) * 100; 2180 2181 my $bar = ""; 2182 for (my $i = 0; $i <= 3; $i++) { 2183 next if not defined $self->{stats}->{word_times}{$nick}[$i]; 2184 my $w = int(($self->{stats}->{word_times}{$nick}[$i] / $self->{stats}->{words}{$nick}) * $len); 2185 if ($w) { 2186 my $pic = 'pic_h_'.(6*$i); 2187 $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"\" />"; 2188 } 2189 } 2190 return "$bar $self->{stats}->{words}{$nick}"; 2191} 2192 2193sub _user_times 2194{ 2195 my $self = shift; 2196 my ($nick) = @_; 2197 2198 my $bar = ""; 2199 2200 my $itemstat = ($self->{cfg}->{sortbywords} ? 'words' : 'lines'); 2201 my $timestat = ($self->{cfg}->{sortbywords} ? 'word_times' : 'line_times'); 2202 2203 for (my $i = 0; $i <= 3; $i++) { 2204 my $l = $self->{stats}->{$timestat}{$nick}[$i]; 2205 next if not defined $l; 2206 my $w = int(($l / $self->{stats}->{$itemstat}{$nick}) * 40); 2207 if ($w) { 2208 my $pic = 'pic_h_'.(6*$i); 2209 $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" alt=\"$l\" title=\"$l\" />"; 2210 } 2211 } 2212 return $bar; 2213} 2214 2215sub _user_pic 2216{ 2217 my $self = shift; 2218 my $nick = shift; 2219 my $style = shift; 2220 2221 return unless $self->{users}->{userpics}{$nick} or $self->{cfg}->{defaultpic}; 2222 2223 my $rowspan = $self->{cfg}->{userpics} ? " rowspan=\"$self->{cfg}->{userpics}\"" : ""; 2224 my $output = "<td $style align=\"center\" valign=\"middle\"$rowspan>"; 2225 2226 my $biguserpic = $self->{users}->{biguserpics}{$nick}; 2227 if ($biguserpic) { 2228 $biguserpic = $self->{cfg}->{imagepath} . 2229 randomglob($biguserpic, $self->{cfg}->{imageglobpath}, $nick) 2230 if $biguserpic !~ /^http:\/\//i; 2231 $output .= "<a href=\"$biguserpic\">"; 2232 } 2233 2234 my $pic = $self->{users}->{userpics}{$nick} || $self->{cfg}->{defaultpic}; 2235 $pic = $self->{cfg}->{imagepath} . 2236 randomglob($pic, $self->{cfg}->{imageglobpath}, $nick) 2237 unless $pic =~ /^http:\/\//i; 2238 my $height = $self->{cfg}->{picheight} ? " height=\"$self->{cfg}->{picheight}\"" : ""; 2239 my $width = $self->{cfg}->{picwidth} ? " width=\"$self->{cfg}->{picwidth}\"" : ""; 2240 my $alt = $self->{users}->{userpics}{$nick} ? " alt=\"$nick\" title=\"$nick\"" : ""; 2241 my $border = $biguserpic ? ' border="0"' : ''; 2242 $output .= "<img src=\"$pic\"$width$height$alt$border />"; 2243 2244 $output .= "</a>" if $biguserpic; 2245 _html("$output</td>"); 2246} 2247 2248sub _mostnicks 2249{ 2250 # List showing the user with most used nicks 2251 my $self = shift; 2252 2253 my @sortnicks = sort { keys %{ $self->{stats}->{nicks}->{$b} } <=> keys %{ $self->{stats}->{nicks}->{$a} } } 2254 keys %{ $self->{stats}->{nicks} }; 2255 2256 if (keys %{ $self->{stats}->{nicks}->{$sortnicks[0]} } > 1) { 2257 2258 $self->_headline($self->_template_text('mostnickstopic')); 2259 2260 my $names1 = $self->_template_text('names1'); 2261 my $names2 = $self->_template_text('names2'); 2262 my $nick_txt = $self->_template_text('nick'); 2263 my $names_txt = $self->_template_text('names'); 2264 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 2265 _html("<td> </td><td class=\"tdtop\"><b>$nick_txt</b></td>"); 2266 _html("<td class=\"tdtop\"><b>$names_txt</b></td></tr>"); 2267 2268 my $a = 0; 2269 foreach my $nick (@sortnicks) { 2270 next if is_ignored($nick); 2271 my $nickcount = keys %{ $self->{stats}->{nicks}->{$nick} }; 2272 my @nicks = values %{ $self->{stats}->{nicks}->{$nick} }; 2273 my $nickused = join(", ", $self->_trimlist(@nicks)); 2274 2275 last unless ($nickcount > 1); 2276 2277 $a++; 2278 my $class = $a == 1 ? 'hirankc' : 'rankc'; 2279 my $n = $nickcount > 1 ? $names1 : $names2; 2280 2281 _html("<tr><td class=\"$class\">$a</td>"); 2282 if ($self->{cfg}->{mostnicksverbose}) { 2283 _html("<td class=\"hicell\">$nick ($nickcount $n)</td>"); 2284 _html("<td class=\"hicell\" valign='top'>$nickused</td>"); 2285 } else { 2286 _html("<td class=\"hicell\">$nick</td>"); 2287 _html("<td class=\"hicell\" valign='top'>$nickcount $n</td>"); 2288 } 2289 _html("</tr>"); 2290 last if $a >= $self->{cfg}->{mostnickshistory}; 2291 } 2292 _html("</table>"); 2293 } 2294} 2295 2296sub _mostactivebyhour 2297{ 2298 # Charts for most active nicks by hour (0-5, 6-11, 12-17, 18-23) 2299 my $self = shift; 2300 2301 my $sortnicks; 2302 2303 my $lastline=-1; 2304 my $maxlines=0; 2305 2306 foreach my $period (0,1,2,3) { 2307 my @sortnicks = 2308 sort 2309 { 2310 (defined $self->{stats}->{line_times}{$b}[$period]?$self->{stats}->{line_times}{$b}[$period]:0) 2311 <=> 2312 (defined $self->{stats}->{line_times}{$a}[$period]?$self->{stats}->{line_times}{$a}[$period]:0) 2313 } 2314 keys %{ $self->{stats}->{line_times} } ; 2315 2316 for(my $i = 0; $i < $self->{cfg}->{activenicksbyhour}; $i++) { 2317 next if ! $sortnicks[$i]; 2318 next if is_ignored($sortnicks[$i]); 2319 last unless $i < @sortnicks; 2320 2321 my $nick=$sortnicks[$i]; 2322 my $count=$self->{stats}->{line_times}{$nick}[$period] || 0; 2323 2324 last unless $nick; 2325 last unless $count; 2326 2327 $sortnicks->[$period][$i]=$nick; 2328 2329 if ($lastline<$i) { 2330 $lastline=$i; 2331 } 2332 2333 2334 if ($maxlines<$count) { 2335 $maxlines=$count; 2336 } 2337 } 2338 } 2339 2340 if ($lastline>=0) { 2341 2342 $self->_headline($self->_template_text('activenickbyhourtopic')); 2343 2344 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 2345 _html("<td> </td>"); 2346 _html("<td class=\"tdtop\"><b>0-5</b></td>"); 2347 _html("<td class=\"tdtop\"><b>6-11</b></td>"); 2348 _html("<td class=\"tdtop\"><b>12-17</b></td>"); 2349 _html("<td class=\"tdtop\"><b>18-23</b></td>"); 2350 _html("</tr>"); 2351 2352 for(my $i = 0; $i <= $lastline; $i++) { 2353 2354 my $a = $i + 1; 2355 my $class = $a == 1 ? 'hirankc' : 'rankc'; 2356 2357 _html("<tr><td class=\"$class\">$a</td>"); 2358 foreach my $period (0,1,2,3) { 2359 my $nick=$sortnicks->[$period][$i]; 2360 if ($nick) { 2361 my $count=$self->{stats}->{line_times}{$nick}[$period]; 2362 if ($count) { 2363 _html("<td class=\"hicell\">"); 2364 if ($self->{cfg}->{showmostactivebyhourgraph}) { 2365 my $pic = 'pic_h_'.(6*$period); 2366 my $w = int(($count / $maxlines) * 100) || 1; 2367 _html("<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"\" />"); 2368 } 2369 _html($self->_format_word($nick)." - ".$count); 2370 _html("</td>"); 2371 } else { 2372 _html("<td class=\"hicell\"> </td>"); 2373 } 2374 } else { 2375 _html("<td class=\"hicell\"> </td>"); 2376 } 2377 } 2378 _html("</tr>"); 2379 } 2380 _html("</table>"); 2381 } 2382} 2383 2384sub _topactive { 2385 my $self = shift; 2386 my @top_active; 2387 my $top_nicks; 2388 2389 if ($self->{cfg}->{sortbywords}) { 2390 @top_active = sort { $self->{stats}->{words}{$b} <=> $self->{stats}->{words}{$a} } 2391 keys %{ $self->{stats}->{words} }; 2392 $top_nicks = scalar keys %{ $self->{stats}->{words} }; 2393 } else { 2394 @top_active = sort { $self->{stats}->{lines}{$b} <=> $self->{stats}->{lines}{$a} } 2395 keys %{ $self->{stats}->{lines} }; 2396 $top_nicks = scalar keys %{ $self->{stats}->{lines} }; 2397 } 2398 2399 if ($self->{cfg}->{activenicks} > $top_nicks) { 2400 $self->{cfg}->{activenicks} = $top_nicks; 2401 } 2402 if (($self->{cfg}->{activenicks}+$self->{cfg}->{activenicks2}) > $top_nicks) { 2403 $self->{cfg}->{activenicks2} = $top_nicks-$self->{cfg}->{activenicks}; 2404 } 2405 2406 (@top_active) = @top_active[0..($self->{cfg}->{activenicks}-1)]; 2407 $self->{stats}->{topactive_lines} = @top_active ? $self->{stats}->{lines}{$top_active[0]} : 1; 2408 2409 foreach (@top_active) { 2410 $self->{topactive}{$_} = 1; 2411 } 2412} 2413 2414 2415sub _istoponly { 2416 my $self = shift; 2417 my (@nicks_tmp) = @_; 2418 my @nicks; 2419 my $cnt=0; 2420 2421 if ($self->{cfg}->{showonlytop}) { 2422 foreach my $nick (@nicks_tmp) { 2423 if ($self->{topactive}{$nick}) { 2424 push(@nicks, $nick); 2425 } 2426 } 2427 return(@nicks); 2428 } else { 2429 return(@nicks_tmp); 2430 } 2431} 2432 2433sub _trimlist { 2434 my $self = shift; 2435 return @_ unless $self->{cfg}->{nicklimit}; 2436 splice @_, $self->{cfg}->{nicklimit}, @_, qw/.../ if @_ > $self->{cfg}->{nicklimit}; 2437 return @_; 2438} 2439 2440sub _activegenders { 2441 # The most active gender in the channel 2442 my $self = shift; 2443 my @topgender = sort {$self->{stats}->{sex_lines}{$b} <=> $self->{stats}->{sex_lines}{$a}} keys %{$self->{stats}->{sex_lines}}; 2444 2445 return unless @topgender; 2446 2447 $self->_headline($self->_template_text('activegenderstopic')); 2448 _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>"); 2449 _html(" <td> </td>" 2450 . "<td class=\"tdtop\"><b>" . $self->_template_text('gender') . "</b></td>" 2451 . "<td class=\"tdtop\"><b>" . $self->_template_text('numberlines') . "</b></td>" 2452 . "<td class=\"tdtop\"><b>" . $self->_template_text('nick') . "</b></td>" 2453 ); 2454 2455 my $i = 1; 2456 for my $gender (@topgender) { 2457 my $bar = ""; 2458 my $len = ($self->{stats}->{sex_lines}{$gender} / $self->{stats}->{sex_lines}{$topgender[0]}) * 100; 2459 2460 for (0 .. 3) { 2461 next if not defined $self->{stats}->{sex_line_times}{$gender}[$_]; 2462 my $w = int(($self->{stats}->{sex_line_times}{$gender}[$_] / $self->{stats}->{sex_lines}{$gender}) * $len); 2463 if ($w) { 2464 my $pic = 'pic_h_'.(6*$_); 2465 $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"$self->{stats}->{sex_line_times}{$gender}[$_]\" />"; 2466 } 2467 } 2468 2469 my @top_active = sort { $self->{stats}->{lines}{$b} <=> $self->{stats}->{lines}{$a} } 2470 grep { $self->{users}->{sex}{$_} and $self->{users}->{sex}{$_} eq $gender } 2471 keys %{ $self->{stats}->{lines} }; 2472 my $nicklist = join ", ", 2473 map { $_ . ($self->{stats}->{lines}{$_} ? " ($self->{stats}->{lines}{$_})" : "") } 2474 $self->_trimlist(@top_active); 2475 2476 my $class = ($i == 1 ? "hirankc" : "rankc"); 2477 my $span_class = $gender eq 'm' ? "male" : ($gender eq 'f' ? "female" : "bot"); 2478 _html("</tr><tr>"); 2479 _html(" <td class=\"$class\" align=\"left\">$i</td>"); 2480 _html(" <td class=\"hicell\"><span class=\"$span_class\">" . $self->_template_text("gender_$gender") . "</span></td>"); 2481 _html(" <td class=\"hicell\"><span style=\"white-space:nowrap;\">$bar</span> $self->{stats}->{sex_lines}{$gender}</td>"); 2482 _html(" <td class=\"hicell\">$nicklist</td>"); 2483 $i++; 2484 } 2485 2486 _html("</tr></table>"); 2487} 2488 24891; 2490 2491__END__ 2492 2493=head1 NAME 2494 2495Pisg::HTMLGenerator - class to create a static HTML page out of data parsed 2496 2497=head1 DESCRIPTION 2498 2499C<Pisg::HTMLGenerator> uses the hash returned by Pisg::Parser::Logfile and turns it into a static HTML page. 2500 2501=head1 SYNOPSIS 2502 2503 use Pisg::HTMLGenerator; 2504 2505 $generator = new Pisg::HTMLGenerator( 2506 cfg => $cfg, 2507 stats => $stats, 2508 users => $users, 2509 tmps => $tmps 2510 ); 2511 2512=head1 CONSTRUCTOR 2513 2514=over 4 2515 2516=item new ( [ OPTIONS ] ) 2517 2518This is the constructor for a new Pisg::HTMLGenerator object. C<OPTIONS> are passed in a hash like fashion using key and value pairs. 2519 2520Possible options are: 2521 2522B<cfg> - hashref containing configuration variables, created by the Pisg module. 2523 2524B<stats> - reference to the hash returned by Pisg::Parser::Logfile containing all stats. 2525 2526B<users> - reference to a hash containg user information 2527 2528B<tmps> - reference to a hash containing the language templates. 2529 2530=back 2531 2532=head1 AUTHOR 2533 2534Morten Brix Pedersen <morten@wtf.dk> 2535 2536=head1 COPYRIGHT 2537 2538Copyright (C) 2001-2005 Morten Brix Pedersen. All rights reserved. 2539Copyright (C) 2003-2005 Christoph Berg <cb@df7cb.de>. 2540This program is free software; you can redistribute it and/or modify it 2541under the terms of the GPL, license is included with the distribution of 2542this file. 2543 2544=cut 2545