/[irc-logger]/trunk/bin/irc-logger.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/bin/irc-logger.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 6 by dpavlin, Mon Feb 27 12:41:10 2006 UTC revision 36 by dpavlin, Sun Jun 25 16:37:39 2006 UTC
# Line 18  log all conversation on irc channel Line 18  log all conversation on irc channel
18    
19  ## CONFIG  ## CONFIG
20    
21    my $HOSTNAME = `hostname`;
22    
23  my $NICK = 'irc-logger';  my $NICK = 'irc-logger';
24    $NICK .= '-dev' if ($HOSTNAME =~ m/llin/);
25  my $CONNECT =  my $CONNECT =
26    {Server => 'irc.freenode.net',    {Server => 'irc.freenode.net',
27     Nick => $NICK,     Nick => $NICK,
28     Ircname => 'logger: ask dpavlin@rot13.org'     Ircname => "try /msg $NICK help",
29    };    };
30  my $CHANNEL = '#razmjenavjestina';  my $CHANNEL = '#razmjenavjestina';
31    $CHANNEL = '#irc-logger' if ($HOSTNAME =~ m/llin/);
32  my $IRC_ALIAS = "log";  my $IRC_ALIAS = "log";
33    
34  my %FOLLOWS =  my %FOLLOWS =
# Line 33  my %FOLLOWS = Line 37  my %FOLLOWS =
37     ERROR => "/var/log/apache/error.log",     ERROR => "/var/log/apache/error.log",
38    );    );
39    
40  my $DSN = 'DBI:Pg:dbname=irc-logger';  my $DSN = 'DBI:Pg:dbname=' . $NICK;
41    
42    my $ENCODING = 'ISO-8859-2';
43    my $TIMESTAMP = '%Y-%m-%d %H:%M:%S';
44    
45  ## END CONFIG  ## END CONFIG
46    
47    
48    
49  use POE qw(Component::IRC Wheel::FollowTail);  use POE qw(Component::IRC Wheel::FollowTail Component::Server::HTTP);
50    use HTTP::Status;
51  use DBI;  use DBI;
52  use Encode qw/from_to/;  use Encode qw/from_to is_utf8/;
53    use Regexp::Common qw /URI/;
54    use CGI::Simple;
55    use HTML::TagCloud;
56    use POSIX qw/strftime/;
57    use HTML::CalendarMonthSimple;
58    
59  my $dbh = DBI->connect($DSN,"","", { RaiseError => 1, AutoCommit => 1 }) || die $DBI::errstr;  my $dbh = DBI->connect($DSN,"","", { RaiseError => 1, AutoCommit => 1 }) || die $DBI::errstr;
60    
61  =for SQL schema  eval {
62            $dbh->do(qq{ select count(*) from log });
63    };
64    
65    if ($@) {
66            warn "creating database table in $DSN\n";
67            $dbh->do(<<'_SQL_SCHEMA_');
68    
 $dbh->do(qq{  
69  create table log (  create table log (
70          id serial,          id serial,
71          time timestamp default now(),          time timestamp default now(),
72          channel text not null,          channel text not null,
73            me boolean default false,
74          nick text not null,          nick text not null,
75          message text not null,          message text not null,
76          primary key(id)          primary key(id)
# Line 62  create index log_time on log(time); Line 80  create index log_time on log(time);
80  create index log_channel on log(channel);  create index log_channel on log(channel);
81  create index log_nick on log(nick);  create index log_nick on log(nick);
82    
83  });  _SQL_SCHEMA_
84    }
 =cut  
85    
86  my $sth = $dbh->prepare(qq{  my $sth = $dbh->prepare(qq{
87  insert into log  insert into log
88          (channel, nick, message)          (channel, me, nick, message)
89  values (?,?,?)  values (?,?,?,?)
90  });  });
91    
92    my $tags;
93    my $tag_regex = '\b([\w-_]+)//';
94    
95    =head2 get_from_log
96    
97     my @messages = get_from_log(
98            limit => 42,
99            search => '%what to stuff in ilike%',
100            fmt => {
101                    time => '{%s} ',
102                    time_channel => '{%s %s} ',
103                    nick => '%s: ',
104                    me_nick => '***%s ',
105                    message => '%s',
106            },
107            filter => {
108                    message => sub {
109                            # modify message content
110                            return shift;
111                    }
112            },
113            context => 5,
114     );
115    
116    Order is important. Fields are first passed through C<filter> (if available) and
117    then throgh C<< sprintf($fmt->{message}, $message >> if available.
118    
119    C<context> defines number of messages around each search hit for display.
120    
121    =cut
122    
123    sub get_from_log {
124            my $args = {@_};
125    
126            $args->{fmt} ||= {
127                    date => '[%s] ',
128                    time => '{%s} ',
129                    time_channel => '{%s %s} ',
130                    nick => '%s: ',
131                    me_nick => '***%s ',
132                    message => '%s',
133            };
134    
135            my $sql_message = qq{
136                    select
137                            time::date as date,
138                            time::time as time,
139                            channel,
140                            me,
141                            nick,
142                            message
143                    from log
144            };
145    
146            my $sql_context = qq{
147                    select
148                            id
149                    from log
150            };
151    
152            my $context = $1 if ($args->{search} && $args->{search} =~ s/\s*\+(\d+)\s*/ /);
153    
154            my $sql = $context ? $sql_context : $sql_message;
155    
156            $sql .= " where message ilike ? or nick ilike ? " if ($args->{search});
157            $sql .= " where id in (" . join(",", @{ $tags->{ $args->{tag} } }) . ") " if ($args->{tag} && $tags->{ $args->{tag} });
158            $sql .= " where date(time) = ? " if ($args->{date});
159            $sql .= " order by log.time desc";
160            $sql .= " limit " . $args->{limit} if ($args->{limit});
161    
162            my $sth = $dbh->prepare( $sql );
163            if (my $search = $args->{search}) {
164                    $search =~ s/^\s+//;
165                    $search =~ s/\s+$//;
166                    $sth->execute( ( '%' . $search . '%' ) x 2 );
167                    warn "search for '$search' returned ", $sth->rows, " results ", $context || '', "\n";
168            } elsif (my $tag = $args->{tag}) {
169                    $sth->execute();
170                    warn "tag '$tag' returned ", $sth->rows, " results ", $context || '', "\n";
171            } elsif (my $date = $args->{date}) {
172                    $sth->execute($date);
173                    warn "found ", $sth->rows, " messages for date $date ", $context || '', "\n";
174            } else {
175                    $sth->execute();
176            }
177            my $last_row = {
178                    date => '',
179                    time => '',
180                    channel => '',
181                    nick => '',
182            };
183    
184            my @rows;
185    
186            while (my $row = $sth->fetchrow_hashref) {
187                    unshift @rows, $row;
188            }
189    
190            my @msgs = (
191                    "Showing " . ($#rows + 1) . " messages..."
192            );
193    
194            if ($context) {
195                    my @ids = @rows;
196                    @rows = ();
197    
198                    my $last_to = 0;
199    
200                    my $sth = $dbh->prepare( $sql_message . qq{ where id >= ? and id < ? } );
201                    foreach my $row_id (sort { $a->{id} <=> $b->{id} } @ids) {
202                            my $id = $row_id->{id} || die "can't find id in row";
203            
204                            my ($from, $to) = ($id - $context, $id + $context);
205                            $from = $last_to if ($from < $last_to);
206                            $last_to = $to;
207                            $sth->execute( $from, $to );
208    
209                            #warn "## id: $id from: $from to: $to returned: ", $sth->rows, "\n";
210    
211                            while (my $row = $sth->fetchrow_hashref) {
212                                    push @rows, $row;
213                            }
214    
215                    }
216            }
217    
218            # sprintf which can take coderef as first parametar
219            sub cr_sprintf {
220                    my $fmt = shift || return;
221                    if (ref($fmt) eq 'CODE') {
222                            $fmt->(@_);
223                    } else {
224                            sprintf($fmt, @_);
225                    }
226            }
227    
228            foreach my $row (@rows) {
229    
230                    $row->{time} =~ s#\.\d+##;
231    
232                    my $msg = '';
233    
234                    $msg = cr_sprintf($args->{fmt}->{date}, $row->{date}) . ' ' if ($last_row->{date} ne $row->{date});
235                    my $t = $row->{time};
236    
237                    if ($last_row->{channel} ne $row->{channel}) {
238                            $msg .= cr_sprintf($args->{fmt}->{time_channel}, $t, $row->{channel});
239                    } else {
240                            $msg .= cr_sprintf($args->{fmt}->{time}, $t);
241                    }
242    
243                    my $append = 1;
244    
245                    my $nick = $row->{nick};
246                    if ($nick =~ s/^_*(.*?)_*$/$1/) {
247                            $row->{nick} = $nick;
248                    }
249    
250                    if ($last_row->{nick} ne $nick) {
251                            # obfu way to find format for me_nick if needed or fallback to default
252                            my $fmt = $row->{me} ? ( $args->{fmt}->{me_nick} || $args->{fmt}->{nick} ) : $args->{fmt}->{nick};
253                            $fmt ||= '%s';
254    
255                            $nick = $args->{filter}->{nick}->($nick) if (ref($args->{filter}->{nick}) eq 'CODE');
256    
257                            $msg .= cr_sprintf( $fmt, $nick );
258                            $append = 0;
259                    }
260    
261                    $args->{fmt}->{message} ||= '%s';
262                    if (ref($args->{filter}->{message}) eq 'CODE') {
263                            $msg .= cr_sprintf($args->{fmt}->{message},
264                                    $args->{filter}->{message}->(
265                                            $row->{message}
266                                    )
267                            );
268                    } else {
269                            $msg .= cr_sprintf($args->{fmt}->{message}, $row->{message});
270                    }
271    
272                    if ($append && @msgs) {
273                            $msgs[$#msgs] .= " " . $msg;
274                    } else {
275                            push @msgs, $msg;
276                    }
277    
278                    $last_row = $row;
279            }
280    
281            return @msgs;
282    }
283    
284    
285  my $SKIPPING = 0;               # if skipping, how many we've done  my $SKIPPING = 0;               # if skipping, how many we've done
286  my $SEND_QUEUE;                 # cache  my $SEND_QUEUE;                 # cache
287    
288  POE::Component::IRC->new($IRC_ALIAS);  POE::Component::IRC->new($IRC_ALIAS);
289    
290  POE::Session->create  =head2 save_message
291    (inline_states =>  
292      save_message($channel,$me,$nick,$msg);
293    
294    =cut
295    
296    sub save_message {
297            my ($channel,$me,$nick,$msg) = @_;
298            $me ||= 0;
299            $sth->execute($channel, $me, $nick, $msg);
300            add_tag( id => $dbh->last_insert_id(undef,undef,"log",undef),
301                    message => $msg);
302    }
303    
304    POE::Session->create( inline_states =>
305     {_start => sub {           {_start => sub {      
306        $_[KERNEL]->post($IRC_ALIAS => register => 'all');                  $_[KERNEL]->post($IRC_ALIAS => register => 'all');
307        $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);                  $_[KERNEL]->post($IRC_ALIAS => connect => $CONNECT);
308      },      },
309      irc_255 => sub {            # server is done blabbing      irc_255 => sub {    # server is done blabbing
310        $_[KERNEL]->post($IRC_ALIAS => join => $CHANNEL);                  $_[KERNEL]->post($IRC_ALIAS => join => $CHANNEL);
311        $_[KERNEL]->post($IRC_ALIAS => join => '#logger');                  $_[KERNEL]->post($IRC_ALIAS => join => '#logger');
312        $_[KERNEL]->yield("heartbeat"); # start heartbeat                  $_[KERNEL]->yield("heartbeat"); # start heartbeat
313  #      $_[KERNEL]->yield("my_add", $_) for keys %FOLLOWS;  #               $_[KERNEL]->yield("my_add", $_) for keys %FOLLOWS;
314                    $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );
315      },      },
316      irc_public => sub {      irc_public => sub {
317            my $kernel = $_[KERNEL];                  my $kernel = $_[KERNEL];
318            my $nick = (split /!/, $_[ARG0])[0];                  my $nick = (split /!/, $_[ARG0])[0];
319            my $channel = $_[ARG1]->[0];                  my $channel = $_[ARG1]->[0];
320            my $msg = $_[ARG2];                  my $msg = $_[ARG2];
321    
322            from_to($msg, 'UTF-8', 'ISO-8859-2');                  from_to($msg, 'UTF-8', $ENCODING);
323    
324            print "$channel: <$nick> $msg\n";                  print "$channel: <$nick> $msg\n";
325            $sth->execute($channel, $nick, $msg);                  save_message($channel, 0, $nick, $msg);
326      },      },
327      (map      irc_ctcp_action => sub {
328       {                  my $kernel = $_[KERNEL];
329         ;"irc_$_" => sub { }}                  my $nick = (split /!/, $_[ARG0])[0];
330       qw(join                  my $channel = $_[ARG1]->[0];
331          ctcp_version                  my $msg = $_[ARG2];
332          connected snotice ctcp_action ping notice mode part quit  
333          001 002 003 004 005                  from_to($msg, 'UTF-8', $ENCODING);
334          250 251 252 253 254 265 266  
335          332 333 353 366 372 375 376                  print "$channel ***$nick $msg\n";
336                  477                  save_message($channel, 1, $nick, $msg);
337                  )),      },
338            irc_msg => sub {
339                    my $kernel = $_[KERNEL];
340                    my $nick = (split /!/, $_[ARG0])[0];
341                    my $msg = $_[ARG2];
342                    from_to($msg, 'UTF-8', $ENCODING);
343    
344                    my $res = "unknown command '$msg', try /msg $NICK help!";
345                    my @out;
346    
347                    print "<< $msg\n";
348    
349                    if ($msg =~ m/^help/i) {
350    
351                            $res = "usage: /msg $NICK comand | commands: stat - user/message stat | last - show backtrace | grep foobar - find foobar";
352    
353                    } elsif ($msg =~ m/^msg\s+(\S+)\s+(.*)$/i) {
354    
355                            print ">> /msg $1 $2\n";
356                            $_[KERNEL]->post( $IRC_ALIAS => privmsg => $1, $2 );
357                            $res = '';
358    
359                    } elsif ($msg =~ m/^stat.*?\s*(\d*)/i) {
360    
361                            my $nr = $1 || 10;
362    
363                            my $sth = $dbh->prepare(qq{
364                                    select nick,count(*) from log group by nick order by count desc limit $nr
365                            });
366                            $sth->execute();
367                            $res = "Top $nr users: ";
368                            my @users;
369                            while (my $row = $sth->fetchrow_hashref) {
370                                    push @users,$row->{nick} . ': ' . $row->{count};
371                            }
372                            $res .= join(" | ", @users);
373                    } elsif ($msg =~ m/^last.*?\s*(\d*)/i) {
374    
375                            foreach my $res (get_from_log( limit => $1 )) {
376                                    print "last: $res\n";
377                                    from_to($res, $ENCODING, 'UTF-8');
378                                    $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );
379                            }
380    
381                            $res = '';
382    
383                    } elsif ($msg =~ m/^(search|grep)\s+(.*)\s*$/i) {
384    
385                            my $what = $2;
386    
387                            foreach my $res (get_from_log(
388                                            limit => 20,
389                                            search => $what,
390                                    )) {
391                                    print "search [$what]: $res\n";
392                                    from_to($res, $ENCODING, 'UTF-8');
393                                    $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );
394                            }
395    
396                            $res = '';
397    
398                    }
399    
400                    if ($res) {
401                            print ">> [$nick] $res\n";
402                            from_to($res, $ENCODING, 'UTF-8');
403                            $_[KERNEL]->post( $IRC_ALIAS => privmsg => $nick, $res );
404                    }
405    
406            },
407            irc_477 => sub {
408                    print "# irc_477: ",$_[ARG1], "\n";
409                    $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "register $NICK" );
410            },
411            irc_505 => sub {
412                    print "# irc_505: ",$_[ARG1], "\n";
413                    $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "register $NICK" );
414    #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "set hide email on" );
415    #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "set email dpavlin\@rot13.org" );
416            },
417            irc_registered => sub {
418                    warn "## indetify $NICK\n";
419                    $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );
420            },
421    #       irc_433 => sub {
422    #               print "# irc_433: ",$_[ARG1], "\n";
423    #               warn "## indetify $NICK\n";
424    #               $_[KERNEL]->post( $IRC_ALIAS => privmsg => 'nickserv', "IDENTIFY $NICK" );
425    #       },
426      _child => sub {},      _child => sub {},
427      _default => sub {      _default => sub {
428        printf "%s: session %s caught an unhandled %s event.\n",                  printf "%s #%s %s %s\n",
429          scalar localtime(), $_[SESSION]->ID, $_[ARG0];                          strftime($TIMESTAMP,localtime()), $_[SESSION]->ID, $_[ARG0],
430        print "The $_[ARG0] event was given these parameters: ",                          ref($_[ARG1]) eq "ARRAY"        ?       join(",", map { ref($_) eq "ARRAY" ? join(";", @{$_}) : $_ } @{ $_[ARG1] })     :
431          join(" ", map({"ARRAY" eq ref $_ ? "[@$_]" : "$_"} @{$_[ARG1]})), "\n";                          $_[ARG1]                                        ?       $_[ARG1]                                        :
432                            "";
433        0;                        # false for signals        0;                        # false for signals
434      },      },
435      my_add => sub {      my_add => sub {
# Line 183  POE::Session->create Line 495  POE::Session->create
495     },     },
496    );    );
497    
498    # tags support
499    
500    my $cloud = HTML::TagCloud->new;
501    
502    =head2 add_tag
503    
504     add_tag( id => 42, message => 'irc message' );
505    
506    =cut
507    
508    sub add_tag {
509            my $arg = {@_};
510    
511            return unless ($arg->{id} && $arg->{message});
512    
513            my $m = $arg->{message};
514            from_to('UTF-8', 'iso-8859-2', $m) if (is_utf8($m));
515    
516            while ($m =~ s#$tag_regex##s) {
517                    my $tag = $1;
518                    next if (! $tag || $tag =~ m/https?:/i);
519                    push @{ $tags->{$tag} }, $arg->{id};
520                    #warn "+tag $tag: $arg->{id}\n";
521                    $cloud->add($tag, "?tag=$tag", scalar @{$tags->{$tag}} + 1);
522            }
523    }
524    
525    =head2 seed_tags
526    
527    Read all tags from database and create in-memory cache for tags
528    
529    =cut
530    
531    sub seed_tags {
532            my $sth = $dbh->prepare(qq{ select id,message from log where message like '%//%' });
533            $sth->execute;
534            while (my $row = $sth->fetchrow_hashref) {
535                    add_tag( %$row );
536            }
537    
538            foreach my $tag (keys %$tags) {
539                    $cloud->add($tag, "?tag=$tag", scalar @{$tags->{$tag}} + 1);
540            }
541    }
542    
543    seed_tags;
544    
545    # http server
546    
547    my $httpd = POE::Component::Server::HTTP->new(
548            Port => $NICK =~ m/-dev/ ? 8001 : 8000,
549            ContentHandler => { '/' => \&root_handler },
550            Headers        => { Server => 'irc-logger' },
551    );
552    
553    my %escape = ('<'=>'&lt;', '>'=>'&gt;', '&'=>'&amp;', '"'=>'&quot;');
554    my $escape_re  = join '|' => keys %escape;
555    
556    my $style = <<'_END_OF_STYLE_';
557    p { margin: 0; padding: 0.1em; }
558    .time, .channel { color: #808080; font-size: 60%; }
559    .date { float: right; background: #e0e0e0; color: #404040; font-size: 120%; padding: 0.25em; border: 1px dashed #808080; }
560    .nick { color: #000000; font-size: 80%; padding: 2px; font-family: courier, courier new, monospace ; }
561    .message { color: #000000; font-size: 100%; }
562    .search { float: right; }
563    .col-0 { background: #ffff66 }
564    .col-1 { background: #a0ffff }
565    .col-2 { background: #99ff99 }
566    .col-3 { background: #ff9999 }
567    .col-4 { background: #ff66ff }
568    a:link.tag, a:visited.tag { border: 1px dashed #ccc; backgound: #ccc; text-decoration: none }
569    a:hover.tag { border: 1px solid #eee }
570    hr { border: 1px dashed #ccc; height: 1px; clear: both; }
571    _END_OF_STYLE_
572    
573    my $max_color = 4;
574    
575    my %nick_enumerator;
576    
577    sub root_handler {
578            my ($request, $response) = @_;
579            $response->code(RC_OK);
580            $response->content_type("text/html; charset=$ENCODING");
581    
582            my $q;
583    
584            if ( $request->method eq 'POST' ) {
585                    $q = new CGI::Simple( $request->content );
586            } elsif ( $request->uri =~ /\?(.+)$/ ) {
587                    $q = new CGI::Simple( $1 );
588            } else {
589                    $q = new CGI::Simple;
590            }
591    
592            my $search = $q->param('search') || $q->param('grep') || '';
593    
594            my $html =
595                    qq{<html><head><title>$NICK</title><style type="text/css">$style} .
596                    $cloud->css .
597                    qq{</style></head><body>} .
598                    qq{
599                    <form method="post" class="search" action="/">
600                    <input type="text" name="search" value="$search" size="10">
601                    <input type="submit" value="search">
602                    </form>
603                    } .
604                    $cloud->html(500) .
605                    qq{<p>};
606            if ($request->url =~ m#/history#) {
607                    my $sth = $dbh->prepare(qq{
608                            select date(time) as date,count(*) as nr
609                                    from log
610                                    group by date(time)
611                                    order by date(time) desc
612                    });
613                    $sth->execute();
614                    my ($l_yyyy,$l_mm) = (0,0);
615                    my $cal;
616                    while (my $row = $sth->fetchrow_hashref) {
617                            # this is probably PostgreSQL specific, expects ISO date
618                            my ($yyyy,$mm,$dd) = split(/-/, $row->{date});
619                            if ($yyyy != $l_yyyy || $mm != $l_mm) {
620                                    $html .= $cal->as_HTML() if ($cal);
621                                    $cal = new HTML::CalendarMonthSimple('month'=>$mm,'year'=>$yyyy);
622                                    $cal->border(2);
623                                    ($l_yyyy,$l_mm) = ($yyyy,$mm);
624                            }
625                            $cal->setcontent($dd, qq{
626                                    <a href="/?date=$row->{date}">$row->{nr}</a>
627                            });
628                    }
629                    $html .= $cal->as_HTML() if ($cal);
630    
631            } else {
632                    $html .= join("</p><p>",
633                            get_from_log(
634                                    limit => $q->param('last') || $q->param('date') ? undef : 100,
635                                    search => $search || undef,
636                                    tag => $q->param('tag') || undef,
637                                    date => $q->param('date') || undef,
638                                    fmt => {
639                                            date => sub {
640                                                    my $date = shift || return;
641                                                    qq{<hr/><div class="date"><a href="/?date=$date">$date</a></div> '};
642                                            },
643                                            time => '<span class="time">%s</span> ',
644                                            time_channel => '<span class="channel">%s %s</span> ',
645                                            nick => '%s:&nbsp;',
646                                            me_nick => '***%s&nbsp;',
647                                            message => '<span class="message">%s</span>',
648                                    },
649                                    filter => {
650                                            message => sub {
651                                                    my $m = shift || return;
652                                                    $m =~ s/($escape_re)/$escape{$1}/gs;
653                                                    $m =~ s#($RE{URI}{HTTP})#<a href="$1">$1</a>#gs;
654                                                    $m =~ s#$tag_regex#<a href="?tag=$1" class="tag">$1</a>#g;
655                                                    return $m;
656                                            },
657                                            nick => sub {
658                                                    my $n = shift || return;
659                                                    if (! $nick_enumerator{$n})  {
660                                                            my $max = scalar keys %nick_enumerator;
661                                                            $nick_enumerator{$n} = $max + 1;
662                                                    }
663                                                    return '<span class="nick col-' .
664                                                            ( $nick_enumerator{$n} % $max_color ) .
665                                                            '">' . $n . '</span>';
666                                            },
667                                    },
668                            )
669                    );
670            }
671    
672            $html .= qq{</p>
673            <hr/>
674            <p>See <a href="/history">history</a> of all messages.</p>
675            </body></html>};
676    
677            $response->content( $html );
678            return RC_OK;
679    }
680    
681  POE::Kernel->run;  POE::Kernel->run;

Legend:
Removed from v.6  
changed lines
  Added in v.36

  ViewVC Help
Powered by ViewVC 1.1.26