1 /* Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme [nickfile] > /path/to/file.html */
11 #define MAXNICKLENGTH 50
12 #define MAXLINELENGTH 2000
13 #define MAXQUOTELENGTH 100
15 #define NBUSERSTIME 10
19 #define MINWORDLENGTH 5
23 #define URL "http://royale.zerezo.com/programmation/irssistats/"
38 #define D_MONOLOGUE 12
40 char *counters[NBCOUNTERS]={"C_SMILE","C_FROWN","C_EXCLAM","C_QUESTION","C_ME","C_TOPIC","C_MODE","C_KICK","C_KICKED","C_URL","C_JOIN","C_NICK","C_MONOLOGUE"};
45 char *keys[NBLANGUAGES][NBKEYS+1][2]= /* first key used for language name and abbreviation */
47 { /* English language */
49 { "HEADER", "Statistics for #%s by %s" },
50 { "LEGEND", "Legend" },
51 { "LASTDAYS", "Lastdays statistics" },
52 { "TOPHOURS", "Hourly statistics" },
53 { "TOPUSERS", "Most active people" },
54 { "OTHERS", "There are %d left not ranked..." },
55 { "NBLINES", "lines" },
57 { "AVGLETTERS", "letters/lines" },
59 { "QUOTE", "random message" },
60 { "TOPUSERSTIME", "Most active people by time of day" },
61 { "RANDTOPICS", "Some topics" },
62 { "CHANGEDBY", "changed by" },
63 { "NEWTOPIC", "new topic" },
64 { "RANDURLS", "Some URLs" },
65 { "POSTEDBY", "posted by" },
66 { "POSTEDURL", "URL" },
67 { "TOPWORDS", "Most used words" },
69 { "OCCURRENCES", "occurrences" },
70 { "BIGNUMBERS", "Some big numbers..." },
71 { "NUMBERS", "numbers" },
72 { "TIME", "%d lines parsed in %d seconds" },
73 { "FOOTER", "Statistics generated by" },
74 { "C_SMILE", "is often happy :)" },
75 { "C_FROWN", "is often sad :(" },
76 { "C_EXCLAM", "yells a lot !" },
77 { "C_QUESTION", "asks a lot of questions ?" },
78 { "C_ME", "likes /me command" },
79 { "C_TOPIC", "often changes the topic" },
80 { "C_MODE", "often changes the modes" },
81 { "C_KICK", "likes to /kick" },
82 { "C_KICKED", "is often kicked" },
83 { "C_URL", "posts many URLs" },
84 { "C_JOIN", "doesn't know wether to stay or quit" },
85 { "C_NICK", "often changes his nick" },
86 { "C_MONOLOGUE", "speaks a lot of monologues" }
88 { /* French language */
90 { "HEADER", "Statistiques de #%s par %s" },
91 { "LEGEND", "Légende" },
92 { "LASTDAYS", "Statistiques des derniers jours" },
93 { "TOPHOURS", "Statistiques horaires" },
94 { "TOPUSERS", "Personnes les plus actives" },
95 { "OTHERS", "Il reste %d personnes non classées..." },
96 { "NBLINES", "lignes" },
98 { "AVGLETTERS", "lettres/lignes" },
99 { "HOURS", "heures" },
100 { "QUOTE", "message aléatoire" },
101 { "TOPUSERSTIME", "Personnes les plus actives par période de la journée" },
102 { "RANDTOPICS", "Quelques topics" },
103 { "CHANGEDBY", "changé par" },
104 { "NEWTOPIC", "nouveau topic" },
105 { "RANDURLS", "Quelques URLs" },
106 { "POSTEDBY", "postée par" },
107 { "POSTEDURL", "URL" },
108 { "TOPWORDS", "Mots les plus utilisés" },
110 { "OCCURRENCES", "occurrences" },
111 { "BIGNUMBERS", "Quelques grands nombres..." },
112 { "NUMBERS", "nombres" },
113 { "TIME", "%d lignes traitées en %d secondes" },
114 { "FOOTER", "Statistiques générées par" },
115 { "C_SMILE", "est souvent heureux :)" },
116 { "C_FROWN", "est souvent triste :(" },
117 { "C_EXCLAM", "hurle beaucoup !" },
118 { "C_QUESTION", "pose beaucoup de questions ?" },
119 { "C_ME", "aime la commande /me" },
120 { "C_TOPIC", "change souvent le topic" },
121 { "C_MODE", "change souvent les modes" },
122 { "C_KICK", "aime la commande /kick" },
123 { "C_KICKED", "est souvent kické" },
124 { "C_URL", "poste beaucoup d'URLs" },
125 { "C_JOIN", "ne sait pas s'il doit rester ou partir" },
126 { "C_NICK", "change souvent de nick" },
127 { "C_MONOLOGUE", "parle beaucoup de monologues" }
129 { /* German language */
130 /* contributed by Valentin Gelhorn <valentin.gelhorn@web.de> */
132 { "HEADER", "Statistiken für #%s von %s" },
133 { "LEGEND", "Legende" },
134 { "LASTDAYS", "Statistik der letzten Tage" },
135 { "TOPHOURS", "Stündliche Statistik" },
136 { "TOPUSERS", "Die aktivsten Personen" },
137 { "OTHERS", "Es bleiben noch %d uneingetragene" },
138 { "NBLINES", "Zeilen" },
140 { "AVGLETTERS", "Buchstaben/Zeile" },
141 { "HOURS", "Stunden" },
142 { "QUOTE", "Zufällig ausgewaehlte Zitate" },
143 { "TOPUSERSTIME", "Die aktivsten Personen zur bestimmten Tageszeit" },
144 { "RANDTOPICS", "Ein paar Topics" },
145 { "CHANGEDBY", "Gesetzt von" },
146 { "NEWTOPIC", "Neues topic" },
147 { "RANDURLS", "Ein paar URLs" },
148 { "POSTEDBY", "Geschrieben von" },
149 { "POSTEDURL", "URL" },
150 { "TOPWORDS", "Am häufigsten benutze Wörter" },
152 { "OCCURRENCES", "Vorkommen" },
153 { "BIGNUMBERS", "Ein paar grosse Zahlen" },
154 { "NUMBERS", "Zahlen" },
155 { "TIME", "%d Zeilen analysiert in %d Sekunden" },
156 { "FOOTER", "Statistiken wurden erstellt von" },
157 { "C_SMILE", "ist oft glüklich :)" },
158 { "C_FROWN", "ist oft traurig :(" },
159 { "C_EXCLAM", "schreit oft !" },
160 { "C_QUESTION", "stellt viele Fragen ?" },
161 { "C_ME", "mag /me'en" },
162 { "C_TOPIC", "aendert oft das Topico" },
163 { "C_MODE", "aendert oft die Modes" },
164 { "C_KICK", "mag /kick'en" },
165 { "C_KICKED", "wird oft gekickt"},
166 { "C_URL", "schreibt viele URLs"},
167 { "C_JOIN", "kann sich nicht entscheiden ob er bleiben oder gehen soll" },
168 { "C_NICK", "ändert oft seinen Nick" },
169 { "C_MONOLOGUE", "spricht oft Monologe" }
171 { /* Spanish language */
172 /* contributed by Alex <ainaker@gmx.net> */
174 { "HEADER", "Estadísticas de #%s por %s" },
175 { "LEGEND", "Leyenda" },
176 { "LASTDAYS", "Estadísticas de los últimos días" },
177 { "TOPHOURS", "Estadísticas por horas" },
178 { "TOPUSERS", "Los que más escriben" },
179 { "OTHERS", "Hay %d más que no llegaron..." },
180 { "NBLINES", "líneas" },
182 { "AVGLETTERS", "letras por línea" },
183 { "HOURS", "horas" },
184 { "QUOTE", "Frase aleatoria" },
185 { "TOPUSERSTIME", "Los que más escriben según la hora" },
186 { "RANDTOPICS", "Algunos topics" },
187 { "CHANGEDBY", "Puestos por" },
188 { "NEWTOPIC", "topic" },
189 { "RANDURLS", "Algunas URLs" },
190 { "POSTEDBY", "puestas por" },
191 { "POSTEDURL", "URL" },
192 { "TOPWORDS", "Palabras más usadas" },
193 { "WORD", "Palabra" },
194 { "OCCURRENCES", "Frecuencia" },
195 { "BIGNUMBERS", "Algunos datos..." },
196 { "NUMBERS", "Número de veces" },
197 { "TIME", "%d lineas procesadas en %d segundos" },
198 { "FOOTER", "Estadísticas generadas por" },
199 { "C_SMILE", "Suele estar felíz :)" },
200 { "C_FROWN", "Suele estar triste :(" },
201 { "C_EXCLAM", "Grita mucho !" },
202 { "C_QUESTION", "Hace muchas preguntas ?" },
203 { "C_ME", "Abusa del comando /me" },
204 { "C_TOPIC", "Suele cambiar el topic" },
205 { "C_MODE", "Cambia a veces los modos del canal" },
206 { "C_KICK", "Le gusta patear" },
207 { "C_KICKED", "Es pateado con frecuencia" },
208 { "C_URL", "Pone muchas URLs" },
209 { "C_JOIN", "No sabe si irse o quedarse" },
210 { "C_NICK", "Cambia mucho de nick" },
211 { "C_MONOLOGUE", "Habla solo" }
220 for (i=1;i<=NBKEYS;i++) if (strcmp(key,keys[language][i][0])==0) return(keys[language][i][1]);
221 fprintf(stderr,"unknown language key: %s\n",key);
228 char *colors[NBTHEMES][NBCOLORS+1][2]= /* first key used for theme name/description and abbreviation */
230 { /* Default theme */
231 { "White background", "default" },
232 { "BGCOLOR", "#FFFFFF" },
233 { "TEXT", "#000000" },
234 { "LINK", "#0000EE" },
235 { "VLINK", "#551A8B" },
236 { "ALINK", "#FF0000" },
237 { "TITLE1", "#000000" },
238 { "TITLE2", "#000000" },
239 { "BGTABLE", "#EEEEEE" },
240 { "BGTITLE", "#FFEEEE" }
243 { "Black background", "dark" },
244 { "BGCOLOR", "#000000" },
245 { "TEXT", "#FFFFFF" },
246 { "LINK", "#AAAAFF" },
247 { "VLINK", "#CCCCDD" },
248 { "ALINK", "#FFAAAA" },
249 { "TITLE1", "#AAAAFF" },
250 { "TITLE2", "#FFAAAA" },
251 { "BGTABLE", "#225522" },
252 { "BGTITLE", "#552222" }
255 { "Green theme...", "zerezo" },
256 { "BGCOLOR", "#000000" },
257 { "TEXT", "#FFFFFF" },
258 { "LINK", "#14F024" },
259 { "VLINK", "#0CBA18" },
260 { "ALINK", "#FFFFFF" },
261 { "TITLE1", "#0CBA18" },
262 { "TITLE2", "#84DB8C" },
263 { "BGTABLE", "#085D10" },
264 { "BGTITLE", "#0B810B" }
266 { /* tit-namour theme */
267 { "Purple and Pink", "namour" },
268 { "BGCOLOR", "#9933CC" },
269 { "TEXT", "#DDAAFF" },
270 { "LINK", "#CC99FF" },
271 { "VLINK", "#999999" },
272 { "ALINK", "#FFC8C8" },
273 { "TITLE1", "#FFC8C8" },
274 { "TITLE2", "#FFC8C8" },
275 { "BGTABLE", "#7711AA" },
276 { "BGTITLE", "#550088" }
279 { "Orange theme...", "zeduel" },
280 { "BGCOLOR", "#FFFFFF" },
281 { "TEXT", "#000000" },
282 { "LINK", "#FF7700" },
283 { "VLINK", "#C05A00" },
284 { "ALINK", "#FF9A41" },
285 { "TITLE1", "#C05A00" },
286 { "TITLE2", "#FF7700" },
287 { "BGTABLE", "#FFEEEE" },
288 { "BGTITLE", "#FF7700" }
297 for (i=1;i<=NBCOLORS;i++) if (strcmp(color,colors[theme][i][0])==0) return(colors[theme][i][1]);
298 fprintf(stderr,"unknown theme color: %s\n",color);
309 char nick[MAXNICKLENGTH];
313 char quote[MAXQUOTELENGTH+1];
314 int counters[NBCOUNTERS];
320 char nick[MAXNICKLENGTH];
321 char url[MAXLINELENGTH];
322 char shorturl[MAXQUOTELENGTH+1];
328 char nick[MAXNICKLENGTH];
329 char topic[MAXQUOTELENGTH+1];
346 struct letter *next[26];
352 char word[MAXLINELENGTH];
355 #define isletter(c) (((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))
356 #define lowercase(c) (((c>='A')&&(c<='Z'))?c-'A'+'a':c)
357 void findwords(char *message)
360 struct letter *pos,*tmp;
363 while (!isletter(*message)) if (*message=='\0') return; else message++;
365 while (isletter(*message))
367 c=lowercase(*message)-'a';
368 if (pos->next[(int)c]==NULL)
370 tmp=malloc(sizeof(struct letter));
372 for (i=0;i<26;i++) tmp->next[i]=NULL;
373 pos->next[(int)c]=tmp;
375 pos=pos->next[(int)c];
383 char tempword[MAXLINELENGTH];
384 void bestwords(struct letter pos,int cur)
387 if ((cur>=MINWORDLENGTH)&&(pos.nb>topwords[NBWORDS-1].nb))
389 for (i=0;pos.nb<topwords[i].nb;i++);
390 for (j=NBWORDS-1;j>i;j--)
392 topwords[j].nb=topwords[j-1].nb;
393 strcpy(topwords[j].word,topwords[j-1].word);
395 topwords[i].nb=pos.nb;
396 strcpy(topwords[i].word,tempword);
398 for (i=0;i<26;i++) if (pos.next[i]!=NULL)
401 bestwords(*(pos.next[i]),cur+1);
406 void printhtml(char *string) /* replace < and > by < and > */
408 while (*string!='\0')
412 case '<':printf("<"); break;
413 case '>':printf(">"); break;
414 case '&':printf("&"); break;
415 default:printf("%c",*string); break;
422 int dichotomic(char *nick)
424 int i,j,start=0,end=nbusers-1,middle;
427 middle=(start+end)/2;
428 if (strcmp(nick,users[middle].nick)>0) start=middle+1; else end=middle-1;
430 if (strcmp(nick,users[start].nick)!=0)
433 if (nbusers>=MAXUSERS) { fprintf(stderr,"too many users\n"); exit(1); }
434 for (i=nbusers-1;i>start;i--)
436 strcpy(users[i].nick,users[i-1].nick);
437 users[i].lines=users[i-1].lines;
438 users[i].letters=users[i-1].letters;
439 for (j=0;j<4;j++) users[i].hours[j]=users[i-1].hours[j];
440 strcpy(users[i].quote,users[i-1].quote);
441 for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=users[i-1].counters[j];
443 strcpy(users[start].nick,nick);
444 users[start].lines=0;
445 users[start].letters=0;
446 for (j=0;j<4;j++) users[start].hours[j]=0;
447 users[start].quote[0]='\0';
448 for (j=0;j<NBCOUNTERS;j++) users[start].counters[j]=0;
453 int main(int argc,char *argv[])
456 int max,user,temp,hour;
457 int mononick,monolines;
463 char line[MAXLINELENGTH];
469 if ((argc<5) || (argc>6))
471 fprintf(stderr,"Usage: cat /path/to/file.log | ./irssistats channel maintainer language theme [nickfile] > /path/to/file.html\n\n");
472 fprintf(stderr,"Version :\nirssistats %s\n\n",VERSION);
473 fprintf(stderr,"Supported languages :\n");
474 for (i=0;i<NBLANGUAGES;i++) fprintf(stderr,"%s = %s\n",keys[i][0][1],keys[i][0][0]);
475 fprintf(stderr,"\nSupported themes :\n");
476 for (i=0;i<NBTHEMES;i++) fprintf(stderr,"%s = %s\n",colors[i][0][1],colors[i][0][0]);
481 for (i=0;i<NBLANGUAGES;i++) if (strcmp(argv[3],keys[i][0][1])==0) { language=i; break; }
484 fprintf(stderr,"Invalid language : %s\n",argv[3]);
487 for (i=0;i<NBTHEMES;i++) if (strcmp(argv[4],colors[i][0][1])==0) { theme=i; break; }
490 fprintf(stderr,"Invalid theme : %s\n",argv[4]);
496 srand(debut=time(NULL));
497 fprintf(stderr,"working:");
502 if (pos>=MAXLINELENGTH) { fprintf(stderr,"line too long\n"); exit(1); }
507 if (totallines%10000==0) { fprintf(stderr,"."); fflush(stdout); }
508 if (strncmp("--- Day changed",line,15)==0) /* --- Day changed Wed May 01 2002 */
512 lastdays[i].lines=lastdays[i-1].lines;
513 for (j=0;j<4;j++) lastdays[i].hours[j]=lastdays[i-1].hours[j];
516 for (j=0;j<4;j++) lastdays[0].hours[j]=0;
519 else if (strncmp("-!- mode/",&line[6],9)==0) /* 00:00 -!- mode/#channel [...] by (Nick, Nick2, )Nick3 */
521 for (i=strlen(line);line[i]!=' ';i--);
523 users[dichotomic(nick)].counters[D_MODE]++;
525 else if (strncmp("-!-",&line[6],3)==0) /* 00:00 -!- Nick something... */
527 for (i=10;line[i]!=' ';i++);
531 if (strncmp("changed the topic of",message,20)==0) /* 00:00 -!- Nick changed the topic of #channel to: new topic */
533 users[dichotomic(nick)].counters[D_TOPIC]++;
534 for (i=21;message[i]!=':';i++);
535 message=&message[i+2];
537 if ((nbtopics<=NBTOPICS) || (rand()%(nbtopics/NBTOPICS)==0))
539 temp=nbtopics<=NBTOPICS?nbtopics-1:rand()%NBTOPICS;
540 strcpy(topics[temp].nick,nick);
541 strncpy(topics[temp].topic,message,MAXQUOTELENGTH);
544 else if (strncmp("was kicked from",message,15)==0) /* 00:00 -!- Nick was kicked from #channel by Nick [Reason] */
546 users[dichotomic(nick)].counters[D_KICKED]++;
547 for (i=16;message[i]!=' ';i++);
548 message=&message[i+4];
549 for (i=0;message[i]!=' ';i++);
551 users[dichotomic(message)].counters[D_KICK]++;
553 else if (strncmp("is now known as",message,15)==0) /* 00:00 -!- Nick is now known as Nick */
554 users[dichotomic(nick)].counters[D_NICK]++;
555 else if (message[0]=='[') /* 00:00 -!- Nick [user@host] something... */
557 for (i=0;message[i]!=']';i++);
558 message=&message[i+2];
559 if (strncmp("has joined",message,10)==0) /* 00:00 -!- Nick [user@host] has joined #channel */
560 users[dichotomic(nick)].counters[D_JOIN]++;
561 else if (strncmp("has quit",message,8)==0); /* 00:00 -!- Nick [user@host] has quit [Reason] */
562 else if (strncmp("has left",message,8)==0); /* 00:00 -!- Nick [user@host] has left #channel [Reason] */
566 else if ((line[6]=='<') || (line[7]=='*'))
570 if (line[7]=='*') /* 00:00 * Nick the message */
572 for (i=9;line[i]!=' ';i++);
576 else if (line[7]=='>') /* 00:00 <>>>?Nick<<<> the personal message */
577 /* 00:00 <>>?Nick<<> the personal message */
579 for (i=10;line[i]!='<';i++);
581 if (line[9]=='>') nick++;
584 else /* 00:00 <?Nick> the message */
586 for (i=8;line[i]!='>';i++);
592 if (line[7]=='*') users[i].counters[D_ME]++;
596 if (monolines==5) users[i].counters[D_MONOLOGUE]++;
606 users[i].hours[hour/6]++;
608 lastdays[0].hours[hour/6]++;
611 if (message[j-1]=='?') users[i].counters[D_QUESTION]++;
612 else if (message[j-1]=='!') users[i].counters[D_EXCLAM]++;
613 else if ((message[j-3]==' ')&&(message[j-2]==':'))
615 if (message[j-1]==')') users[i].counters[D_SMILE]++;
616 else if (message[j-1]=='(') users[i].counters[D_FROWN]++;
618 if (rand()%users[i].lines==0) strncpy(users[i].quote,message,MAXQUOTELENGTH);
619 if (strncmp("http://",message,7)==0)
621 users[i].counters[D_URL]++;
622 for (i=0;(message[i]!=' ') && (i<strlen(message));i++);
625 if ((nburls<=NBURLS) || (rand()%(nburls/NBURLS)==0))
627 temp=nburls<=NBURLS?nburls-1:rand()%NBURLS;
628 strcpy(urls[temp].nick,nick);
629 strcpy(urls[temp].url,message);
630 strncpy(urls[temp].shorturl,message,MAXQUOTELENGTH);
638 fprintf(stderr,"done\n");
646 if ((fic=fopen(argv[5],"rt"))==NULL) { fprintf(stderr,"can't open nick file\n"); exit(1); }
647 while (fscanf(fic,"%s",line)==1)
649 user=dichotomic(line);
650 fscanf(fic,"%s",line);
651 if (regcomp(&preg,line,0)!=0) { fprintf(stderr,"error in nick file"); exit(1); }
652 temp=users[user].lines;
653 for (i=0;i<nbusers;i++) if ((i!=user) && (regexec(&preg,users[i].nick,0,0,0)==0) && (users[i].lines>=0))
655 if (users[i].lines>temp) /* for nick alias, keep the random quote of the most used nick */
657 strcpy(users[user].quote,users[i].quote);
660 users[user].lines+=users[i].lines;
661 users[user].letters+=users[i].letters;
662 for (j=0;j<4;j++) users[user].hours[j]+=users[i].hours[j];
663 for (j=0;j<NBCOUNTERS;j++) users[user].counters[j]+=users[i].counters[j];
664 /* "remove" old user */
667 for (j=0;j<4;j++) users[i].hours[j]=-1;
668 for (j=0;j<NBCOUNTERS;j++) users[i].counters[j]=-1;
678 printf("<!-- Generated by irssistats %s : %s -->\n\n",VERSION,URL);
679 printf("<html>\n\n<head>\n<base target=\"_blank\">\n<title>");
680 printf(L("HEADER"),channel,maintainer);
681 printf("</title>\n</head>\n\n");
682 printf("<body bgcolor=\"%s\" text=\"%s\" link=\"%s\" vlink=\"%s\" alink=\"%s\">\n\n<center>\n\n<font color=\"%s\"><h1>",T("BGCOLOR"),T("TEXT"),T("LINK"),T("VLINK"),T("ALINK"),T("TITLE1"));
683 printf(L("HEADER"),channel,maintainer);
684 printf("</h1></font>\n%s<br>\n<br><br>\n\n",ctime(&debut));
687 printf("<font color=\"%s\"><h3>%s</h3></font>\n<table bgcolor=%s>\n<tr>\n",T("TITLE2"),L("LEGEND"),T("BGTABLE"));
688 for (i=0;i<4;i++) printf("<td><img src=\"h%d.png\" width=\"40\" height=\"15\"></td><td> : %s %d-%d</td><td width=\"10\"></td>\n",i+1,L("HOURS"),i*6,i*6+5);
689 printf("</tr>\n</table>\n<br><br>\n\n");
692 printf("<font color=\"%s\"><h3>%s</h3></font>\n<table>\n<tr>\n",T("TITLE2"),L("LASTDAYS"));
694 for (i=30;i>=0;i--) if (lastdays[i].lines>max) max=lastdays[i].lines;
697 printf("<td width=\"15\" align=\"center\" valign=\"bottom\"><font size=\"-2\">%d</font><br>",lastdays[i].lines);
698 for (j=0;j<4;j++) if (lastdays[i].hours[j]!=0) printf("<img src=\"v%d.png\" width=\"15\" height=\"%d\"><br>",j+1,150*lastdays[i].hours[j]/max);
701 printf("</tr>\n<tr>\n");
703 printf("<td align=\"center\" valign=\"center\" bgcolor=\"%s\">%d</td>\n",T("BGTABLE"),i);
704 printf("</tr>\n</table>\n<br><br>\n\n");
707 printf("<font color=\"%s\"><h3>%s</h3></font>\n<table>\n<tr>\n",T("TITLE2"),L("TOPHOURS"));
709 for (i=0;i<24;i++) if (hours[i]>max) max=hours[i];
712 printf("<td width=\"15\" align=\"center\" valign=\"bottom\"><font size=\"-2\">%.1f%%</font><br>",lines!=0?(float)100*hours[i]/lines:0);
713 if (hours[i]!=0) printf("<img src=\"v%d.png\" width=\"15\" height=\"%d\"><br>",i/6+1,150*hours[i]/max);
716 printf("</tr>\n<tr>\n");
718 printf("<td align=\"center\" valign=\"center\" bgcolor=\"%s\">%d</td>\n",T("BGTABLE"),i);
719 printf("</tr>\n</table>\n<br><br>\n\n");
722 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("TOPUSERS"));
723 printf("<table>\n<tr><td></td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\" colspan=\"2\">%s</td><td bgcolor=\"%s\">%s</td>\n",T("BGTITLE"),L("NICK"),T("BGTITLE"),L("NBLINES"),T("BGTITLE"),L("HOURS"),T("BGTITLE"),L("AVGLETTERS"),T("BGTITLE"),L("QUOTE"));
724 for (i=1;i<=NBUSERS;i++)
728 for (j=0;j<nbusers;j++) if (users[j].lines>max) max=users[user=j].lines;
731 printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\">",T("BGTABLE"),i,T("BGTABLE"),users[user].nick,T("BGTABLE"),users[user].lines,T("BGTABLE"));
732 for (j=0;j<4;j++) if (users[user].hours[j]!=0) printf("<img src=\"h%d.png\" width=\"%d\" height=\"15\">",j+1,100*users[user].hours[j]/users[user].lines);
733 printf("</td><td bgcolor=\"%s\">%d</td><td bgcolor=\"%s\"><img src=\"hm.png\" width=\"%d\" height=\"15\"></td><td bgcolor=\"%s\">\"",T("BGTABLE"),users[user].lines!=0?users[user].letters/users[user].lines:0,T("BGTABLE"),users[user].lines!=0?users[user].letters/users[user].lines:0,T("BGTABLE"));
734 printhtml(users[user].quote);
735 printf("\"</td></tr>\n");
736 users[user].lines=-1;
739 printf("</table>\n");
741 for (i=0;i<=nbusers;i++) if (users[i].lines>=0) temp++;
745 printf(L("OTHERS"),temp);
748 printf("<br><br>\n\n");
750 /* top users by time */
751 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("TOPUSERSTIME"));
752 printf("<table>\n<tr><td></td>");
753 for (i=0;i<4;i++) printf("<td bgcolor=\"%s\" colspan=\"2\">%s %d-%d</td>",T("BGTITLE"),L("HOURS"),i*6,i*6+5);
755 for (i=1;i<=NBUSERSTIME;i++)
757 printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td>",T("BGTABLE"),i);
762 for (k=0;k<nbusers;k++) if (users[k].hours[j]>max) max=users[user=k].hours[j];
765 printf("<td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td>",T("BGTABLE"),users[user].nick,T("BGTABLE"),users[user].hours[j]);
766 users[user].hours[j]=-1;
768 else printf("<td></td><td></td>");
772 printf("</table>\n<br><br>\n\n");
775 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("RANDTOPICS"));
776 printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("CHANGEDBY"),T("BGTITLE"),L("NEWTOPIC"));
777 for (i=nbtopics<NBTOPICS?nbtopics-1:NBTOPICS-1;i>=0;i--)
779 printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"",T("BGTABLE"),topics[i].nick,T("BGTABLE"));
780 printhtml(topics[i].topic);
781 printf("\"</td></tr>\n");
783 printf("</table>\n<br><br>\n\n");
786 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("RANDURLS"));
787 printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("POSTEDBY"),T("BGTITLE"),L("POSTEDURL"));
788 for (i=nburls<NBURLS?nburls-1:NBURLS-1;i>=0;i--)
790 printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">\"<a href=\"%s\">",T("BGTABLE"),urls[i].nick,T("BGTABLE"),urls[i].url);
791 printhtml(urls[i].shorturl);
792 printf("</a>\"</td></tr>\n");
794 printf("</table>\n<br><br>\n\n");
797 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("TOPWORDS"));
798 printf("<table>\n<tr><td></td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("WORD"),T("BGTITLE"),L("OCCURRENCES"));
799 for (i=0;i<NBWORDS;i++)
800 if (topwords[i].nb!=0) printf("<tr><td bgcolor=\"%s\" align=\"right\">%d</td><td bgcolor=\"%s\">\"%s\"</td><td bgcolor=\"%s\">%d</td></tr>\n",T("BGTABLE"),i+1,T("BGTABLE"),topwords[i].word,T("BGTABLE"),topwords[i].nb);
801 printf("</table>\n<br><br>\n\n");
804 printf("<font color=\"%s\"><h3>%s</h3></font>\n",T("TITLE2"),L("BIGNUMBERS"));
805 printf("<table>\n<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td></tr>\n",T("BGTITLE"),L("NICK"),T("BGTITLE"),L("NUMBERS"),T("BGTITLE"),L("NBLINES"));
806 for (i=0;i<NBCOUNTERS;i++)
810 for (j=0;j<nbusers;j++) if (users[j].counters[i]>max) max=users[user=j].counters[i];
811 if (user!=-1) printf("<tr><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%s</td><td bgcolor=\"%s\">%d</td></tr>",T("BGTABLE"),users[user].nick,T("BGTABLE"),L(counters[i]),T("BGTABLE"),users[user].counters[i]);
813 printf("</table>\n<br><br>\n\n");
816 printf(L("TIME"),totallines,(int)(time(NULL)-debut));
817 printf("<br>\n%s <a href=\"%s\">irssistats %s</a>",L("FOOTER"),URL,VERSION);
818 printf("\n\n</center>\n\n</body>\n\n</html>\n");