1package Onis::Plugins::Core; 2 3use strict; 4use warnings; 5 6use Carp (qw(confess)); 7use Exporter; 8 9=head1 NAME 10 11Onis::Plugins::Core 12 13=head1 DESCRIPTION 14 15Plugin for the main table and the hourly-statistics. This is the most 16complicated plugin so far. 17 18=cut 19 20use Onis::Config (qw(get_config)); 21use Onis::Html (qw(html_escape get_filehandle)); 22use Onis::Language (qw(translate)); 23use Onis::Users (qw(get_realname get_link get_image chatter_to_name)); 24use Onis::Data::Core (qw(get_all_nicks nick_to_ident ident_to_nick get_main_nick register_plugin)); 25use Onis::Data::Persistent (); 26 27@Onis::Plugins::Core::EXPORT_OK = (qw(get_core_nick_counters get_sorted_nicklist nick_is_in_main_table)); 28@Onis::Plugins::Core::ISA = ('Exporter'); 29 30our $NickLinesCounter = Onis::Data::Persistent->new ('NickLinesCounter', 'nick', 31 qw( 32 lines00 lines01 lines02 lines03 lines04 lines05 lines06 lines07 lines08 lines09 lines10 lines11 33 lines12 lines13 lines14 lines15 lines16 lines17 lines18 lines19 lines20 lines21 lines22 lines23 34 ) 35); 36our $NickWordsCounter = Onis::Data::Persistent->new ('NickWordsCounter', 'nick', 37 qw( 38 words00 words01 words02 words03 words04 words05 words06 words07 words08 words09 words10 words11 39 words12 words13 words14 words15 words16 words17 words18 words19 words20 words21 words22 words23 40 ) 41); 42our $NickCharsCounter = Onis::Data::Persistent->new ('NickCharsCounter', 'nick', 43 qw( 44 chars00 chars01 chars02 chars03 chars04 chars05 chars06 chars07 chars08 chars09 chars10 chars11 45 chars12 chars13 chars14 chars15 chars16 chars17 chars18 chars19 chars20 chars21 chars22 chars23 46 ) 47); 48 49our $QuoteCache = Onis::Data::Persistent->new ('QuoteCache', 'key', qw(epoch text)); 50our $QuotePtr = Onis::Data::Persistent->new ('QuotePtr', 'nick', qw(pointer)); 51 52our $QuoteData = {}; # Is generated before output. Nicks are merged according to Data::Core. 53our $NickData = {}; # Same as above, but for nicks rather than quotes. 54our $SortedNicklist = []; 55 56our $NicksInMainTable = {}; 57 58our @HorizontalImages = qw#dark-theme/h-red.png dark-theme/h-blue.png dark-theme/h-yellow.png dark-theme/h-green.png#; 59our $QuoteCacheSize = 10; 60our $QuoteMin = 30; 61our $QuoteMax = 80; 62our $SortBy = 'LINES'; 63our $DisplayLines = 'BOTH'; 64our $DisplayWords = 'NONE'; 65our $DisplayChars = 'NONE'; 66our $DisplayTimes = 0; 67our $DisplayImages = 0; 68our $DefaultImage = ''; 69our $LongLines = 50; 70our $ShortLines = 10; 71 72=head1 CONFIGURATION OPTIONS 73 74=over 4 75 76=item B<quote_cache_size>: I<10> 77 78Sets how many quotes are cached and, at the end, one is chosen at random. 79 80=cut 81 82if (get_config ('quote_cache_size')) 83{ 84 my $tmp = get_config ('quote_cache_size'); 85 $tmp =~ s/\D//g; 86 $QuoteCacheSize = $tmp if ($tmp); 87} 88 89=item B<quote_min>: I<30> 90 91Minimum number of characters in a line to be included in the quote-cache. 92 93=cut 94 95if (get_config ('quote_min')) 96{ 97 my $tmp = get_config ('quote_min'); 98 $tmp =~ s/\D//g; 99 $QuoteMin = $tmp if ($tmp); 100} 101=item B<quote_max>: I<80> 102 103Maximum number of characters in a line to be included in the quote-cache. 104 105=cut 106 107if (get_config ('quote_max')) 108{ 109 my $tmp = get_config ('quote_max'); 110 $tmp =~ s/\D//g; 111 $QuoteMax = $tmp if ($tmp); 112} 113 114=item B<display_lines>: I<BOTH> 115 116Choses wether to display B<lines> as I<BAR>, I<NUMBER>, I<BOTH> or not at all 117(I<NONE>). 118 119=cut 120 121if (get_config ('display_lines')) 122{ 123 my $tmp = get_config ('display_lines'); 124 $tmp = uc ($tmp); 125 126 if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH')) 127 { 128 $DisplayLines = $tmp; 129 } 130 else 131 { 132 $tmp = get_config ('display_lines'); 133 print STDERR $/, __FILE__, ": ``display_lines'' has been set to the invalid value ``$tmp''. ", 134 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``both''."; 135 } 136} 137 138=item B<display_words>: I<NONE> 139 140See L<display_lines> 141 142=cut 143 144if (get_config ('display_words')) 145{ 146 my $tmp = get_config ('display_words'); 147 $tmp = uc ($tmp); 148 149 if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH')) 150 { 151 $DisplayWords = $tmp; 152 } 153 else 154 { 155 $tmp = get_config ('display_words'); 156 print STDERR $/, __FILE__, ": ``display_words'' has been set to the invalid value ``$tmp''. ", 157 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``none''."; 158 } 159} 160 161=item B<display_chars>: I<NONE> 162 163See L<display_lines> 164 165=cut 166 167if (get_config ('display_chars')) 168{ 169 my $tmp = get_config ('display_chars'); 170 $tmp = uc ($tmp); 171 172 if (($tmp eq 'NONE') or ($tmp eq 'BAR') or ($tmp eq 'NUMBER') or ($tmp eq 'BOTH')) 173 { 174 $DisplayChars = $tmp; 175 } 176 else 177 { 178 $tmp = get_config ('display_chars'); 179 print STDERR $/, __FILE__, ": ``display_chars'' has been set to the invalid value ``$tmp''. ", 180 $/, __FILE__, ": Valid values are ``none'', ``bar'', ``number'' and ``both''. Using default value ``none''."; 181 } 182} 183 184=item B<display_times>: I<false> 185 186Wether or not to display a fixed width bar that shows when a user is most 187active. 188 189=cut 190 191if (get_config ('display_times')) 192{ 193 my $tmp = get_config ('display_times'); 194 195 if ($tmp =~ m/true|on|yes/i) 196 { 197 $DisplayTimes = 1; 198 } 199 elsif ($tmp =~ m/false|off|no/i) 200 { 201 $DisplayTimes = 0; 202 } 203 else 204 { 205 print STDERR $/, __FILE__, ": ``display_times'' has been set to the invalid value ``$tmp''. ", 206 $/, __FILE__, ": Valid values are ``true'' and ``false''. Using default value ``false''."; 207 } 208} 209 210=item B<display_images>: I<false> 211 212Wether or not to display images in the main ranking. 213 214=cut 215 216if (get_config ('display_images')) 217{ 218 my $tmp = get_config ('display_images'); 219 220 if ($tmp =~ m/true|on|yes/i) 221 { 222 $DisplayImages = 1; 223 } 224 elsif ($tmp =~ m/false|off|no/i) 225 { 226 $DisplayImages = 0; 227 } 228 else 229 { 230 print STDERR $/, __FILE__, ": ``display_times'' has been set to the invalid value ``$tmp''. ", 231 $/, __FILE__, ": Valid values are ``true'' and ``false''. Using default value ``false''."; 232 } 233} 234 235=item B<default_image>: I<http://www.url.org/image.png> 236 237Sets the URL to the default image. This is included as-is in the HTML. You have 238to take care of (absolute) paths yourself. 239 240=cut 241 242if (get_config ('default_image')) 243{ 244 $DefaultImage = get_config ('default_image'); 245} 246 247=item B<sort_by>: I<LINES> 248 249Sets by which field the output has to be sorted. This is completely independent 250from B<display_lines>, B<display_words> and B<display_chars>. Valid options are 251I<LINES>, I<WORDS> and I<CHARS>. 252 253=cut 254 255if (get_config ('sort_by')) 256{ 257 my $tmp = get_config ('sort_by'); 258 $tmp = uc ($tmp); 259 260 if (($tmp eq 'LINES') or ($tmp eq 'WORDS') or ($tmp eq 'CHARS')) 261 { 262 $SortBy = $tmp; 263 } 264 else 265 { 266 $tmp = get_config ('sort_by'); 267 print STDERR $/, __FILE__, ": ``sort_by'' has been set to the invalid value ``$tmp''. ", 268 $/, __FILE__, ": Valid values are ``lines'' and ``words''. Using default value ``lines''."; 269 } 270} 271 272=item B<horizontal_images>: I<image1>, I<image2>, I<image3>, I<image4> 273 274Sets the B<four> images used for horizontal bars/graphs. As above: You have to 275take care of correctness of paths yourself. 276 277=cut 278 279if (get_config ('horizontal_images')) 280{ 281 my @tmp = get_config ('horizontal_images'); 282 my $i; 283 284 if (scalar (@tmp) != 4) 285 { 286 print STDERR $/, __FILE__, ": The number of horizontal images is not four. The output might look weird.", $/; 287 } 288 289 for ($i = 0; $i < 4; $i++) 290 { 291 if (!defined ($tmp[$i])) 292 { 293 next; 294 } 295 296 $HorizontalImages[$i] = $tmp[$i]; 297 } 298} 299 300=item B<longlines>: I<50> 301 302Sets the number of rows of the main ranking table. 303 304=cut 305 306if (get_config ('longlines')) 307{ 308 my $tmp = get_config ('longlines'); 309 $tmp =~ s/\D//g; 310 $LongLines = $tmp if ($tmp); 311} 312 313=item B<shortlines>: I<10> 314 315Sets the number of rows of the "they didn't write so much" table. There are six 316persons per line; you set the number of lines. 317 318=over 319 320=cut 321 322if (get_config ('shortlines')) 323{ 324 my $tmp = get_config ('shortlines'); 325 $tmp =~ s/\D//g; 326 if ($tmp or ($tmp == 0)) 327 { 328 $ShortLines = $tmp; 329 } 330} 331 332register_plugin ('TEXT', \&add); 333register_plugin ('ACTION', \&add); 334register_plugin ('OUTPUT', \&output); 335 336my $VERSION = '$Id: Core.pm 114 2005-04-30 14:54:40Z octo $'; 337print STDERR $/, __FILE__, ": $VERSION" if ($::DEBUG); 338 339return (1); 340 341sub add 342{ 343 my $data = shift; 344 345 my $nick = $data->{'nick'}; 346 my $ident = $data->{'ident'}; 347 my $hour = int ($data->{'hour'}); 348 my $host = $data->{'host'}; 349 my $text = $data->{'text'}; 350 my $type = $data->{'type'}; 351 my $time = $data->{'epoch'}; 352 353 my $words = scalar (@{$data->{'words'}}); 354 my $chars = length ($text); 355 356 if ($type eq 'ACTION') 357 { 358 $chars -= (length ($nick) + 3); 359 } 360 361 my @counter = $NickLinesCounter->get ($nick); 362 if (!@counter) 363 { 364 @counter = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0); 365 } 366 $counter[$hour]++; 367 $NickLinesCounter->put ($nick, @counter); 368 369 @counter = $NickWordsCounter->get ($nick); 370 if (!@counter) 371 { 372 @counter = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0); 373 } 374 $counter[$hour] += $words; 375 $NickWordsCounter->put ($nick, @counter); 376 377 @counter = $NickCharsCounter->get ($nick); 378 if (!@counter) 379 { 380 @counter = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0); 381 } 382 $counter[$hour] += $chars; 383 $NickCharsCounter->put ($nick, @counter); 384 385 if ((length ($text) >= $QuoteMin) 386 and (length ($text) <= $QuoteMax)) 387 { 388 my ($pointer) = $QuotePtr->get ($nick); 389 $pointer ||= 0; 390 391 my $key = sprintf ("%s:%02i", $nick, $pointer); 392 393 $QuoteCache->put ($key, $time, $text); 394 395 $pointer = ($pointer + 1) % $QuoteCacheSize; 396 $QuotePtr->put ($nick, $pointer); 397 } 398 return (1); 399} 400 401sub calculate 402{ 403 for (get_all_nicks ()) 404 { 405 my $nick = $_; 406 my $main = get_main_nick ($nick); 407 408 if (!defined ($NickData->{$main})) 409 { 410 $NickData->{$main} = 411 { 412 lines => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)], 413 words => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)], 414 chars => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)], 415 lines_total => 0, 416 words_total => 0, 417 chars_total => 0 418 }; 419 } 420 421 my @counter = $NickLinesCounter->get ($nick); 422 if (@counter) 423 { 424 my $sum = 0; 425 for (my $i = 0; $i < 24; $i++) 426 { 427 $NickData->{$main}{'lines'}[$i] += $counter[$i]; 428 $sum += $counter[$i]; 429 } 430 $NickData->{$main}{'lines_total'} += $sum; 431 } 432 433 @counter = $NickWordsCounter->get ($nick); 434 if (@counter) 435 { 436 my $sum = 0; 437 for (my $i = 0; $i < 24; $i++) 438 { 439 $NickData->{$main}{'words'}[$i] += $counter[$i]; 440 $sum += $counter[$i]; 441 } 442 $NickData->{$main}{'words_total'} += $sum; 443 } 444 445 @counter = $NickCharsCounter->get ($nick); 446 if (@counter) 447 { 448 my $sum = 0; 449 for (my $i = 0; $i < 24; $i++) 450 { 451 $NickData->{$main}{'chars'}[$i] += $counter[$i]; 452 $sum += $counter[$i]; 453 } 454 $NickData->{$main}{'chars_total'} += $sum; 455 } 456 457 if (!defined ($QuoteData->{$main})) 458 { 459 $QuoteData->{$main} = []; 460 } 461 } 462 463 for ($QuoteCache->keys ()) 464 { 465 my $key = $_; 466 my ($nick, $num) = split (m/:/, $key); 467 my $main = get_main_nick ($nick); 468 469 my ($epoch, $text) = $QuoteCache->get ($key); 470 die unless (defined ($text)); 471 472 if (!defined ($QuoteData->{$main})) 473 { 474 next; 475 } 476 elsif (scalar (@{$QuoteData->{$main}}) < $QuoteCacheSize) 477 { 478 push (@{$QuoteData->{$main}}, [$epoch, $text]); 479 } 480 else 481 { 482 my $insert = -1; 483 my $min = $epoch; 484 485 for (my $i = 0; $i < $QuoteCacheSize; $i++) 486 { 487 if ($QuoteData->{$main}[$i][0] < $min) 488 { 489 $insert = $i; 490 $min = $QuoteData->{$main}[$i][0]; 491 } 492 } 493 494 if ($insert != -1) 495 { 496 $QuoteData->{$main}[$insert] = [$epoch, $text]; 497 } 498 } 499 } 500} 501 502sub output 503{ 504 calculate (); 505 activetimes (); 506 ranking (); 507} 508 509sub activetimes 510{ 511 my $max = 0; # the most lines that were written in one hour.. 512 my $total = 0; # the total amount of lines we wrote.. 513 514 my @data = qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0); 515 516 my @img_urls = get_config ('vertical_images'); 517 if (!@img_urls) 518 { 519 @img_urls = qw#images/ver0n.png images/ver1n.png images/ver2n.png images/ver3n.png#; 520 } 521 522 my $fh = get_filehandle () or die; 523 524# this for loop looks for the most amount of lines in one hour and sets 525# $most_lines 526 for (keys %$NickData) 527 { 528 my $nick = $_; 529 530 for (my $i = 0; $i < 24; $i++) 531 { 532 $data[$i] += $NickData->{$nick}{'chars'}[$i]; 533 } 534 } 535 536 for (my $i = 0; $i < 24; $i++) 537 { 538 $max = $data[$i] if ($max < $data[$i]); 539 $total += $data[$i]; 540 } 541 542 if (!$total) 543 { 544 $total = 1; 545 $max = 1; 546 } 547 548 my $header = translate ('When do we actually talk here?'); 549 print $fh "<h2>$header</h2>\n", 550 qq#<table class="hours">\n#, 551 qq# <tr class="bars">\n#; 552 553# this for circles through the four colors. Each color represents six hours. 554# (4 * 6 hours = 24 hours) 555 for (my $i = 0; $i <= 3; $i++) 556 { 557 for (my $j = 0; $j < 6; $j++) 558 { 559 my $hour = (($i * 6) + $j); 560 if (!defined ($data[$hour])) 561 { 562 $data[$hour] = 0; 563 } 564 565 my $height = sprintf ("%.2f", 95 * $data[$hour] / $max); 566 my $img = $img_urls[$i]; 567 568 print $fh qq# <td class="bar vertical"><img src="$img" class="first last" style="height: $height\%;" alt="" /></td>\n#; 569 } 570 } 571 print $fh qq# </tr>\n <tr class="counter">\n#; 572 for (my $i = 0; $i < 24; $i++) 573 { 574 my $percent = sprintf ("%.1f", 100 * $data[$i] / $total); 575 print $fh qq# <td class="counter">$percent\%</td>\n#; 576 } 577 578 print $fh " </tr>\n", 579 qq# <tr class="numeration">\n#; 580 print $fh map { qq# <td class="numeration">$_</td>\n# } (0 .. 23); 581 print $fh " </tr>\n", 582 "</table>\n\n"; 583} 584 585sub ranking 586{ 587 my $count = 0; 588 589 my @nicks = keys (%$NickData); 590 591 return unless (@nicks); 592 593 my $max_lines = 1; 594 my $max_words = 1; 595 my $max_chars = 1; 596 597 my $linescount = 0; 598 599 my $fh = get_filehandle () or die; 600 601 my $sort_field = lc ($SortBy); 602 603 my $trans; 604 605 my $tmp; 606 ($tmp) = sort { $NickData->{$b}{'lines_total'} <=> $NickData->{$a}{'lines_total'} } (@nicks); 607 $max_lines = $NickData->{$tmp}{'lines_total'} || 0; 608 609 ($tmp) = sort { $NickData->{$b}{'words_total'} <=> $NickData->{$a}{'words_total'} } (@nicks); 610 $max_words = $NickData->{$tmp}{'words_total'} || 0; 611 612 ($tmp) = sort { $NickData->{$b}{'chars_total'} <=> $NickData->{$a}{'chars_total'} } (@nicks); 613 $max_chars = $NickData->{$tmp}{'chars_total'} || 0; 614 615 $trans = translate ('Most active nicks'); 616 617 print $fh "<h2>$trans</h2>\n"; 618 if ($SortBy eq 'LINES') 619 { 620 $trans = translate ('Nicks sorted by numbers of lines written'); 621 } 622 elsif ($SortBy eq 'WORDS') 623 { 624 $trans = translate ('Nicks sorted by numbers of words written'); 625 } 626 else # ($SortBy eq 'CHARS') 627 { 628 $trans = translate ('Nicks sorted by numbers of characters written'); 629 } 630 print $fh "<p>($trans)</p>\n"; 631 632 print $fh <<EOF; 633 634<table class="big_ranking"> 635 <tr> 636 <td class="invis"> </td> 637EOF 638 if ($DisplayImages) 639 { 640 $trans = translate ('Image'); 641 print $fh " <th>$trans</th>\n"; 642 } 643 #if (true) 644 { 645 $trans = translate ('Nick'); 646 print $fh " <th>$trans</th>\n"; 647 } 648 if ($DisplayLines ne 'NONE') 649 { 650 my $span = $DisplayLines eq 'BOTH' ? ' colspan="2"' : ''; 651 $trans = translate ('Number of Lines'); 652 print $fh " <th$span>$trans</th>\n"; 653 } 654 if ($DisplayWords ne 'NONE') 655 { 656 my $span = $DisplayWords eq 'BOTH' ? ' colspan="2"' : ''; 657 $trans = translate ('Number of Words'); 658 print $fh " <th$span>$trans</th>\n"; 659 } 660 if ($DisplayChars ne 'NONE') 661 { 662 my $span = $DisplayChars eq 'BOTH' ? ' colspan="2"' : ''; 663 $trans = translate ('Number of Characters'); 664 print $fh " <th$span>$trans</th>\n"; 665 } 666 if ($DisplayTimes) 667 { 668 $trans = translate ('When?'); 669 print $fh " <th>$trans</th>\n"; 670 } 671 672 $trans = translate ('Random Quote'); 673 print $fh " <th>$trans</th>\n", 674 " </tr>\n"; 675 676 @$SortedNicklist = sort 677 { 678 $NickData->{$b}{"${sort_field}_total"} <=> $NickData->{$a}{"${sort_field}_total"} 679 } (@nicks); 680 681 @nicks = (); 682 683 for (@$SortedNicklist) 684 { 685 my $nick = $_; 686 my $ident = nick_to_ident ($nick); 687 my $name = chatter_to_name ("$nick!$ident"); 688 my $print = $name || $nick; 689 690 $linescount++; 691 692 # As long as we didn't hit the 693 # $LongLines-limit we continue 694 # our table.. 695 if ($linescount <= $LongLines) 696 { 697 $NicksInMainTable->{$nick} = $linescount; 698 699 my $quote = translate ('-- no quote available --'); 700 701 if (@{$QuoteData->{$nick}}) 702 { 703 my $num = scalar (@{$QuoteData->{$nick}}); 704 my $rand = int (rand ($num)); 705 706 $quote = html_escape ($QuoteData->{$nick}[$rand][1]); 707 } 708 709 my $link = ''; 710 my $image = ''; 711 my $realname = ''; 712 if ($name) 713 { 714 $link = get_link ($name); 715 $image = get_image ($name); 716 $realname = get_realname ($name); 717 } 718 719 print $fh " <tr>\n", 720 qq# <td class="numeration"># . $linescount . "</td>\n"; 721 722 if ($DisplayImages) 723 { 724 if ($DefaultImage and !$image) 725 { 726 $image = $DefaultImage; 727 } 728 729 print $fh qq# <td class="image">#; 730 if ($image) 731 { 732 if ($link) 733 { 734 print $fh qq#<a href="$link">#; 735 } 736 print $fh qq#<img src="$image" alt="$name" />#; 737 if ($link) 738 { 739 print $fh "</a>"; 740 } 741 } 742 else 743 { 744 print $fh ' '; 745 } 746 print $fh "</td>\n"; 747 } 748 749 my $title = $realname; 750 if (!$title) 751 { 752 $title = "User: $name; " if ($name); 753 $title .= "Ident: $ident"; 754 } 755 print $fh qq# <td class="nick" title="$title">#; 756 757 if ($link) 758 { 759 print $fh qq#<a href="$link">$print</a></td>\n# 760 } 761 else 762 { 763 print $fh qq#$print</td>\n#; 764 } 765 766 if ($DisplayLines ne 'NONE') 767 { 768 if (($DisplayLines eq 'BOTH') or ($DisplayLines eq 'NUMBER')) 769 { 770 my $num = $NickData->{$nick}{'lines_total'}; 771 print $fh qq( <td class="counter">$num</td>\n); 772 } 773 if (($DisplayLines eq 'BOTH') or ($DisplayLines eq 'BAR')) 774 { 775 my $code = bar ($max_lines, $NickData->{$nick}{'lines'}); 776 print $fh qq( <td class="bar horizontal">$code</td>\n); 777 } 778 } 779 780 if ($DisplayWords ne 'NONE') 781 { 782 if (($DisplayWords eq 'BOTH') or ($DisplayWords eq 'NUMBER')) 783 { 784 my $num = $NickData->{$nick}{'words_total'}; 785 print $fh qq( <td class="counter">$num</td>\n); 786 } 787 if (($DisplayWords eq 'BOTH') or ($DisplayWords eq 'BAR')) 788 { 789 my $code = bar ($max_words, $NickData->{$nick}{'words'}); 790 print $fh qq( <td class="bar horizontal">$code</td>\n); 791 } 792 } 793 794 if ($DisplayChars ne 'NONE') 795 { 796 if (($DisplayChars eq 'BOTH') or ($DisplayChars eq 'NUMBER')) 797 { 798 my $num = $NickData->{$nick}{'chars_total'}; 799 print $fh qq( <td class="counter">$num</td>\n); 800 } 801 if (($DisplayChars eq 'BOTH') or ($DisplayChars eq 'BAR')) 802 { 803 my $code = bar ($max_chars, $NickData->{$nick}{'chars'}); 804 print $fh qq( <td class="bar horizontal">$code</td>\n); 805 } 806 } 807 808 if ($DisplayTimes) 809 { 810 my $code = bar ($NickData->{$nick}{'chars_total'}, $NickData->{$nick}{'chars'}); 811 print $fh qq# <td class="bar horizontal">$code</td>\n#; 812 } 813 814 print $fh qq# <td class="quote">$quote</td>\n#, 815 qq# </tr>\n#; 816 817 if ($linescount == $LongLines) 818 { 819 print $fh "</table>\n\n"; 820 } 821 } 822 823 # Ok, we have too many people to 824 # list them all so we start a 825 # smaller table and just list the 826 # names.. (Six names per line..) 827 elsif ($linescount <= ($LongLines + 6 * $ShortLines)) 828 { 829 my $row_in_this_table = int (($linescount - $LongLines - 1) / 6); 830 my $col_in_this_table = ($linescount - $LongLines - 1) % 6; 831 832 my $total = 0; 833 if ($SortBy eq 'LINES') 834 { 835 $total = $NickData->{$nick}{'lines_total'}; 836 } 837 elsif ($SortBy eq 'WORDS') 838 { 839 $total = $NickData->{$nick}{'words_total'}; 840 } 841 else # ($SortBy eq 'CHARS') 842 { 843 $total = $NickData->{$nick}{'chars_total'}; 844 } 845 846 my $title = $name ? get_realname ($name) : ''; 847 if (!$title) 848 { 849 $title = "User: $name; " if ($name); 850 $title .= "Ident: $ident"; 851 } 852 853 if ($row_in_this_table == 0 and $col_in_this_table == 0) 854 { 855 $trans = translate ("They didn't write so much"); 856 print $fh "<h2>$trans</h2>\n", 857 qq#<table class="small_ranking">\n#, 858 qq# <tr>\n#; 859 } 860 861 if ($col_in_this_table == 0 and $row_in_this_table != 0) 862 { 863 print $fh " </tr>\n", 864 qq# <tr>\n#; 865 } 866 867 print $fh qq# <td title="$title">$print ($total)</td>\n#; 868 869 if ($row_in_this_table == $ShortLines and $col_in_this_table == 5) 870 { 871 print $fh " </tr>\n", 872 qq#</table>\n\n#; 873 } 874 } 875 876 # There is no else. There are 877 # just too many people around. 878 # I might add a "There are xyz 879 # unmentioned nicks"-line.. 880 } 881 882 if (($linescount > $LongLines) 883 and ($linescount <= ($LongLines + 6 * $ShortLines))) 884 { 885 my $col = ($linescount - $LongLines - 1) % 6; 886 887 while ($col < 5) 888 { 889 print $fh qq# <td> </td>\n#; 890 $col++; 891 } 892 893 print $fh " </tr>\n"; 894 } 895 896 if ($linescount != $LongLines) 897 { 898 print $fh "</table>\n\n"; 899 } 900} 901 902# this is called by "&ranking ();" and prints the horizontal usage-bar in the 903# detailed nick-table 904sub bar 905{ 906 my $max_num = shift; 907 my $source = shift; 908 909 confess () unless (ref ($source) eq 'ARRAY'); 910 911 my $retval = ''; 912 913 my $i; 914 my $j; 915 916 for ($i = 0; $i < 4; $i++) 917 { 918 my $sum = 0; 919 my $img = $HorizontalImages[$i]; 920 my $width; 921 922 for ($j = 0; $j < 6; $j++) 923 { 924 my $hour = ($i * 6) + $j; 925 $sum += $source->[$hour]; 926 } 927 928 $width = sprintf ("%.2f", 95 * $sum / $max_num); 929 930 $retval .= qq#<img src="$img" style="width: $width%;"#; 931 if ($i == 0) { $retval .= qq# class="first"#; } 932 elsif ($i == 3) { $retval .= qq# class="last"#; } 933 $retval .= qq( alt="$sum" />); 934 } 935 936 return ($retval); 937} 938 939=head1 EXPORTED FUNCTIONS 940 941=over 4 942 943=item B<get_core_nick_counters> (I<$nick>) 944 945Returns a hash-ref that containes all the nick-counters available. It looks 946like this: 947 948 { 949 lines => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)], 950 words => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)], 951 chars => [qw(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)], 952 lines_total => 0, 953 words_total => 0, 954 chars_total => 0 955 } 956 957=cut 958 959sub get_core_nick_counters 960{ 961 my $nick = shift; 962 963 if (!defined ($NickData->{$nick})) 964 { 965 return ({}); 966 } 967 968 return ($NickData->{$nick}); 969} 970 971=item B<get_sorted_nicklist> () 972 973Returns an array-ref that containes all nicks, sorted by the field given in the 974config-file. 975 976=cut 977 978sub get_sorted_nicklist 979{ 980 return ($SortedNicklist); 981} 982 983=item B<nick_is_in_main_table> (I<$nick>) 984 985Returns the position of the nick in the main table or zero if it is not in the 986main table. 987 988=cut 989 990sub nick_is_in_main_table 991{ 992 my $nick = shift; 993 994 return (defined ($NicksInMainTable->{$nick}) ? $NicksInMainTable->{$nick} : 0); 995} 996 997=back 998 999=head1 AUTHOR 1000 1001Florian octo Forster E<lt>octo at verplant.orgE<gt> 1002 1003=cut 1004