4
0

HTMLGenerator.pm 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072
  1. package Pisg::HTMLGenerator;
  2. # Copyright and license, as well as documentation(POD) for this module is
  3. # found at the end of the file.
  4. use strict;
  5. $^W = 1;
  6. sub new
  7. {
  8. my $type = shift;
  9. my %args = @_;
  10. my $self = {
  11. cfg => $args{cfg},
  12. stats => $args{stats},
  13. users => $args{users},
  14. tmps => $args{tmps},
  15. topactive => {},
  16. };
  17. # Import common functions in Pisg::Common
  18. require Pisg::Common;
  19. Pisg::Common->import();
  20. bless($self, $type);
  21. return $self;
  22. }
  23. sub create_html
  24. {
  25. # This subroutine calls all the subroutines which create their
  26. # individual stats. The name of the functions is somewhat saying - if
  27. # you don't understand it, most subs have a better explanation in the
  28. # sub itself.
  29. my $self = shift;
  30. $self->_topactive();
  31. print "Now generating HTML($self->{cfg}->{outputfile})...\n"
  32. unless ($self->{cfg}->{silent});
  33. open (OUTPUT, "> $self->{cfg}->{outputfile}") or
  34. die("$0: Unable to open outputfile($self->{cfg}->{outputfile}): $!\n");
  35. if ($self->{cfg}->{showtime}) {
  36. $self->{cfg}->{tablewidth} += 40;
  37. }
  38. if ($self->{cfg}->{showlinetime}) {
  39. $self->{cfg}->{tablewidth} += 100;
  40. }
  41. if ($self->{cfg}->{showwordtime}) {
  42. $self->{cfg}->{tablewidth} += 100;
  43. }
  44. if ($self->{cfg}->{showwords}) {
  45. $self->{cfg}->{tablewidth} += 40;
  46. }
  47. if ($self->{cfg}->{showwpl}) {
  48. $self->{cfg}->{tablewidth} += 40;
  49. }
  50. if ($self->{cfg}->{showcpl}) {
  51. $self->{cfg}->{tablewidth} += 40;
  52. }
  53. $self->{cfg}->{headwidth} = $self->{cfg}->{tablewidth} - 4;
  54. $self->_htmlheader();
  55. $self->_pageheader()
  56. if ($self->{cfg}->{pagehead} ne 'none');
  57. if ($self->{cfg}->{showactivetimes}) {
  58. $self->_activetimes();
  59. }
  60. $self->_activenicks();
  61. if ($self->{cfg}->{showmostactivebyhour}) {
  62. $self->_mostactivebyhour();
  63. }
  64. if ($self->{cfg}->{showbignumbers}) {
  65. $self->_headline($self->_template_text('bignumtopic'));
  66. _html("<table width=\"$self->{cfg}->{tablewidth}\">\n"); # Needed for sections
  67. $self->_questions();
  68. $self->_shoutpeople();
  69. $self->_capspeople();
  70. $self->_violent();
  71. $self->_mostsmiles();
  72. $self->_mostsad();
  73. $self->_linelengths();
  74. $self->_mostwords();
  75. $self->_mostwordsperline();
  76. _html("</table>"); # Needed for sections
  77. }
  78. if ($self->{cfg}->{showmostnicks}) {
  79. $self->_mostnicks();
  80. }
  81. if ($self->{cfg}->{showmuw}) {
  82. $self->_mostusedword();
  83. }
  84. if ($self->{cfg}->{showmrn}) {
  85. $self->_mostreferencednicks();
  86. }
  87. if ($self->{cfg}->{showmru}) {
  88. $self->_mosturls();
  89. }
  90. if ($self->{cfg}->{showbignumbers}) {
  91. $self->_headline($self->_template_text('othernumtopic'));
  92. _html("<table width=\"$self->{cfg}->{tablewidth}\">\n"); # Needed for sections
  93. $self->_gotkicks();
  94. $self->_mostkicks();
  95. $self->_mostop();
  96. $self->_mosthalfop() if $self->{cfg}->{showhalfops};
  97. $self->_mostvoice() if $self->{cfg}->{showvoices};
  98. $self->_mostactions();
  99. $self->_mostmonologues();
  100. $self->_mostjoins();
  101. $self->_mostfoul();
  102. _html("</table>"); # Needed for sections
  103. }
  104. if ($self->{cfg}->{showtopics}) {
  105. $self->_headline($self->_template_text('latesttopic'));
  106. _html("<table width=\"$self->{cfg}->{tablewidth}\">\n"); # Needed for sections
  107. $self->_lasttopics();
  108. _html("</table>"); # Needed for sections
  109. }
  110. my %hash = ( lines => $self->{stats}->{totallines} );
  111. _html($self->_template_text('totallines', %hash) . "<br /><br />");
  112. $self->_pagefooter()
  113. if ($self->{cfg}->{pagefoot} ne 'none');
  114. $self->_htmlfooter();
  115. close(OUTPUT);
  116. }
  117. sub _htmlheader
  118. {
  119. my $self = shift;
  120. my %hash = (
  121. network => $self->{cfg}->{network},
  122. maintainer => $self->{cfg}->{maintainer},
  123. days => $self->{stats}->{days},
  124. nicks => scalar keys %{ $self->{stats}->{lines} }
  125. );
  126. my $css_file = $self->{cfg}->{cssdir} . $self->{cfg}->{colorscheme} . ".css";
  127. # Get the chosen CSS file
  128. open(FILE, $css_file) or open (FILE, $self->{cfg}->{search_path} . "/$css_file") or die("$0: Unable to open stylesheet($css_file): $!\n");
  129. my @CSS = <FILE>;
  130. my $title = $self->_template_text('pagetitle1', %hash);
  131. print OUTPUT <<HTML;
  132. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  133. <html>
  134. <head>
  135. <meta http-equiv="Content-Type" content="text/html; charset=$self->{cfg}->{charset}" />
  136. <title>$title</title>
  137. <style type="text/css">
  138. @CSS
  139. </style></head>
  140. <body>
  141. <div align="center">
  142. HTML
  143. _html("<span class=\"title\">$title</span><br />");
  144. _html("<br />");
  145. _html($self->_template_text('pagetitle2', %hash) . " " . $self->get_time());
  146. _html("<br />" . $self->_template_text('pagetitle3', %hash) . "<br /><br />");
  147. }
  148. sub get_time
  149. {
  150. my $self = shift;
  151. my ($tday, %hash);
  152. my $month = $self->_template_text('month', %hash);
  153. my $day = $self->_template_text('day', %hash);
  154. my @month = split(" ", $month);
  155. my @day = split(" ", $day);
  156. # Get the Date from the users computer
  157. my $timezone = $self->{cfg}->{timeoffset} * 3600;
  158. my ($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(time+$timezone);
  159. $year += 1900; # Y2K Patch
  160. $min =~ s/^(.)$/0$1/; # Fixes the display of mins/secs below
  161. $sec =~ s/^(.)$/0$1/; # it displays 03 instead of 3
  162. if ($hour > '23') { # Checks to see if it Midnight
  163. $hour = 12; # Makes it display the hour 12
  164. $tday = "AM"; # Display AM
  165. } elsif($hour > '12') { # Get rid of the Military time and
  166. $hour -= 12; # put it into normal time
  167. $tday = "PM"; # If past Noon and before Midnight set
  168. } else {
  169. $tday = "AM"; # If it's past Midnight and before Noon
  170. } # set the time as AM
  171. # Use 24 hours pr. day
  172. if ($tday eq "PM" && $hour < '12') {
  173. $hour += 12;
  174. }
  175. return "$day[$wday] $mday $month[$mon] $year - $hour:$min:$sec";
  176. }
  177. sub _htmlfooter
  178. {
  179. my $self = shift;
  180. my %hash;
  181. my $pisg_hp = $self->_template_text('pisghomepage');
  182. $hash{pisg_url} = "<a href=\"http://pisg.sourceforge.net/\" title=\"$pisg_hp\" class=\"background\">pisg</a>";
  183. my $author_hp = $self->_template_text('authorhomepage');
  184. $hash{author_url} = "<a href=\"http://wtf.dk/hp/\" title=\"$author_hp\" class=\"background\">Morten Brix Pedersen</a>";
  185. $hash{version} = $self->{cfg}->{version};
  186. my $hours = $self->_template_text('hours');
  187. my $mins = $self->_template_text('minutes');
  188. my $secs = $self->_template_text('seconds');
  189. my $and = $self->_template_text('and');
  190. my $h = $self->{stats}->{processtime}{hours};
  191. my $m = $self->{stats}->{processtime}{mins};
  192. my $s = $self->{stats}->{processtime}{secs};
  193. $hash{time} = "$h $hours $m $mins $and $s $secs";
  194. my $stats_gen = $self->_template_text('stats_gen_by', %hash);
  195. my $author_text = $self->_template_text('author', %hash);
  196. my $stats_text = $self->_template_text('stats_gen_in', %hash);
  197. print OUTPUT <<HTML;
  198. <span class="small">
  199. $stats_gen<br />
  200. $author_text<br />
  201. $stats_text
  202. </span>
  203. </div>
  204. </body>
  205. </html>
  206. HTML
  207. }
  208. sub _headline
  209. {
  210. my $self = shift;
  211. my ($title) = (@_);
  212. print OUTPUT <<HTML;
  213. <br />
  214. <table width="$self->{cfg}->{headwidth}" cellpadding="1" cellspacing="0" border="0">
  215. <tr>
  216. <td class="headlinebg">
  217. <table width="100%" cellpadding="2" cellspacing="0" border="0">
  218. <tr>
  219. <td class="headtext">$title</td>
  220. </tr>
  221. </table>
  222. </td>
  223. </tr>
  224. </table>
  225. HTML
  226. }
  227. sub _pageheader
  228. {
  229. my $self = shift;
  230. open(PAGEHEAD, $self->{cfg}->{pagehead}) or die("$0: Unable to open $self->{cfg}->{pagehead} for reading: $!\n");
  231. while (<PAGEHEAD>) {
  232. _html($_);
  233. }
  234. close(PAGEHEAD);
  235. }
  236. sub _pagefooter
  237. {
  238. my $self = shift;
  239. open(PAGEFOOT, $self->{cfg}->{pagefoot}) or die("$0: Unable to open $self->{cfg}->{pagefoot} for reading: $!\n");
  240. while (<PAGEFOOT>) {
  241. _html($_);
  242. }
  243. close(PAGEFOOT);
  244. }
  245. sub _activetimes
  246. {
  247. # The most actives times on the channel
  248. my $self = shift;
  249. my (%output, $class);
  250. $self->_headline($self->_template_text('activetimestopic'));
  251. my @toptime = sort { $self->{stats}->{times}{$b} <=> $self->{stats}->{times}{$a} } keys %{ $self->{stats}->{times} };
  252. my $highest_value = $self->{stats}->{times}{$toptime[0]};
  253. my @now = localtime($self->{cfg}->{timestamp});
  254. my $image;
  255. for my $hour (sort keys %{ $self->{stats}->{times} }) {
  256. my $size = ($self->{stats}->{times}{$hour} / $highest_value) * 100;
  257. my $percent = ($self->{stats}->{times}{$hour} / $self->{stats}->{totallines}) * 100;
  258. $percent =~ s/(\.\d)\d+/$1/;
  259. if ($size < 1 && $size != 0) {
  260. # Opera doesn't understand '0.xxxx' in the height="xx" attr,
  261. # so we simply round up to 1.0 here.
  262. $size = 1.0;
  263. }
  264. $image = "pic_v_".(int($hour/6)*6);
  265. $image = $self->{cfg}->{$image};
  266. $output{$hour} = "<td align=\"center\" valign=\"bottom\" class=\"asmall\">$percent%<br /><img src=\"$self->{cfg}->{piclocation}/$image\" width=\"15\" height=\"$size\" alt=\"$percent\" /></td>\n";
  267. }
  268. _html("<table border=\"0\"><tr>\n");
  269. for ($b = 0; $b < 24; $b++) {
  270. $a = sprintf("%02d", $b);
  271. if (!defined($output{$a}) || $output{$a} eq "") {
  272. _html("<td align=\"center\" valign=\"bottom\" class=\"asmall\">0%</td>");
  273. } else {
  274. _html($output{$a});
  275. }
  276. }
  277. _html("</tr><tr>");
  278. # Remove leading zero
  279. $toptime[0] =~ s/0(\d)/$1/;
  280. for ($b = 0; $b < 24; $b++) {
  281. if ($toptime[0] == $b) {
  282. # Highlight the top time
  283. $class = 'hirankc10center';
  284. } else {
  285. $class = 'rankc10center';
  286. }
  287. _html("<td class=\"$class\" align=\"center\">$b</td>");
  288. }
  289. _html("</tr></table>");
  290. if($self->{cfg}->{showlegend} == 1) {
  291. $self->_legend();
  292. }
  293. }
  294. sub _activenicks
  295. {
  296. # The most active nicks (those who wrote most lines)
  297. my $self = shift;
  298. $self->_headline($self->_template_text('activenickstopic'));
  299. _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>");
  300. _html("<td>&nbsp;</td>"
  301. . "<td class=\"tdtop\"><b>" . $self->_template_text('nick') . "</b></td>"
  302. . "<td class=\"tdtop\"><b>" . $self->_template_text('numberlines') . "</b></td>"
  303. . ($self->{cfg}->{showtime} ? "<td class=\"tdtop\"><b>".$self->_template_text('show_time')."</b></td>" : "")
  304. . ($self->{cfg}->{showwords} ? "<td class=\"tdtop\"><b>".$self->_template_text('show_words')."</b></td>" : "")
  305. . ($self->{cfg}->{showwpl} ? "<td class=\"tdtop\"><b>".$self->_template_text('show_wpl')."</b></td>" : "")
  306. . ($self->{cfg}->{showcpl} ? "<td class=\"tdtop\"><b>".$self->_template_text('show_cpl')."</b></td>" : "")
  307. . ($self->{cfg}->{showlastseen} ? "<td class=\"tdtop\"><b>".$self->_template_text('show_lastseen')."</b></td>" : "")
  308. . ($self->{cfg}->{showrandquote} ? "<td class=\"tdtop\"><b>".$self->_template_text('randquote')."</b></td>" : "")
  309. );
  310. my @active;
  311. my $nicks;
  312. if ($self->{cfg}->{sortbywords}) {
  313. @active = sort { $self->{stats}->{words}{$b} <=> $self->{stats}->{words}{$a} } keys %{ $self->{stats}->{words} };
  314. $nicks = scalar keys %{ $self->{stats}->{words} };
  315. } else {
  316. @active = sort { $self->{stats}->{lines}{$b} <=> $self->{stats}->{lines}{$a} } keys %{ $self->{stats}->{lines} };
  317. $nicks = scalar keys %{ $self->{stats}->{lines} };
  318. }
  319. if ($self->{cfg}->{activenicks} > $nicks) { $self->{cfg}->{activenicks} = $nicks; }
  320. my $have_userpics;
  321. for (my $c = 0; $c < $self->{cfg}->{activenicks}; $c++) {
  322. my $nick = $active[$c];
  323. if ($self->{users}->{userpics}{$nick} && $self->{cfg}->{userpics} !~ /n/i) {
  324. $have_userpics = 1;
  325. _html("<td class=\"tdtop\"><b>" . $self->_template_text('userpic') ."</b></td>");
  326. last;
  327. }
  328. }
  329. _html("</tr>");
  330. for (my $i = 0; $i < $self->{cfg}->{activenicks}; $i++) {
  331. my $c = $i + 1;
  332. my $nick = $active[$i];
  333. my $visiblenick = $active[$i];
  334. my $randomline;
  335. if (not defined $self->{stats}->{sayings}{$nick}) {
  336. if ($self->{stats}->{actions}{$nick}) {
  337. $randomline = $self->_format_line($self->{stats}->{actionlines}{$nick});
  338. } else {
  339. $randomline = "";
  340. }
  341. } else {
  342. $randomline = $self->{stats}->{sayings}{$nick};
  343. }
  344. if ($randomline) {
  345. # Wrap longer than 40 chars words. It will break long HTML
  346. # links.
  347. # TODO: put <br> after 40 ! or ? marks - IE bug
  348. # TODO: respect long URLs (like merge spaces back in url?)
  349. # glen, 29/11/2002
  350. 1 while $randomline =~ s/(\S{40})(\S+)/$1 $2/m;
  351. $randomline = htmlentities($randomline);
  352. # Convert URLs and e-mail addys to links
  353. $randomline = $self->_replace_links($randomline);
  354. }
  355. # Add a link to the nick if there is any
  356. if ($self->{users}->{userlinks}{$nick}) {
  357. $visiblenick = $self->_replace_links($self->{users}->{userlinks}{$nick}, $nick);
  358. }
  359. my $color = $self->generate_colors($c);
  360. my $class = 'rankc';
  361. if ($c == 1) {
  362. $class = 'hirankc';
  363. }
  364. my $lastseen;
  365. if ($self->{cfg}->{showlastseen}) {
  366. $lastseen = $self->{stats}->{days} - $self->{stats}->{lastvisited}{$nick};
  367. if ($lastseen == 0) {
  368. $lastseen = $self->_template_text('today');
  369. } elsif ($lastseen == 1) {
  370. $lastseen = "$lastseen " .$self->_template_text('lastseen1');
  371. } else {
  372. $lastseen = "$lastseen " .$self->_template_text('lastseen2');
  373. }
  374. }
  375. _html("<tr><td class=\"$class\" align=\"left\">$c</td>");
  376. my $line = $self->{stats}->{lines}{$nick};
  377. my $w = $self->{stats}->{words}{$nick} ? $self->{stats}->{words}{$nick} : 0;
  378. my $ch = $self->{stats}->{lengths}{$nick};
  379. my $sex = $self->{users}->{sex}{$nick};
  380. _html("<td style=\"background-color: $color\""
  381. . ($sex ? ($sex eq 'm' ? " class=\"male\">"
  382. : ($sex eq 'f' ? " class=\"female\">" : " class=\"bot\">")) : ">")
  383. ."$visiblenick</td>"
  384. . ($self->{cfg}->{showlinetime} ?
  385. "<td style=\"background-color: $color\" nowrap=\"nowrap\">".$self->_user_linetimes($nick,$active[0])."</td>"
  386. : "<td style=\"background-color: $color\">$line</td>")
  387. . ($self->{cfg}->{showtime} ?
  388. "<td style=\"background-color: $color\">".$self->_user_times($nick)."</td>"
  389. : "")
  390. . ($self->{cfg}->{showwords} ?
  391. ($self->{cfg}->{showwordtime} ?
  392. "<td style=\"background-color: $color\" nowrap=\"nowrap\">".$self->_user_wordtimes($nick,$active[0])."</td>"
  393. : "<td style=\"background-color: $color\">$w</td>")
  394. : "")
  395. . ($self->{cfg}->{showwpl} ?
  396. "<td style=\"background-color: $color\">".sprintf("%.1f",$w/$line)."</td>"
  397. : "")
  398. . ($self->{cfg}->{showcpl} ?
  399. "<td style=\"background-color: $color\">".sprintf("%.1f",$ch/$line)."</td>"
  400. : "")
  401. . ($self->{cfg}->{showlastseen} ?
  402. "<td style=\"background-color: $color\">$lastseen</td>"
  403. : "")
  404. . ($self->{cfg}->{showrandquote} ?
  405. "<td style=\"background-color: $color\">\"$randomline\"</td>"
  406. : "")
  407. );
  408. my $height = $self->{cfg}->{picheight};
  409. my $width = $self->{cfg}->{picwidth};
  410. if ($self->{users}->{userpics}{$nick} && $self->{cfg}->{userpics} !~ /n/i) {
  411. _html("<td style=\"background-color: $color\" align=\"center\">");
  412. if (defined $self->{users}->{biguserpics}{$nick}) {
  413. _html("<a href=\"$self->{cfg}->{imagepath}$self->{users}->{biguserpics}{$nick}\">");
  414. }
  415. if ($width ne '') {
  416. _html("<img valign=\"middle\" src=\"$self->{cfg}->{imagepath}$self->{users}->{userpics}{$nick}\" width=\"$width\" height=\"$height\" alt=\"$nick\" />");
  417. } else {
  418. _html("<img valign=\"middle\" src=\"$self->{cfg}->{imagepath}$self->{users}->{userpics}{$nick}\" alt=\"$nick\" />");
  419. }
  420. if (defined $self->{users}->{biguserpics}{$nick}) {
  421. _html("</a>");
  422. }
  423. _html("</td>");
  424. } elsif ($self->{cfg}->{defaultpic} ne '' && $self->{cfg}->{userpics} !~ /n/i) {
  425. _html("<td style=\"background-color: $color\" align=\"center\"><img valign=\"middle\" src=\"$self->{cfg}->{imagepath}$self->{cfg}->{defaultpic}\" alt=\"\" /></td>");
  426. }
  427. _html("</tr>");
  428. }
  429. _html("</table><br />");
  430. # Almost as active nicks ('These didn't make it to the top..')
  431. my $toshow = $self->{cfg}->{activenicks2} - $self->{cfg}->{activenicks};
  432. my $remain = $self->{cfg}->{activenicks} + $toshow;
  433. unless ($toshow > $nicks) {
  434. $remain = $self->{cfg}->{activenicks} + $self->{cfg}->{activenicks2};
  435. if ($remain > $nicks) {
  436. $remain = $nicks;
  437. }
  438. if ($self->{cfg}->{activenicks} < $remain) {
  439. _html("<br /><b><i>" . $self->_template_text('nottop') . "</i></b><table><tr>");
  440. for (my $i = $self->{cfg}->{activenicks}; $i < $remain; $i++) {
  441. unless ($i % 5) { if ($i != $self->{cfg}->{activenicks}) { _html("</tr><tr>"); } }
  442. my $items;
  443. if ($self->{cfg}->{sortbywords}) {
  444. $items = $self->{stats}->{words}{$active[$i]};
  445. } else {
  446. $items = $self->{stats}->{lines}{$active[$i]};
  447. }
  448. my $sex = $self->{users}->{sex}{$active[$i]};
  449. _html("<td class=\"rankc10\">"
  450. . ($sex ? ($sex eq 'm' ? "<span class=\"male\">"
  451. : ($sex eq 'f' ? "<span class=\"female\">" : "<span class=\"bot\">")) : "")
  452. ."$active[$i] ($items)"
  453. . ($sex ? "</span>" : "")
  454. ."</td>");
  455. }
  456. _html("</tr></table>");
  457. }
  458. }
  459. my %hash;
  460. $hash{totalnicks} = $nicks - $remain;
  461. if ($hash{totalnicks} > 0) {
  462. _html("<br /><b>" . $self->_template_text('totalnicks', %hash) . "</b><br />");
  463. }
  464. }
  465. sub generate_colors
  466. {
  467. my $self = shift;
  468. my $c = shift;
  469. my $h = $self->{cfg}->{hicell};
  470. $h =~ s/^#//;
  471. $h = hex $h;
  472. my $h2 = $self->{cfg}->{hicell2};
  473. $h2 =~ s/^#//;
  474. $h2 = hex $h2;
  475. my $f_b = $h & 0xff;
  476. my $f_g = ($h & 0xff00) >> 8;
  477. my $f_r = ($h & 0xff0000) >> 16;
  478. my $t_b = $h2 & 0xff;
  479. my $t_g = ($h2 & 0xff00) >> 8;
  480. my $t_r = ($h2 & 0xff0000) >> 16;
  481. my $blue = sprintf "%0.2x", abs int(((($t_b - $f_b) / $self->{cfg}->{activenicks}) * +$c) + $f_b);
  482. my $green = sprintf "%0.2x", abs int(((($t_g - $f_g) / $self->{cfg}->{activenicks}) * +$c) + $f_g);
  483. my $red = sprintf "%0.2x", abs int(((($t_r - $f_r) / $self->{cfg}->{activenicks}) * +$c) + $f_r);
  484. return "#$red$green$blue";
  485. }
  486. sub _html
  487. {
  488. my $html = shift;
  489. print OUTPUT "$html\n";
  490. }
  491. sub _questions
  492. {
  493. # Persons who asked the most questions
  494. my $self = shift;
  495. my %qpercent;
  496. foreach my $nick (sort keys %{ $self->{stats}->{questions} }) {
  497. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  498. if ($self->{stats}->{lines}{$nick} > 100) {
  499. $qpercent{$nick} = ($self->{stats}->{questions}{$nick} / $self->{stats}->{lines}{$nick}) * 100;
  500. $qpercent{$nick} =~ s/(\.\d)\d+/$1/;
  501. }
  502. }
  503. }
  504. my @question = sort { $qpercent{$b} <=> $qpercent{$a} } keys %qpercent;
  505. if (@question) {
  506. my %hash = (
  507. nick => $question[0],
  508. per => $qpercent{$question[0]}
  509. );
  510. my $text = $self->_template_text('question1', %hash);
  511. _html("<tr><td class=\"hicell\">$text");
  512. if (@question >= 2) {
  513. my %hash = (
  514. nick => $question[1],
  515. per => $qpercent{$question[1]}
  516. );
  517. my $text = $self->_template_text('question2', %hash);
  518. _html("<br /><span class=\"small\">$text</span>");
  519. }
  520. _html("</td></tr>");
  521. } else {
  522. _html("<tr><td class=\"hicell\">" . $self->_template_text('question3') . "</td></tr>");
  523. }
  524. }
  525. sub _shoutpeople
  526. {
  527. # The ones who speak with exclamation marks!
  528. my $self = shift;
  529. my %spercent;
  530. foreach my $nick (sort keys %{ $self->{stats}->{shouts} }) {
  531. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  532. if ($self->{stats}->{lines}{$nick} > 100) {
  533. $spercent{$nick} = ($self->{stats}->{shouts}{$nick} / $self->{stats}->{lines}{$nick}) * 100;
  534. $spercent{$nick} =~ s/(\.\d)\d+/$1/;
  535. }
  536. }
  537. }
  538. my @shout = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent;
  539. if (@shout) {
  540. my %hash = (
  541. nick => $shout[0],
  542. per => $spercent{$shout[0]}
  543. );
  544. my $text = $self->_template_text('shout1', %hash);
  545. _html("<tr><td class=\"hicell\">$text");
  546. if (@shout >= 2) {
  547. my %hash = (
  548. nick => $shout[1],
  549. per => $spercent{$shout[1]}
  550. );
  551. my $text = $self->_template_text('shout2', %hash);
  552. _html("<br /><span class=\"small\">$text</span>");
  553. }
  554. _html("</td></tr>");
  555. } else {
  556. my $text = $self->_template_text('shout3');
  557. _html("<tr><td class=\"hicell\">$text</td></tr>");
  558. }
  559. }
  560. sub _capspeople
  561. {
  562. # The ones who speak ALL CAPS.
  563. my $self = shift;
  564. my %cpercent;
  565. foreach my $nick (sort keys %{ $self->{stats}->{allcaps} }) {
  566. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  567. if ($self->{stats}->{lines}{$nick} > 100) {
  568. $cpercent{$nick} = $self->{stats}->{allcaps}{$nick} / $self->{stats}->{lines}{$nick} * 100;
  569. $cpercent{$nick} =~ s/(\.\d)\d+/$1/;
  570. }
  571. }
  572. }
  573. my @caps = sort { $cpercent{$b} <=> $cpercent{$a} } keys %cpercent;
  574. if (@caps) {
  575. my %hash = (
  576. nick => $caps[0],
  577. per => $cpercent{$caps[0]},
  578. line => htmlentities($self->_format_line($self->{stats}->{allcaplines}{$caps[0]}))
  579. );
  580. my $text = $self->_template_text('allcaps1', %hash);
  581. if($self->{cfg}->{showshoutline}) {
  582. my $exttext = $self->_template_text('allcapstext', %hash);
  583. _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span><br />");
  584. } else {
  585. _html("<tr><td class=\"hicell\">$text");
  586. }
  587. if (@caps >= 2) {
  588. my %hash = (
  589. nick => $caps[1],
  590. per => $cpercent{$caps[1]}
  591. );
  592. my $text = $self->_template_text('allcaps2', %hash);
  593. _html("<br /><span class=\"small\">$text</span>");
  594. }
  595. _html("</td></tr>");
  596. } else {
  597. my $text = $self->_template_text('allcaps3');
  598. _html("<tr><td class=\"hicell\">$text</td></tr>");
  599. }
  600. }
  601. sub _violent
  602. {
  603. # They attacked others (words defined by $self->{cfg}->{violent})
  604. my $self = shift;
  605. my @aggressors = sort { $self->{stats}->{violence}{$b} <=> $self->{stats}->{violence}{$a} }
  606. keys %{ $self->{stats}->{violence} };
  607. @aggressors = $self->_istoponly(@aggressors);
  608. if(@aggressors) {
  609. my %hash = (
  610. nick => $aggressors[0],
  611. attacks => $self->{stats}->{violence}{$aggressors[0]},
  612. line => htmlentities($self->_format_line($self->{stats}->{violencelines}{$aggressors[0]}))
  613. );
  614. my $text = $self->_template_text('violent1', %hash);
  615. if($self->{cfg}->{showviolentlines}) {
  616. my $exttext = $self->_template_text('violenttext', %hash);
  617. _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span><br />");
  618. } else {
  619. _html("<tr><td class=\"hicell\">$text");
  620. }
  621. if (@aggressors >= 2) {
  622. my %hash = (
  623. nick => $aggressors[1],
  624. attacks => $self->{stats}->{violence}{$aggressors[1]}
  625. );
  626. my $text = $self->_template_text('violent2', %hash);
  627. _html("<br /><span class=\"small\">$text</span>");
  628. }
  629. _html("</td></tr>");
  630. } else {
  631. my $text = $self->_template_text('violent3');
  632. _html("<tr><td class=\"hicell\">$text</td></tr>");
  633. }
  634. # They got attacked
  635. my @victims = sort { $self->{stats}->{attacked}{$b} <=> $self->{stats}->{attacked}{$a} }
  636. keys %{ $self->{stats}->{attacked} };
  637. @victims = $self->_istoponly(@victims);
  638. if(@victims) {
  639. my %hash = (
  640. nick => $victims[0],
  641. attacks => $self->{stats}->{attacked}{$victims[0]},
  642. line => htmlentities($self->_format_line($self->{stats}->{attackedlines}{$victims[0]}))
  643. );
  644. my $text = $self->_template_text('attacked1', %hash);
  645. if($self->{cfg}->{showviolentlines}) {
  646. my $exttext = $self->_template_text('attackedtext', %hash);
  647. _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span><br />");
  648. } else {
  649. _html("<tr><td class=\"hicell\">$text");
  650. }
  651. if (@victims >= 2) {
  652. my %hash = (
  653. nick => $victims[1],
  654. attacks => $self->{stats}->{attacked}{$victims[1]}
  655. );
  656. my $text = $self->_template_text('attacked2', %hash);
  657. _html("<br /><span class=\"small\">$text</span>");
  658. }
  659. _html("</td></tr>");
  660. }
  661. }
  662. sub _gotkicks
  663. {
  664. # The persons who got kicked the most
  665. my $self = shift;
  666. my @gotkick = sort { $self->{stats}->{gotkicked}{$b} <=> $self->{stats}->{gotkicked}{$a} }
  667. keys %{ $self->{stats}->{gotkicked} };
  668. @gotkick = $self->_istoponly(@gotkick);
  669. if (@gotkick) {
  670. my %hash = (
  671. nick => $gotkick[0],
  672. kicks => $self->{stats}->{gotkicked}{$gotkick[0]},
  673. line => $self->_format_line($self->{stats}->{kicklines}{$gotkick[0]})
  674. );
  675. my $text = $self->_template_text('gotkick1', %hash);
  676. if ($self->{cfg}->{showkickline}) {
  677. my $exttext = $self->_template_text('kicktext', %hash);
  678. _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span><br />");
  679. } else {
  680. _html("<tr><td class=\"hicell\">$text");
  681. }
  682. if (@gotkick >= 2) {
  683. my %hash = (
  684. nick => $gotkick[1],
  685. kicks => $self->{stats}->{gotkicked}{$gotkick[1]}
  686. );
  687. my $text = $self->_template_text('gotkick2', %hash);
  688. _html("<br /><span class=\"small\">$text</span>");
  689. }
  690. _html("</td></tr>");
  691. }
  692. }
  693. sub _mostjoins
  694. {
  695. my $self = shift;
  696. my @joins = sort { $self->{stats}->{joins}{$b} <=> $self->{stats}->{joins}{$a} }
  697. keys %{ $self->{stats}->{joins} };
  698. @joins = $self->_istoponly(@joins);
  699. if (@joins) {
  700. my %hash = (
  701. nick => $joins[0],
  702. joins => $self->{stats}->{joins}{$joins[0]}
  703. );
  704. my $text = $self->_template_text('joins', %hash);
  705. _html("<tr><td class=\"hicell\">$text</td></tr>");
  706. }
  707. }
  708. sub _mostwords
  709. {
  710. # The person who got words the most
  711. my $self = shift;
  712. my @words = sort { $self->{stats}->{words}{$b} <=> $self->{stats}->{words}{$a} }
  713. keys %{ $self->{stats}->{words} };
  714. @words = $self->_istoponly(@words);
  715. if (@words) {
  716. my %hash = (
  717. nick => $words[0],
  718. words => $self->{stats}->{words}{$words[0]}
  719. );
  720. my $text = $self->_template_text('words1', %hash);
  721. _html("<tr><td class=\"hicell\">$text");
  722. if (@words >= 2) {
  723. my %hash = (
  724. oldnick => $words[0],
  725. nick => $words[1],
  726. words => $self->{stats}->{words}{$words[1]}
  727. );
  728. my $text = $self->_template_text('words2', %hash);
  729. _html("<br /><span class=\"small\">$text</span>");
  730. }
  731. _html("</td></tr>");
  732. } else {
  733. my $text = $self->_template_text('kick3');
  734. _html("<tr><td class=\"hicell\">$text</td></tr>");
  735. }
  736. }
  737. sub _mostkicks
  738. {
  739. # The person who kicked the most
  740. my $self = shift;
  741. my @kicked = sort { $self->{stats}->{kicked}{$b} <=> $self->{stats}->{kicked}{$a} }
  742. keys %{ $self->{stats}->{kicked} };
  743. @kicked = $self->_istoponly(@kicked);
  744. if (@kicked) {
  745. my %hash = (
  746. nick => $kicked[0],
  747. kicked => $self->{stats}->{kicked}{$kicked[0]}
  748. );
  749. my $text = $self->_template_text('kick1', %hash);
  750. _html("<tr><td class=\"hicell\">$text");
  751. if (@kicked >= 2) {
  752. my %hash = (
  753. oldnick => $kicked[0],
  754. nick => $kicked[1],
  755. kicked => $self->{stats}->{kicked}{$kicked[1]}
  756. );
  757. my $text = $self->_template_text('kick2', %hash);
  758. _html("<br /><span class=\"small\">$text</span>");
  759. }
  760. _html("</td></tr>");
  761. } else {
  762. my $text = $self->_template_text('kick3');
  763. _html("<tr><td class=\"hicell\">$text</td></tr>");
  764. }
  765. }
  766. sub _mostmonologues
  767. {
  768. # The person who had the most monologues (speaking to himself)
  769. my $self = shift;
  770. my @monologue = sort { $self->{stats}->{monologues}{$b} <=> $self->{stats}->{monologues}{$a} }
  771. keys %{ $self->{stats}->{monologues} };
  772. @monologue = $self->_istoponly(@monologue);
  773. if (@monologue) {
  774. my %hash = (
  775. nick => $monologue[0],
  776. monos => $self->{stats}->{monologues}{$monologue[0]}
  777. );
  778. my $text = $self->_template_text('mono1', %hash);
  779. _html("<tr><td class=\"hicell\">$text");
  780. if (@monologue >= 2) {
  781. my %hash = (
  782. nick => $monologue[1],
  783. monos => $self->{stats}->{monologues}{$monologue[1]}
  784. );
  785. my $text = $self->_template_text('mono2', %hash);
  786. _html("<br /><span class=\"small\">$text</span>");
  787. }
  788. _html("</td></tr>");
  789. }
  790. }
  791. sub _linelengths
  792. {
  793. # The person(s) who wrote the longest lines
  794. my $self = shift;
  795. my %len;
  796. foreach my $nick (sort keys %{ $self->{stats}->{lengths} }) {
  797. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  798. if ($self->{stats}->{lines}{$nick} > 100) {
  799. $len{$nick} = $self->{stats}->{lengths}{$nick} / $self->{stats}->{lines}{$nick};
  800. $len{$nick} =~ s/(\.\d)\d+/$1/;
  801. }
  802. }
  803. }
  804. my @len = sort { $len{$b} <=> $len{$a} } keys %len;
  805. my $all_lines = 0;
  806. my $totallength;
  807. foreach my $nick (keys %{ $self->{stats}->{lines} }) {
  808. $all_lines += $self->{stats}->{lines}{$nick};
  809. $totallength += $self->{stats}->{lengths}{$nick};
  810. }
  811. my $totalaverage;
  812. if ($all_lines > 0) {
  813. $totalaverage = $totallength / $all_lines;
  814. $totalaverage =~ s/(\.\d)\d+/$1/;
  815. }
  816. if (@len) {
  817. my %hash = (
  818. nick => $len[0],
  819. letters => $len{$len[0]}
  820. );
  821. my $text = $self->_template_text('long1', %hash);
  822. _html("<tr><td class=\"hicell\">$text<br />");
  823. if (@len >= 2) {
  824. %hash = (
  825. avg => $totalaverage
  826. );
  827. $text = $self->_template_text('long2', %hash);
  828. _html("<span class=\"small\">$text</span></td></tr>");
  829. }
  830. }
  831. # The person(s) who wrote the shortest lines
  832. if (@len) {
  833. my %hash = (
  834. nick => $len[$#len],
  835. letters => $len{$len[$#len]}
  836. );
  837. my $text = $self->_template_text('short1', %hash);
  838. _html("<tr><td class=\"hicell\">$text<br />");
  839. if (@len >= 2) {
  840. %hash = (
  841. nick => $len[$#len - 1],
  842. letters => $len{$len[$#len - 1]}
  843. );
  844. $text = $self->_template_text('short2', %hash);
  845. _html("<span class=\"small\">$text</span></td></tr>");
  846. }
  847. }
  848. }
  849. sub _mostfoul
  850. {
  851. my $self = shift;
  852. my %spercent;
  853. foreach my $nick (sort keys %{ $self->{stats}->{foul} }) {
  854. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  855. if ($self->{stats}->{lines}{$nick} > 15) {
  856. $spercent{$nick} = $self->{stats}->{foul}{$nick} / $self->{stats}->{words}{$nick} * 100;
  857. $spercent{$nick} =~ s/(\.\d)\d+/$1/;
  858. }
  859. }
  860. }
  861. my @foul = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent;
  862. if (@foul) {
  863. my %hash = (
  864. nick => $foul[0],
  865. per => $spercent{$foul[0]},
  866. line => htmlentities($self->_format_line($self->{stats}{foullines}{$foul[0]})),
  867. );
  868. my $text = $self->_template_text('foul1', %hash);
  869. if($self->{cfg}->{showfoulline}) {
  870. my $exttext = $self->_template_text('foultext', %hash);
  871. _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span><br />");
  872. } else {
  873. _html("<tr><td class=\"hicell\">$text");
  874. }
  875. if (@foul >= 2) {
  876. my %hash = (
  877. nick => $foul[1],
  878. per => $spercent{$foul[1]}
  879. );
  880. my $text = $self->_template_text('foul2', %hash);
  881. _html("<br /><span class=\"small\">$text</span>");
  882. }
  883. _html("</td></tr>");
  884. } else {
  885. my $text = $self->_template_text('foul3');
  886. _html("<tr><td class=\"hicell\">$text</td></tr>");
  887. }
  888. }
  889. sub _mostsad
  890. {
  891. my $self = shift;
  892. my %spercent;
  893. foreach my $nick (sort keys %{ $self->{stats}->{frowns} }) {
  894. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  895. if ($self->{stats}->{lines}{$nick} > 100) {
  896. $spercent{$nick} = $self->{stats}->{frowns}{$nick} / $self->{stats}->{lines}{$nick} * 100;
  897. $spercent{$nick} =~ s/(\.\d)\d+/$1/;
  898. }
  899. }
  900. }
  901. my @sadface = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent;
  902. if (@sadface) {
  903. my %hash = (
  904. nick => $sadface[0],
  905. per => $spercent{$sadface[0]}
  906. );
  907. my $text = $self->_template_text('sad1', %hash);
  908. _html("<tr><td class=\"hicell\">$text");
  909. if (@sadface >= 2) {
  910. my %hash = (
  911. nick => $sadface[1],
  912. per => $spercent{$sadface[1]}
  913. );
  914. my $text = $self->_template_text('sad2', %hash);
  915. _html("<br /><span class=\"small\">$text</span>");
  916. }
  917. _html("</td></tr>");
  918. } else {
  919. my $text = $self->_template_text('sad3');
  920. _html("<tr><td class=\"hicell\">$text</td></tr>");
  921. }
  922. }
  923. sub _mostop
  924. {
  925. my $self = shift;
  926. my @ops = sort { $self->{stats}->{gaveops}{$b} <=> $self->{stats}->{gaveops}{$a} }
  927. keys %{ $self->{stats}->{gaveops} };
  928. @ops = $self->_istoponly(@ops);
  929. my @deops = sort { $self->{stats}->{tookops}{$b} <=> $self->{stats}->{tookops}{$a} }
  930. keys %{ $self->{stats}->{tookops} };
  931. @deops = $self->_istoponly(@deops);
  932. if (@ops) {
  933. my %hash = (
  934. nick => $ops[0],
  935. ops => $self->{stats}->{gaveops}{$ops[0]}
  936. );
  937. my $text = $self->_template_text('mostop1', %hash);
  938. _html("<tr><td class=\"hicell\">$text");
  939. if (@ops >= 2) {
  940. my %hash = (
  941. nick => $ops[1],
  942. ops => $self->{stats}->{gaveops}{$ops[1]}
  943. );
  944. my $text = $self->_template_text('mostop2', %hash);
  945. _html("<br /><span class=\"small\">$text</span>");
  946. }
  947. _html("</td></tr>");
  948. } else {
  949. my $text = $self->_template_text('mostop3');
  950. _html("<tr><td class=\"hicell\">$text</td></tr>");
  951. }
  952. if (@deops) {
  953. my %hash = (
  954. nick => $deops[0],
  955. deops => $self->{stats}->{tookops}{$deops[0]}
  956. );
  957. my $text = $self->_template_text('mostdeop1', %hash);
  958. _html("<tr><td class=\"hicell\">$text");
  959. if (@deops >= 2) {
  960. my %hash = (
  961. nick => $deops[1],
  962. deops => $self->{stats}->{tookops}{$deops[1]}
  963. );
  964. my $text = $self->_template_text('mostdeop2', %hash);
  965. _html("<br /><span class=\"small\">$text</span>");
  966. }
  967. _html("</td></tr>");
  968. } else {
  969. my $text = $self->_template_text('mostdeop3');
  970. _html("<tr><td class=\"hicell\">$text</td></tr>");
  971. }
  972. }
  973. sub _mostvoice
  974. {
  975. my $self = shift;
  976. my @voice = sort { $self->{stats}->{gavevoice}{$b} <=> $self->{stats}->{gavevoice}{$a} }
  977. keys %{ $self->{stats}->{gavevoice} };
  978. @voice = $self->_istoponly(@voice);
  979. my @devoice = sort { $self->{stats}->{tookvoice}{$b} <=> $self->{stats}->{tookvoice}{$a} }
  980. keys %{ $self->{stats}->{tookvoice} };
  981. @devoice = $self->_istoponly(@devoice);
  982. if (@voice) {
  983. my %hash = (
  984. nick => $voice[0],
  985. voices => $self->{stats}->{gavevoice}{$voice[0]}
  986. );
  987. my $text = $self->_template_text('mostvoice1', %hash);
  988. _html("<tr><td class=\"hicell\">$text");
  989. if (@voice >= 2) {
  990. my %hash = (
  991. nick => $voice[1],
  992. voices => $self->{stats}->{gavevoice}{$voice[1]}
  993. );
  994. my $text = $self->_template_text('mostvoice2', %hash);
  995. _html("<br /><span class=\"small\">$text</span>");
  996. }
  997. _html("</td></tr>");
  998. } else {
  999. my $text = $self->_template_text('mostvoice3');
  1000. _html("<tr><td class=\"hicell\">$text</td></tr>");
  1001. }
  1002. if (@devoice) {
  1003. my %hash = (
  1004. nick => $devoice[0],
  1005. devoices => $self->{stats}->{tookvoice}{$devoice[0]}
  1006. );
  1007. my $text = $self->_template_text('mostdevoice1', %hash);
  1008. _html("<tr><td class=\"hicell\">$text");
  1009. if (@devoice >= 2) {
  1010. my %hash = (
  1011. nick => $devoice[1],
  1012. devoices => $self->{stats}->{tookvoice}{$devoice[1]}
  1013. );
  1014. my $text = $self->_template_text('mostdevoice2', %hash);
  1015. _html("<br /><span class=\"small\">$text</span>");
  1016. }
  1017. _html("</td></tr>");
  1018. } else {
  1019. my $text = $self->_template_text('mostdevoice3');
  1020. _html("<tr><td class=\"hicell\">$text</td></tr>");
  1021. }
  1022. }
  1023. sub _mosthalfop
  1024. {
  1025. my $self = shift;
  1026. my @halfops = sort { $self->{stats}->{gavehalfops}{$b} <=> $self->{stats}->{gavehalfops}{$a} }
  1027. keys %{ $self->{stats}->{gavehalfops} };
  1028. @halfops = $self->_istoponly(@halfops);
  1029. my @dehalfops = sort { $self->{stats}->{tookhalfops}{$b} <=> $self->{stats}->{tookhalfops}{$a} }
  1030. keys %{ $self->{stats}->{tookhalfops} };
  1031. @dehalfops = $self->_istoponly(@dehalfops);
  1032. if (@halfops) {
  1033. my %hash = (
  1034. nick => $halfops[0],
  1035. halfops => $self->{stats}->{gavehalfops}{$halfops[0]}
  1036. );
  1037. my $text = $self->_template_text('mosthalfop1', %hash);
  1038. _html("<tr><td class=\"hicell\">$text");
  1039. if (@halfops >= 2) {
  1040. my %hash = (
  1041. nick => $halfops[1],
  1042. halfops => $self->{stats}->{gavehalfops}{$halfops[1]}
  1043. );
  1044. my $text = $self->_template_text('mosthalfop2', %hash);
  1045. _html("<br /><span class=\"small\">$text</span>");
  1046. }
  1047. _html("</td></tr>");
  1048. } else {
  1049. my $text = $self->_template_text('mosthalfop3');
  1050. _html("<tr><td class=\"hicell\">$text</td></tr>");
  1051. }
  1052. if (@dehalfops) {
  1053. my %hash = (
  1054. nick => $dehalfops[0],
  1055. dehalfops => $self->{stats}->{tookhalfops}{$dehalfops[0]}
  1056. );
  1057. my $text = $self->_template_text('mostdehalfop1', %hash);
  1058. _html("<tr><td class=\"hicell\">$text");
  1059. if (@dehalfops >= 2) {
  1060. my %hash = (
  1061. nick => $dehalfops[1],
  1062. dehalfops => $self->{stats}->{tookhalfops}{$dehalfops[1]}
  1063. );
  1064. my $text = $self->_template_text('mostdehalfop2', %hash);
  1065. _html("<br /><span class=\"small\">$text</span>");
  1066. }
  1067. _html("</td></tr>");
  1068. } else {
  1069. my $text = $self->_template_text('mostdehalfop3');
  1070. _html("<tr><td class=\"hicell\">$text</td></tr>");
  1071. }
  1072. }
  1073. sub _mostactions
  1074. {
  1075. # The person who did the most /me's
  1076. my $self = shift;
  1077. my @actions = sort { $self->{stats}->{actions}{$b} <=> $self->{stats}->{actions}{$a} }
  1078. keys %{ $self->{stats}->{actions} };
  1079. @actions = $self->_istoponly(@actions);
  1080. if (@actions) {
  1081. my %linehash =
  1082. my %hash = (
  1083. nick => $actions[0],
  1084. actions => $self->{stats}->{actions}{$actions[0]},
  1085. line => htmlentities($self->_format_line($self->{stats}->{actionlines}{$actions[0]}))
  1086. );
  1087. my $text = $self->_template_text('action1', %hash);
  1088. if($self->{cfg}->{showactionline}) {
  1089. my $exttext = $self->_template_text('actiontext', %hash);
  1090. _html("<tr><td class=\"hicell\">$text<br /><span class=\"small\">$exttext</span><br />");
  1091. } else {
  1092. _html("<tr><td class=\"hicell\">$text");
  1093. }
  1094. if (@actions >= 2) {
  1095. my %hash = (
  1096. nick => $actions[1],
  1097. actions => $self->{stats}->{actions}{$actions[1]}
  1098. );
  1099. my $text = $self->_template_text('action2', %hash);
  1100. _html("<br /><span class=\"small\">$text</span>");
  1101. }
  1102. _html("</td></tr>");
  1103. } else {
  1104. my $text = $self->_template_text('action3');
  1105. _html("<tr><td class=\"hicell\">$text</td></tr>");
  1106. }
  1107. }
  1108. sub _mostsmiles
  1109. {
  1110. # The person(s) who smiled the most :-)
  1111. my $self = shift;
  1112. my %spercent;
  1113. foreach my $nick (sort keys %{ $self->{stats}->{smiles} }) {
  1114. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  1115. if ($self->{stats}->{lines}{$nick} > 100) {
  1116. $spercent{$nick} = $self->{stats}->{smiles}{$nick} / $self->{stats}->{lines}{$nick} * 100;
  1117. $spercent{$nick} =~ s/(\.\d)\d+/$1/;
  1118. }
  1119. }
  1120. }
  1121. my @smiles = sort { $spercent{$b} <=> $spercent{$a} } keys %spercent;
  1122. if (@smiles) {
  1123. my %hash = (
  1124. nick => $smiles[0],
  1125. per => $spercent{$smiles[0]}
  1126. );
  1127. my $text = $self->_template_text('smiles1', %hash);
  1128. _html("<tr><td class=\"hicell\">$text");
  1129. if (@smiles >= 2) {
  1130. my %hash = (
  1131. nick => $smiles[1],
  1132. per => $spercent{$smiles[1]}
  1133. );
  1134. my $text = $self->_template_text('smiles2', %hash);
  1135. _html("<br /><span class=\"small\">$text</span>");
  1136. }
  1137. _html("</td></tr>");
  1138. } else {
  1139. my $text = $self->_template_text('smiles3');
  1140. _html("<tr><td class=\"hicell\">$text</td></tr>");
  1141. }
  1142. }
  1143. sub _lasttopics
  1144. {
  1145. my $self = shift;
  1146. if ($self->{stats}->{topics}) {
  1147. my %topic_seen;
  1148. my %hash = (
  1149. total => scalar @{ $self->{stats}->{topics} }
  1150. );
  1151. my $ltopic = $#{ $self->{stats}->{topics} };
  1152. my $tlimit = 0;
  1153. $self->{cfg}->{topichistory} -= 1;
  1154. if ($ltopic > $self->{cfg}->{topichistory}) {
  1155. $tlimit = $ltopic - $self->{cfg}->{topichistory};
  1156. }
  1157. for (my $i = $ltopic; $i >= $tlimit; $i--) {
  1158. my $topic = htmlentities($self->{stats}->{topics}[$i]{topic});
  1159. # This code makes sure that we don't see the same topic twice
  1160. next if ($topic_seen{$topic});
  1161. $topic_seen{$topic} = 1;
  1162. $topic = $self->_replace_links($topic);
  1163. # Strip off the quotes (')
  1164. $topic =~ s/^\'(.*)\'$/$1/;
  1165. my $nick = $self->{stats}->{topics}[$i]{nick};
  1166. my $hour = $self->{stats}->{topics}[$i]{hour};
  1167. my $min = $self->{stats}->{topics}[$i]{min};
  1168. $hash{nick} = $nick;
  1169. $hash{time} = "$hour:$min";
  1170. _html("<tr><td class=\"hicell\"><i>$topic</i></td>");
  1171. _html("<td class=\"hicell\"><b>" . $self->_template_text('bylinetopic', %hash) ."</b></td></tr>");
  1172. }
  1173. _html("<tr><td align=\"center\" colspan=\"2\" class=\"asmall\">" . $self->_template_text('totaltopic', %hash) . "</td></tr>");
  1174. } else {
  1175. _html("<tr><td class=\"hicell\">" . $self->_template_text('notopic') ."</td></tr>");
  1176. }
  1177. }
  1178. sub _template_text
  1179. {
  1180. # This function is for the homemade template system. It receives a name
  1181. # of a template and a hash with the fields in the template to update to
  1182. # its corresponding value
  1183. my $self = shift;
  1184. my $template = shift;
  1185. my %hash = @_;
  1186. my $text;
  1187. unless ($text = $self->{tmps}->{lc($self->{cfg}->{lang})}{$template}) {
  1188. # Fall back to English if the language template doesn't exist
  1189. if ($text = $self->{tmps}->{en}{$template}) {
  1190. print "Note: No translation in '$self->{cfg}->{lang}' for '$template' - falling back to English..\n"
  1191. unless ($self->{cfg}->{silent});
  1192. } else {
  1193. die("No such template '$template' in language file.\n");
  1194. }
  1195. }
  1196. $hash{channel} = $self->{cfg}->{channel};
  1197. foreach my $key (sort keys %hash) {
  1198. $text =~ s/\[:$key\]/$hash{$key}/;
  1199. $text =~ s/ü/&uuml;/go;
  1200. $text =~ s/ö/&ouml;/go;
  1201. $text =~ s/ä/&auml;/go;
  1202. $text =~ s/ß/&szlig;/go;
  1203. $text =~ s/å/&aring;/go;
  1204. $text =~ s/æ/&aelig;/go;
  1205. $text =~ s/ø/&oslash;/go;
  1206. $text =~ s/Å/&Aring;/go;
  1207. $text =~ s/Æ/&AElig;/go;
  1208. $text =~ s/Ø/&Oslash;/go;
  1209. }
  1210. if ($text =~ /\[:[^:]*?:[^:]*?:[^:]*?:\]/o) {
  1211. $text =~ s/\[:([^:]*?):([^:]*?):([^:]*?):\]/$self->_get_subst($1,$2,$3,\%hash)/geo;
  1212. }
  1213. if ($text =~ /\[:[^:]*?:[^:]*?:]/o) {
  1214. $text =~ s/\[:([^:]*?):([^:]*?):]/$self->_get_subst($1,$2,undef,\%hash)/geo;
  1215. }
  1216. return $text;
  1217. }
  1218. sub _format_line
  1219. {
  1220. # This function formats a action/normal line to be more readable
  1221. my ($self,$line) = @_;
  1222. my $hashref;
  1223. if ($hashref = $self->{cfg}->{analyzer}->{parser}->normalline($line)) {
  1224. return '<' . $hashref->{nick} . '> ' . $hashref->{saying};
  1225. } elsif ($hashref = $self->{cfg}->{analyzer}->{parser}->actionline($line)) {
  1226. return '* ' . $hashref->{nick} . ' ' . $hashref->{saying};
  1227. } elsif ($hashref = $self->{cfg}->{analyzer}->{parser}->thirdline($line)) {
  1228. if (defined($hashref->{kicker})) {
  1229. $line = '*** ' . $hashref->{nick} . ' was kicked by ' . $hashref->{kicker};
  1230. $line .= ' (' . $hashref->{kicktext} . ')'
  1231. if (defined($hashref->{kicktext}));
  1232. } elsif (defined($hashref->{newtopic})) {
  1233. $line = '*** ' . $hashref->{nick} . ' changes topic to \'' . $hashref->{newtopic} . '\'';
  1234. } elsif (defined($hashref->{newmode})) {
  1235. $line = '*** ' . $hashref->{nick} . ' sets mode ' . $hashref->{newmode};
  1236. $line .= ' ' . $hashref->{modechanges}
  1237. if (defined($hashref->{kicktext}));
  1238. } elsif (defined($hashref->{newjoin})) {
  1239. $line = '*** Joins: ' . $hashref->{nick};
  1240. } elsif (defined($hashref->{newnick})) {
  1241. $line = '*** ' . $hashref->{nick} . ' is now known as ' . $hashref->{newnick};
  1242. }
  1243. return $line;
  1244. } else {
  1245. return $line;
  1246. }
  1247. }
  1248. sub _get_subst
  1249. {
  1250. # This function looks at the user definition and see if there is sex
  1251. # defined. If yes, return the appropriate value. If no, just return the
  1252. # default he/she value.
  1253. my $self = shift;
  1254. my ($m,$f,$d,$hash) = @_;
  1255. if ($hash->{nick} && $self->{users}->{sex}{$hash->{nick}}) {
  1256. if ($self->{users}->{sex}{$hash->{nick}} eq 'm') {
  1257. return $m;
  1258. } elsif ($self->{users}->{sex}{$hash->{nick}} eq 'f') {
  1259. return $f;
  1260. }
  1261. }
  1262. return defined($d) ? $d : "$m/$f";
  1263. }
  1264. sub _mostusedword
  1265. {
  1266. # Word usage statistics
  1267. my $self = shift;
  1268. my %usages;
  1269. foreach my $word (keys %{ $self->{stats}->{wordcounts} }) {
  1270. # Skip people's nicks.
  1271. next if is_nick($word);
  1272. next if (length($word) < $self->{cfg}->{wordlength});
  1273. $usages{$word} = $self->{stats}->{wordcounts}{$word};
  1274. }
  1275. my @popular = sort { $usages{$b} <=> $usages{$a} } keys %usages;
  1276. if (@popular) {
  1277. $self->_headline($self->_template_text('mostwordstopic'));
  1278. _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>");
  1279. _html("<td>&nbsp;</td><td class=\"tdtop\"><b>" . $self->_template_text('word') . "</b></td>");
  1280. _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>");
  1281. _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>");
  1282. my $count = 0;
  1283. for(my $i = 0; $count < $self->{cfg}->{wordhistory}; $i++) {
  1284. last unless $i < $#popular;
  1285. # Skip nicks. It's far more efficient to do this here than when
  1286. # @popular is created.
  1287. next if is_ignored($popular[$i]);
  1288. next if is_nick($popular[$i]);
  1289. my $a = $count + 1;
  1290. my $popular = htmlentities($popular[$i]);
  1291. my $wordcount = $self->{stats}->{wordcounts}{$popular[$i]};
  1292. my $lastused = htmlentities($self->{stats}->{wordnicks}{$popular[$i]});
  1293. my $class;
  1294. if ($a == 1) {
  1295. $class = 'hirankc';
  1296. } else {
  1297. $class = 'rankc';
  1298. }
  1299. _html("<tr><td class=\"$class\">$a</td>");
  1300. _html("<td class=\"hicell\">$popular</td>");
  1301. _html("<td class=\"hicell\">$wordcount</td>");
  1302. _html("<td class=\"hicell\">$lastused</td>");
  1303. _html("</tr>");
  1304. $count++;
  1305. }
  1306. _html("</table>");
  1307. }
  1308. }
  1309. sub _mostwordsperline
  1310. {
  1311. # The person who got the most words per line
  1312. my $self = shift;
  1313. my %wpl = ();
  1314. my $numlines = 0;
  1315. my ($avg, $numwords);
  1316. foreach my $nick (keys %{ $self->{stats}->{words} }) {
  1317. if ($self->{topactive}{$nick} || !$self->{cfg}->{showonlytop}) {
  1318. $wpl{$nick} = sprintf("%.2f", $self->{stats}->{words}{$nick}/$self->{stats}->{lines}{$nick});
  1319. $numlines += $self->{stats}->{lines}{$nick};
  1320. $numwords += $self->{stats}->{words}{$nick};
  1321. }
  1322. }
  1323. if ($numlines > 0) {
  1324. $avg = sprintf("%.2f", $numwords/$numlines);
  1325. }
  1326. my @wpl = sort { $wpl{$b} <=> $wpl{$a} } keys %wpl;
  1327. if (@wpl) {
  1328. my %hash = (
  1329. nick => $wpl[0],
  1330. wpl => $wpl{$wpl[0]}
  1331. );
  1332. my $text = $self->_template_text('wpl1', %hash);
  1333. _html("<tr><td class=\"hicell\">$text");
  1334. $hash{avg} = $avg;
  1335. $text = $self->_template_text('wpl2', %hash);
  1336. _html("<br /><span class=\"small\">$text</span>");
  1337. _html("</td></tr>");
  1338. }
  1339. }
  1340. sub _mostreferencednicks
  1341. {
  1342. # List showing the most referenced nicks
  1343. my $self = shift;
  1344. my %usages;
  1345. foreach my $word (sort keys %{ $self->{stats}->{wordcounts} }) {
  1346. next if !exists $self->{stats}->{lines}{$word};
  1347. next if is_ignored($word);
  1348. $usages{$word} = $self->{stats}->{wordcounts}{$word};
  1349. }
  1350. my @popular = sort { $usages{$b} <=> $usages{$a} } keys %usages;
  1351. if (@popular) {
  1352. $self->_headline($self->_template_text('referencetopic'));
  1353. _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>");
  1354. _html("<td>&nbsp;</td><td class=\"tdtop\"><b>" . $self->_template_text('nick') . "</b></td>");
  1355. _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>");
  1356. _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>");
  1357. for(my $i = 0; $i < $self->{cfg}->{nickhistory}; $i++) {
  1358. last unless $i < $#popular;
  1359. my $a = $i + 1;
  1360. my $popular = $popular[$i];
  1361. my $wordcount = $self->{stats}->{wordcounts}{$popular[$i]};
  1362. my $lastused = $self->{stats}->{wordnicks}{$popular[$i]};
  1363. my $class;
  1364. if ($a == 1) {
  1365. $class = 'hirankc';
  1366. } else {
  1367. $class = 'rankc';
  1368. }
  1369. _html("<tr><td class=\"$class\">$a</td>");
  1370. _html("<td class=\"hicell\">$popular</td>");
  1371. _html("<td class=\"hicell\">$wordcount</td>");
  1372. _html("<td class=\"hicell\">$lastused</td>");
  1373. _html("</tr>");
  1374. }
  1375. _html("</table>");
  1376. }
  1377. }
  1378. sub _mosturls
  1379. {
  1380. # List showing the most referenced URLs
  1381. my $self = shift;
  1382. my @sorturls = sort { $self->{stats}->{urlcounts}{$b} <=> $self->{stats}->{urlcounts}{$a} }
  1383. keys %{ $self->{stats}->{urlcounts} };
  1384. if (@sorturls) {
  1385. $self->_headline($self->_template_text('urlstopic'));
  1386. _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>");
  1387. _html("<td>&nbsp;</td><td class=\"tdtop\"><b>" . $self->_template_text('url') . "</b></td>");
  1388. _html("<td class=\"tdtop\"><b>" . $self->_template_text('numberuses') . "</b></td>");
  1389. _html("<td class=\"tdtop\"><b>" . $self->_template_text('lastused') . "</b></td></tr>");
  1390. for(my $i = 0; $i < $self->{cfg}->{urlhistory}; $i++) {
  1391. last unless $i < @sorturls;
  1392. my $a = $i + 1;
  1393. my $sorturl = $sorturls[$i];
  1394. my $urlcount = $self->{stats}->{urlcounts}{$sorturls[$i]};
  1395. my $lastused = $self->{stats}->{urlnicks}{$sorturls[$i]};
  1396. if (length($sorturl) > 60) {
  1397. $sorturl = substr($sorturl, 0, 60);
  1398. }
  1399. my $class;
  1400. if ($a == 1) {
  1401. $class = 'hirankc';
  1402. } else {
  1403. $class = 'rankc';
  1404. }
  1405. _html("<tr><td class=\"$class\">$a</td>");
  1406. _html("<td class=\"hicell\"><a href=\"$sorturls[$i]\">$sorturl</a></td>");
  1407. _html("<td class=\"hicell\">$urlcount</td>");
  1408. _html("<td class=\"hicell\">$lastused</td>");
  1409. _html("</tr>");
  1410. }
  1411. _html("</table>");
  1412. }
  1413. }
  1414. sub _legend
  1415. {
  1416. # A legend showing the timebars and their associated time.
  1417. my $self = shift;
  1418. _html("<table align=\"center\" border=\"0\" width=\"520\"><tr>");
  1419. _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>");
  1420. _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>");
  1421. _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>");
  1422. _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>");
  1423. _html("</tr></table>\n");
  1424. }
  1425. sub _replace_links
  1426. {
  1427. # Sub to replace urls and e-mail addys to links
  1428. my $self = shift;
  1429. my $str = shift;
  1430. my $nick = shift;
  1431. # Regular expressions are taken from match_urls() and match_email() in
  1432. # Common.pm
  1433. my $texturl = $self->_template_text("newwindow");
  1434. my $textmail = $self->_template_text("mailto");
  1435. if ($nick) {
  1436. $str =~ s/(http|https|ftp|telnet|news)(:\/\/[-a-zA-Z0-9_\/~]+\.[-a-zA-Z0-9.,_~=:&amp;@%?#\/+]+)/<a href="$1$2" target="_blank" title="$texturl $1$2">$nick<\/a>/g;
  1437. $str =~ s/([-a-zA-Z0-9._]+@[-a-zA-Z0-9_]+\.[-a-zA-Z0-9._]+)/<a href="mailto:$1" title="$textmail $nick">$nick<\/a>/g;
  1438. } else {
  1439. $str =~ s/(http|https|ftp|telnet|news)(:\/\/[-a-zA-Z0-9_\/~]+\.[-a-zA-Z0-9.,_~=:&amp;@%?#\/+]+)/<a href="$1$2" target="_blank" title="$texturl $1$2">$1$2<\/a>/g;
  1440. $str =~ s/([-a-zA-Z0-9._]+@[-a-zA-Z0-9_]+\.[-a-zA-Z0-9._]+)/<a href="mailto:$1" title="$textmail $1">$1<\/a>/g;
  1441. }
  1442. return $str;
  1443. }
  1444. sub _user_linetimes
  1445. {
  1446. my $self = shift;
  1447. my $nick = shift;
  1448. my $top = shift;
  1449. my $bar = "";
  1450. my $len = ($self->{stats}->{lines}{$nick} / $self->{stats}->{lines}{$top}) * 100;
  1451. for (my $i = 0; $i <= 3; $i++) {
  1452. next if not defined $self->{stats}->{line_times}{$nick}[$i];
  1453. my $w = int(($self->{stats}->{line_times}{$nick}[$i] / $self->{stats}->{lines}{$nick}) * $len);
  1454. if ($w) {
  1455. my $pic = 'pic_h_'.(6*$i);
  1456. $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"\" />";
  1457. }
  1458. }
  1459. return "$bar&nbsp;$self->{stats}->{lines}{$nick}";
  1460. }
  1461. sub _user_wordtimes
  1462. {
  1463. my $self = shift;
  1464. my $nick = shift;
  1465. my $top = shift;
  1466. my $bar = "";
  1467. my $len = ($self->{stats}->{words}{$nick} / $self->{stats}->{words}{$top}) * 100;
  1468. for (my $i = 0; $i <= 3; $i++) {
  1469. next if not defined $self->{stats}->{word_times}{$nick}[$i];
  1470. my $w = int(($self->{stats}->{word_times}{$nick}[$i] / $self->{stats}->{words}{$nick}) * $len);
  1471. if ($w) {
  1472. my $pic = 'pic_h_'.(6*$i);
  1473. $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"\" />";
  1474. }
  1475. }
  1476. return "$bar&nbsp;$self->{stats}->{words}{$nick}";
  1477. }
  1478. sub _user_times
  1479. {
  1480. my $self = shift;
  1481. my ($nick) = @_;
  1482. my $bar = "";
  1483. my $itemstat = ($self->{cfg}->{sortbywords} ? 'words' : 'lines');
  1484. my $timestat = ($self->{cfg}->{sortbywords} ? 'word_times' : 'line_times');
  1485. for (my $i = 0; $i <= 3; $i++) {
  1486. next if not defined $self->{stats}->{$timestat}{$nick}[$i];
  1487. my $w = int(($self->{stats}->{$timestat}{$nick}[$i] / $self->{stats}->{$itemstat}{$nick}) * 40);
  1488. if ($w) {
  1489. my $pic = 'pic_h_'.(6*$i);
  1490. $bar .= "<img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" alt=\"\" />";
  1491. }
  1492. }
  1493. return $bar;
  1494. }
  1495. sub _mostnicks
  1496. {
  1497. # List showing the user with most used nicks
  1498. my $self = shift;
  1499. my @sortnicks = sort { keys %{ $self->{stats}->{nicks}->{$b} } <=> keys %{ $self->{stats}->{nicks}->{$a} } }
  1500. keys %{ $self->{stats}->{nicks} };
  1501. if (keys %{ $self->{stats}->{nicks}->{$sortnicks[0]} } > 1) {
  1502. $self->_headline($self->_template_text('mostnickstopic'));
  1503. my $names1 = $self->_template_text('names1');
  1504. my $names2 = $self->_template_text('names2');
  1505. my $nick_txt = $self->_template_text('nick');
  1506. my $names_txt = $self->_template_text('names');
  1507. _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>");
  1508. _html("<td>&nbsp;</td><td class=\"tdtop\"><b>$nick_txt</b></td>");
  1509. _html("<td class=\"tdtop\"><b>$names_txt</b></td></tr>");
  1510. for(my $i = 0; $i < $self->{cfg}->{mostnickshistory}; $i++) {
  1511. next if is_ignored($sortnicks[$i]);
  1512. last unless $i < @sortnicks;
  1513. my $nickcount = keys %{ $self->{stats}->{nicks}->{$sortnicks[$i]} };
  1514. my $nickused = join(", ", values %{ $self->{stats}->{nicks}->{$sortnicks[$i]} });
  1515. next unless ($nickcount > 1);
  1516. my $a = $i + 1;
  1517. my $class = $a == 1 ? 'hirankc' : 'rankc';
  1518. my $n = $nickcount > 1 ? $names1 : $names2;
  1519. _html("<tr><td class=\"$class\">$a</td>");
  1520. _html("<td class=\"hicell10\">$sortnicks[$i]<br />($nickcount $n)</td>");
  1521. _html("<td class=\"hicell10\" valign='top'>$nickused</td>");
  1522. _html("</tr>");
  1523. }
  1524. _html("</table>");
  1525. }
  1526. }
  1527. sub _mostactivebyhour
  1528. {
  1529. # Charts for most active nicks by hour (0-5, 6-11, 12-17, 18-23)
  1530. my $self = shift;
  1531. my $sortnicks;
  1532. my $lastline=-1;
  1533. my $maxlines=0;
  1534. foreach my $period (0,1,2,3) {
  1535. my @sortnicks =
  1536. sort
  1537. {
  1538. (defined $self->{stats}->{line_times}{$b}[$period]?$self->{stats}->{line_times}{$b}[$period]:0)
  1539. <=>
  1540. (defined $self->{stats}->{line_times}{$a}[$period]?$self->{stats}->{line_times}{$a}[$period]:0)
  1541. }
  1542. keys %{ $self->{stats}->{line_times} } ;
  1543. for(my $i = 0; $i < $self->{cfg}->{activenicksbyhour}; $i++) {
  1544. next if ! $sortnicks[$i];
  1545. next if is_ignored($sortnicks[$i]);
  1546. last unless $i < @sortnicks;
  1547. my $nick=$sortnicks[$i];
  1548. my $count=$self->{stats}->{line_times}{$nick}[$period] || 0;
  1549. last unless $nick;
  1550. last unless $count;
  1551. $sortnicks->[$period][$i]=$nick;
  1552. if ($lastline<$i) {
  1553. $lastline=$i;
  1554. }
  1555. if ($maxlines<$count) {
  1556. $maxlines=$count;
  1557. }
  1558. }
  1559. }
  1560. if ($lastline>=0) {
  1561. $self->_headline($self->_template_text('activenickbyhourtopic'));
  1562. _html("<table border=\"0\" width=\"$self->{cfg}->{tablewidth}\"><tr>");
  1563. _html("<td>&nbsp;</td>");
  1564. _html("<td class=\"tdtop\"><b>0-5</b></td>");
  1565. _html("<td class=\"tdtop\"><b>6-11</b></td>");
  1566. _html("<td class=\"tdtop\"><b>12-17</b></td>");
  1567. _html("<td class=\"tdtop\"><b>18-23</b></td>");
  1568. _html("</tr>");
  1569. for(my $i = 0; $i <= $lastline; $i++) {
  1570. my $a = $i + 1;
  1571. my $class = $a == 1 ? 'hirankc' : 'rankc';
  1572. _html("<tr><td class=\"$class\">$a</td>");
  1573. foreach my $period (0,1,2,3) {
  1574. my $nick=$sortnicks->[$period][$i];
  1575. if ($nick) {
  1576. my $count=$self->{stats}->{line_times}{$nick}[$period];
  1577. if ($count) {
  1578. _html("<td class=\"hicell\">".$nick." - ".$count);
  1579. if ($self->{cfg}->{showmostactivebyhourgraph}) {
  1580. my $pic = 'pic_h_'.(6*$period);
  1581. my $w = int(($count / $maxlines) * 100);
  1582. _html("<br /><img src=\"$self->{cfg}->{piclocation}/$self->{cfg}->{$pic}\" border=\"0\" width=\"$w\" height=\"15\" align=\"middle\" alt=\"\" />");
  1583. }
  1584. _html("</td>");
  1585. } else {
  1586. _html("<td class=\"hicell\">&nbsp;</td>");
  1587. }
  1588. } else {
  1589. _html("<td class=\"hicell\">&nbsp;</td>");
  1590. }
  1591. }
  1592. _html("</tr>");
  1593. }
  1594. _html("</table>");
  1595. }
  1596. }
  1597. sub _topactive {
  1598. my $self = shift;
  1599. my @top_active;
  1600. my $top_nicks;
  1601. if ($self->{cfg}->{sortbywords}) {
  1602. @top_active = sort { $self->{stats}->{words}{$b} <=> $self->{stats}->{words}{$a} }
  1603. keys %{ $self->{stats}->{words} };
  1604. $top_nicks = scalar keys %{ $self->{stats}->{words} };
  1605. } else {
  1606. @top_active = sort { $self->{stats}->{lines}{$b} <=> $self->{stats}->{lines}{$a} }
  1607. keys %{ $self->{stats}->{lines} };
  1608. $top_nicks = scalar keys %{ $self->{stats}->{lines} };
  1609. }
  1610. if ($self->{cfg}->{activenicks} > $top_nicks) {
  1611. $self->{cfg}->{activenicks} = $top_nicks;
  1612. }
  1613. if (($self->{cfg}->{activenicks}+$self->{cfg}->{activenicks2}) > $top_nicks) {
  1614. $self->{cfg}->{activenicks2} = $top_nicks-$self->{cfg}->{activenicks};
  1615. }
  1616. (@top_active) = @top_active[0..($self->{cfg}->{activenicks}+$self->{cfg}->{activenicks2}-1)];
  1617. foreach (@top_active) {
  1618. $self->{topactive}{$_} = 1;
  1619. }
  1620. }
  1621. sub _istoponly {
  1622. my $self = shift;
  1623. my (@nicks_tmp) = @_;
  1624. my @nicks;
  1625. my $cnt=0;
  1626. if ($self->{cfg}->{showonlytop}) {
  1627. foreach my $nick (@nicks_tmp) {
  1628. if ($self->{topactive}{$nick}) {
  1629. push(@nicks, $nick);
  1630. }
  1631. }
  1632. return(@nicks);
  1633. } else {
  1634. return(@nicks_tmp);
  1635. }
  1636. }
  1637. 1;
  1638. __END__
  1639. =head1 NAME
  1640. Pisg::HTMLGenerator - class to create a static HTML page out of data parsed
  1641. =head1 DESCRIPTION
  1642. C<Pisg::HTMLGenerator> uses the hash returned by Pisg::Parser::Logfile and turns it into a static HTML page.
  1643. =head1 SYNOPSIS
  1644. use Pisg::HTMLGenerator;
  1645. $generator = new Pisg::HTMLGenerator(
  1646. cfg => $cfg,
  1647. stats => $stats,
  1648. users => $users,
  1649. tmps => $tmps
  1650. );
  1651. =head1 CONSTRUCTOR
  1652. =over 4
  1653. =item new ( [ OPTIONS ] )
  1654. This is the constructor for a new Pisg::HTMLGenerator object. C<OPTIONS> are passed in a hash like fashion using key and value pairs.
  1655. Possible options are:
  1656. B<cfg> - hashref containing configuration variables, created by the Pisg module.
  1657. B<stats> - reference to the hash returned by Pisg::Parser::Logfile containing all stats.
  1658. B<users> - reference to a hash containg user information
  1659. B<tmps> - reference to a hash containing the language templates.
  1660. =back
  1661. =head1 AUTHOR
  1662. Morten Brix Pedersen <morten@wtf.dk>
  1663. =head1 COPYRIGHT
  1664. Copyright (C) 2001-2002 Morten Brix Pedersen. All rights reserved.
  1665. This program is free software; you can redistribute it and/or modify it
  1666. under the terms of the GPL, license is included with the distribution of
  1667. this file.
  1668. =cut