]> git.donarmstrong.com Git - infobot.git/blob - src/Modules/Factoids.pl
* Add vim formatting comments ( # vim:ts=4:sw=4:expandtab:tw=80 )
[infobot.git] / src / Modules / Factoids.pl
1 #
2 #  Factoids.pl: Helpers for generating factoids statistics.
3 #       Author: dms
4 #      Version: v0.1 (20000514)
5 #     Splitted: SQLExtras.pl
6 #
7
8 use strict;
9
10 use vars qw($dbh $who);
11 use vars qw(%param);
12
13 ###
14 # Usage: &CmdFactInfo($faqtoid, $query);
15 sub CmdFactInfo {
16     my ($faqtoid, $query) = (lc $_[0], $_[1]);
17     my @array;
18     my $string = '';
19
20     if ($faqtoid eq '') {
21         &help('factinfo');
22         return;
23     }
24
25     my %factinfo = &sqlSelectRowHash('factoids', '*',
26         { factoid_key => $faqtoid }
27     );
28
29     # factoid does not exist.
30     if (scalar (keys %factinfo) <= 1) {
31         &performReply("there's no such factoid as \002$faqtoid\002");
32         return;
33     }
34
35     # fix for problem observed by asuffield.
36     # why did it happen though?
37     if (!$factinfo{'factoid_value'}) {
38         &performReply("there's no such factoid as \002$faqtoid\002; deleted because we don't have factoid_value!");
39         foreach (keys %factinfo) {
40             &DEBUG("factinfo{$_} => '$factinfo{$_}'.");
41         }
42 ###     &delFactoid($faqtoid);
43         return;
44     }
45
46     # created:
47     if ($factinfo{'created_by'}) {
48
49         $factinfo{'created_by'} =~ s/\!/ </;
50         $factinfo{'created_by'} .= '>';
51         $string  = "created by $factinfo{'created_by'}";
52
53         my $time = $factinfo{'created_time'};
54         if ($time) {
55             if (time() - $time > 60*60*24*7) {
56                 my $days = int( (time() - $time)/60/60/24 );
57                 $string .= " at \037". scalar(gmtime $time). "\037" .
58                                 " ($days days)";
59             } else {
60                 $string .= ' '.&Time2String(time() - $time).' ago';
61             }
62         }
63
64         push(@array,$string);
65     }
66
67     # modified: (TimRiker asks: why do you keep turning this off?)
68     if ($factinfo{'modified_by'}) {
69         $string = 'last modified';
70
71         my $time = $factinfo{'modified_time'};
72         if ($time) {
73             if (time() - $time > 60*60*24*7) {
74                 $string .= " at \037". scalar(gmtime $time). "\037";
75             } else {
76                 $string .= ' '.&Time2String(time() - $time).' ago ';
77             }
78         }
79
80         $string .= ' by '.(split ',', $factinfo{'modified_by'})[0];
81
82         push(@array,$string);
83     }
84
85     # requested:
86     if ($factinfo{'requested_by'}) {
87         my $requested_count = $factinfo{'requested_count'};
88
89         if ($requested_count) {
90             $string  = 'it has been requested ';
91             if ($requested_count == 1) {
92                 $string .= "\002once\002";
93             } else {
94                 $string .= "\002". $requested_count. "\002 ".
95                         &fixPlural('time', $requested_count);
96             }
97
98             my $requested_by = $factinfo{'requested_by'};
99             $requested_by =~ /\!/;
100             $string .= ", last by $`";
101
102             my $requested_time = $factinfo{'requested_time'};
103             if ($requested_time) {
104                 if (time() - $requested_time > 60*60*24*7) {
105                     $string .= " at \037". scalar(localtime $requested_time). "\037";
106                 } else {
107                     $string .= ', '.&Time2String(time() - $requested_time).' ago';
108                 }
109             }
110         } else {
111             $string  = 'has not been requested yet';
112         }
113
114         push(@array, $string);
115     }
116
117     # locked:
118     if ($factinfo{'locked_by'}) {
119         $factinfo{'locked_by'} =~ /\!/;
120         $string = "it has been locked by $`";
121
122         push(@array, $string);
123     }
124
125     # factoid was inserted not through the bot.
126     if (!scalar @array) {
127         &performReply("no extra info on \002$faqtoid\002");
128         return;
129     }
130
131     &performStrictReply("$factinfo{'factoid_key'} -- ". join('; ', @array) .'.');
132     return;
133 }
134
135 sub CmdFactStats {
136     my ($type) = @_;
137
138     if ($type =~ /^author$/i) {
139         my %hash = &sqlSelectColHash('factoids',
140                 'factoid_key,created_by', undef,
141                 'WHERE created_by IS NOT NULL'
142         );
143         my %author;
144
145         foreach my $factoid (keys %hash) {
146             my $thisnuh = $hash{$factoid};
147
148             $thisnuh =~ /^(\S+)!\S+@\S+$/;
149             $author{lc $1}++;
150         }
151
152         if (!scalar keys %author) {
153             return 'sorry, no factoids with created_by field.';
154         }
155
156         # work-around.
157         my %count;
158         foreach (keys %author) {
159             $count{ $author{$_} }{$_} = 1;
160         }
161         undef %author;
162
163         my $count;
164         my @list;
165         foreach $count (sort { $b <=> $a } keys %count) {
166             my $author = join(', ', sort keys %{ $count{$count} });
167             push(@list, "$count by $author");
168         }
169
170         my $prefix = 'factoid statistics by author: ';
171         return &formListReply(0, $prefix, @list);
172
173     } elsif ($type =~ /^vandalism$/i) {
174         &status('factstats(vandalism): starting...');
175         my $start_time  = &timeget();
176         my %data        = &sqlSelectColHash('factoids',
177                 'factoid_key,factoid_value', undef,
178                 'WHERE factoid_value IS NOT NULL'
179         );
180         my @list;
181
182         my $delta_time  = &timedelta($start_time);
183         &status(sprintf('factstats(vandalism): %.02f sec to retreive all factoids.', $delta_time)) if ($delta_time > 0);
184         $start_time     = &timeget();
185
186         # parse the factoids.
187         foreach (keys %data) {
188             if (&validFactoid($_, $data{$_}) == 0) {
189                 s/([\,\;]+)/\037$1\037/g;       # highlight chars.
190                 push(@list, $_);                # push it.
191             }
192         }
193
194         $delta_time     = &timedelta($start_time);
195         &status(sprintf('factstats(vandalism): %.02f sec to complete.', $delta_time)) if ($delta_time > 0);
196
197         # bail out on no results.
198         if (scalar @list == 0) {
199             return 'no vandalised factoids... wooohoo.';
200         }
201
202         # parse the results.
203         my $prefix = 'Vandalised factoid ';
204         return &formListReply(1, $prefix, @list);
205
206     } elsif ($type =~ /^total$/i) {
207         &status('factstats(total): starting...');
208         my $start_time  = &timeget();
209         my @list;
210         my $str;
211         my($i,$j);
212         my %hash;
213
214         ### lets do it.
215         # total factoids requests.
216         $i = &sumKey('factoids', 'requested_count');
217         push(@list, "total requests - $i");
218
219         # total factoids modified.
220         $str = &countKeys('factoids', 'modified_by');
221         push(@list, "total modified - $str");
222
223         # total factoids modified.
224         $j      = &countKeys('factoids', 'requested_count');
225         $str    = &countKeys('factoids', 'factoid_key');
226         push(@list, 'total non-requested - '.($str - $i));
227
228         # average request/factoid.
229         # i/j == total(requested_count)/count(requested_count)
230         $str = sprintf('%.01f', $i/$j);
231         push(@list, "average requested per factoid - $str");
232
233         # total prepared for deletion.
234         $str    = scalar( &searchTable('factoids', 'factoid_key', 'factoid_value', ' #DEL') );
235         push(@list, "total prepared for deletion - $str");
236
237         # total unique authors.
238         # TODO: convert to sqlSelectColHash ? (or ColArray?)
239         foreach ( &sqlRawReturn('SELECT created_by FROM factoids WHERE created_by IS NOT NULL') ) {
240             /^(\S+)!/;
241             my $nick = lc $1;
242             $hash{$nick}++;
243         }
244         push(@list, 'total unique authors - '.(scalar keys %hash) );
245         undef %hash;
246
247         # total unique requesters.
248         foreach ( &sqlRawReturn('SELECT requested_by FROM factoids WHERE requested_by IS NOT NULL') ) {
249             /^(\S+)!/;
250             my $nick = lc $1;
251             $hash{$nick}++;
252         }
253         push(@list, 'total unique requesters - '.(scalar keys %hash) );
254         undef %hash;
255
256         ### end of 'job'.
257
258         my $delta_time  = &timedelta($start_time);
259         &status(sprintf('factstats(broken): %.02f sec to retreive all factoids.', $delta_time)) if ($delta_time > 0);
260         $start_time     = &timeget();
261
262         # bail out on no results.
263         if (scalar @list == 0) {
264             return 'no broken factoids... wooohoo.';
265         }
266
267         # parse the results.
268         my $prefix = 'General factoid statistics ';
269         return &formListReply(1, $prefix, @list);
270
271     } elsif ($type =~ /^deadredir$/i) {
272         my @list = &searchTable('factoids', 'factoid_key',
273                         'factoid_value', '^<REPLY> see ');
274         my %redir;
275         my $f;
276
277         for (@list) {
278             my $factoid = $_;
279             my $val = &getFactInfo($factoid, 'factoid_value');
280             if ($val =~ /^<REPLY> ?see( also)? (.*?)\.?$/i) {
281                 my $redirf = lc $2;
282                 my $redir = &getFactInfo($redirf, 'factoid_value');
283                 next if (defined $redir);
284                 next if (length $val > 50);
285
286                 $redir{$redirf}{$factoid} = 1;
287             }
288         }
289
290         my @newlist;
291         foreach $f (keys %redir) {
292             my @sublist = keys %{ $redir{$f} };
293             for (@sublist) {
294                 s/([\,\;]+)/\037$1\037/g;
295             }
296
297             push(@newlist, join(', ', @sublist)." => $f");
298         }
299
300         # parse the results.
301         my $prefix = 'Loose link (dead) redirections in factoids ';
302         return &formListReply(1, $prefix, @newlist);
303
304     } elsif ($type =~ /^dup(licate|e)$/i) {
305         &status('factstats(dupe): starting...');
306         my $start_time  = &timeget();
307         my %hash        = &sqlSelectColHash('factoids',
308                 'factoid_key,factoid_value', undef,
309                 'WHERE factoid_value IS NOT NULL', 1
310         );
311         my $refs        = 0;
312         my @list;
313         my $v;
314
315         foreach $v (keys %hash) {
316             my $count = scalar(keys %{ $hash{$v} });
317             next if ($count == 1);
318
319             my @sublist;
320             foreach (keys %{ $hash{$v} }) {
321                 if ($v =~ /^<REPLY> see /i) {
322                     $refs++;
323                     next;
324                 }
325
326                 s/([\,\;]+)/\037$1\037/g;
327                 if ($_ eq '') {
328                     &WARN('dupe: _ = NULL. should never happen!.');
329                     next;
330                 }
331                 push(@sublist, $_);
332             }
333
334             next unless (scalar @sublist);
335
336             push(@list, join(', ', @sublist));
337         }
338
339         &status("factstats(dupe): (good) dupe refs: $refs.");
340         my $delta_time  = &timedelta($start_time);
341         &status(sprintf('factstats(dupe): %.02f sec to complete', $delta_time)) if ($delta_time > 0);
342
343         # bail out on no results.
344         if (scalar @list == 0) {
345             return 'no duplicate factoids... woohoo.';
346         }
347
348         # parse the results.
349         my $prefix = 'dupe factoid ';
350         return &formListReply(1, $prefix, @list);
351
352     } elsif ($type =~ /^nullfactoids$/i) {
353         my $query = "SELECT factoid_key,factoid_value FROM factoids WHERE factoid_value=''";
354         my $sth = $dbh->prepare($query);
355         &ERROR("factstats(null): => '$query'.") unless $sth->execute;
356
357         my @list;
358         while (my @row = $sth->fetchrow_array) {
359             if ($row[1] ne '') {
360                 &DEBUG("row[1] != NULL for $row[0].");
361                 next;
362             }
363
364             &DEBUG("row[0] => '$row[0]'.");
365             push(@list, $row[0]);
366         }
367         $sth->finish;
368
369         # parse the results.
370         my $prefix = 'NULL factoids (not deleted yet) ';
371         return &formListReply(1, $prefix, @list);
372
373     } elsif ($type =~ /^(2|too)short$/i) {
374         # Custom select statement.
375         my $query = 'SELECT factoid_key,factoid_value FROM factoids WHERE length(factoid_value) <= 40';
376         my $sth = $dbh->prepare($query);
377         &ERROR("factstats(lame): => '$query'.") unless $sth->execute;
378
379         my @list;
380         while (my @row = $sth->fetchrow_array) {
381             my($key,$val) = ($row[0], $row[1]);
382             my $match = 0;
383             $match++ if ($val =~ /\s{3,}/);
384             next unless ($match);
385
386             my $v = &getFactoid($val);
387             if (defined $v) {
388                 &DEBUG("key $key => $val => $v");
389             }
390
391             $key =~ s/\,/\037\,\037/g;
392             push(@list, $key);
393         }
394         $sth->finish;
395
396         # parse the results.
397         my $prefix = 'Lame factoids ';
398         return &formListReply(1, $prefix, @list);
399
400     } elsif ($type =~ /^listfix$/i) {
401         # Custom select statement.
402         my $query = 'SELECT factoid_key,factoid_value FROM factoids';
403         my $sth = $dbh->prepare($query);
404         &ERROR("factstats(listfix): => '$query'.") unless $sth->execute;
405
406         my @list;
407         while (my @row = $sth->fetchrow_array) {
408             my($key,$val) = ($row[0], $row[1]);
409             my $match = 0;
410             $match++ if ($val =~ /\S+,? or \S+,? or \S+,? or \S+,?/);
411             next unless ($match);
412
413             $key =~ s/\,/\037\,\037/g;
414             push(@list, $key);
415             $val =~ s/,? or /, /g;
416             &DEBUG("fixed: => $val.");
417             &setFactInfo($key,'factoid_value', $val);
418         }
419         $sth->finish;
420
421         # parse the results.
422         my $prefix = 'Inefficient lists fixed ';
423         return &formListReply(1, $prefix, @list);
424
425     } elsif ($type =~ /^locked$/i) {
426         my %hash = &sqlSelectColHash('factoids',
427                 'factoid_key,locked_by', undef,
428                 'WHERE locked_by IS NOT NULL'
429         );
430         my @list = keys %hash;
431
432         for (@list) {
433             s/([\,\;]+)/\037$1\037/g;
434         }
435
436         my $prefix = "factoid statistics on $type ";
437         return &formListReply(0, $prefix, @list);
438
439     } elsif ($type =~ /^new$/i) {
440         my %hash = &sqlSelectColHash('factoids',
441                 'factoid_key,created_time', undef,
442                 'WHERE created_time IS NOT NULL'
443         );
444         my %age;
445
446         foreach (keys %hash) {
447             my $created_time = $hash{$_};
448             my $delta_time   = time() - $created_time;
449             next if ($delta_time >= 60*60*24);
450
451             $age{$delta_time}{$_} = 1;
452         }
453
454         if (scalar keys %age == 0) {
455             return 'sorry, no new factoids.';
456         }
457
458         my @list;
459         foreach (sort {$a <=> $b} keys %age) {
460             push(@list, join(',', keys %{ $age{$_} }));
461         }
462
463         my $prefix = 'new factoids in the last 24hours ';
464         return &formListReply(0, $prefix, @list);
465
466     } elsif ($type =~ /^part(ial)?dupe$/i) {
467         ### requires 'custom' select statement... oh well...
468         my $start_time  = &timeget();
469
470         # form length|key and key=length hash list.
471         &status('factstats(partdupe): forming length hash list.');
472         my $query = 'SELECT factoid_key,factoid_value,length(factoid_value) AS length FROM factoids WHERE length(factoid_value) >= 192 ORDER BY length';
473         my $sth = $dbh->prepare($query);
474         &ERROR("factstats(partdupe): => '$query'.") unless $sth->execute;
475
476         my (@key, @list);
477         my (%key, %length);
478         while (my @row = $sth->fetchrow_array) {
479             $length{$row[2]}{$row[0]} = 1;      # length(value)|key.
480             $key{$row[0]} = $row[1];            # key=value.
481             push(@key, $row[0]);
482         }
483         $sth->finish;
484         &status("factstats(partdupe): total keys => '". scalar(@key) ."'.");
485         &status('factstats(partdupe): now deciphering data gathered');
486
487         my @length = sort { $a <=> $b } keys %length;
488         my $key;
489
490         foreach $key (@key) {
491             shift @length if (length $key{$key} == $length[0]);
492
493             my $val = quotemeta $key{$key};
494             my @sublist;
495             my $length;
496             foreach $length (@length) {
497                 foreach (keys %{ $length{$length} }) {
498                     if ($key{$_} =~ /^$val/i) {
499                         s/([\,\;]+)/\037$1\037/g;
500                         s/( and|and )/\037$1\037/g;
501                         push(@sublist,$key.' and '.$_);
502                     }
503                 }
504             }
505             push(@list, join(' ,',@sublist)) if (scalar @sublist);
506         }
507
508         my $delta_time = sprintf('%.02fs', &timedelta($start_time) );
509         &status("factstats(partdupe): $delta_time sec to complete.") if ($delta_time > 0);
510
511         # bail out on no results.
512         if (scalar @list == 0) {
513             return 'no initial partial duplicate factoids... woohoo.';
514         }
515
516         # parse the results.
517         my $prefix = 'initial partial dupe factoid ';
518         return &formListReply(1, $prefix, @list);
519
520     } elsif ($type =~ /^profanity$/i) {
521         my %data = &sqlSelectColHash('factoids',
522                 'factoid_key,factoid_value', undef,
523                 'WHERE factoid_value IS NOT NULL'
524         );
525         my @list;
526
527         foreach (keys %data) {
528             push(@list, $_) if (&hasProfanity($_.' '.$data{$_}));
529         }
530
531         # parse the results.
532         my $prefix = 'Profanity in factoids ';
533         return &formListReply(1, $prefix, @list);
534
535     } elsif ($type =~ /^redir(ection)?$/i) {
536         my @list = &searchTable('factoids', 'factoid_key',
537                         'factoid_value', '^<REPLY> see ');
538         my %redir;
539         my $f;
540         my $dangling = 0;
541
542         for (@list) {
543             my $factoid = $_;
544             my $val = &getFactInfo($factoid, 'factoid_value');
545             if ($val =~ /^<REPLY> see( also)? (.*?)\.?$/i) {
546                 my $redir       = lc $2;
547                 my $redirval    = &getFactInfo($redir, 'factoid_value');
548                 if (defined $redirval) {
549                     $redir{$redir}{$factoid} = 1;
550                 } else {
551                     &DEBUG("factstats(redir): '$factoid' has loose link => '$redir'.");
552                     $dangling++;
553                 }
554             }
555         }
556
557         my @newlist;
558         foreach $f (keys %redir) {
559             my @sublist = keys %{ $redir{$f} };
560             for (@sublist) {
561                 s/([\,\;]+)/\037$1\037/g;
562             }
563
564             push(@newlist, "$f => ". join(', ', @sublist));
565         }
566
567         # parse the results.
568         my $prefix = "Redirections in factoids, $dangling dangling ";
569         return &formListReply(1, $prefix, @newlist);
570
571     } elsif ($type =~ /^request(ed)?$/i) {
572         my %hash = &sqlSelectColHash('factoids',
573                 'factoid_key,requested_count', undef,
574                 'WHERE requested_count IS NOT NULL', 1
575         );
576
577         if (!scalar keys %hash) {
578             return 'sorry, no factoids have been questioned.';
579         }
580
581         my $count;
582         my @list;
583         my $total       = 0;
584         foreach $count (sort {$b <=> $a} keys %hash) {
585             my @faqtoids = sort keys %{ $hash{$count} };
586
587             for (@faqtoids) {
588                 s/([\,\;]+)/\037$1\037/g;
589             }
590             $total      += $count * scalar(@faqtoids);
591
592             push(@list, "$count - ". join(', ', @faqtoids));
593         }
594         unshift(@list, "\037$total - TOTAL\037");
595
596         my $prefix = "factoid statistics on $type ";
597         return &formListReply(0, $prefix, @list);
598
599     } elsif ($type =~ /^reqrate$/i) {
600         my %hash = &sqlSelectColHash('factoids',
601                 "factoid_key,(unix_timestamp() - created_time)/requested_count as rate", undef,
602                 'WHERE requested_by IS NOT NULL and created_time IS NOT NULL ORDER BY rate LIMIT 15', 1
603         );
604
605         my $rate;
606         my @list;
607         my $total       = 0;
608         my $users       = 0;
609         foreach $rate (sort { $b <=> $a } keys %hash) {
610             my $f       = join(', ', sort keys %{ $hash{$rate} });
611             my $str     = "$f - ".&Time2String($rate);
612             $str        =~ s/\002//g;
613             push(@list, $str);
614         }
615
616         my $prefix = "Rank of top factoid rate (time/req): ";
617         return &formListReply(0, $prefix, @list);
618
619     } elsif ($type =~ /^requesters?$/i) {
620         my %hash = &sqlSelectColHash('factoids',
621                 'factoid_key,requested_by', undef,
622                 'WHERE requested_by IS NOT NULL'
623         );
624         my %requester;
625
626         foreach (keys %hash) {
627             my $thisnuh = $hash{$_};
628
629             $thisnuh =~ /^(\S+)!\S+@\S+$/;
630             $requester{lc $1}++;
631         }
632
633         if (!scalar keys %requester) {
634             return 'sorry, no factoids with requested_by field.';
635         }
636
637         # work-around.
638         my %count;
639         foreach (keys %requester) {
640             $count{ $requester{$_} }{$_} = 1;
641         }
642         undef %requester;
643
644         my $count;
645         my @list;
646         my $total       = 0;
647         my $users       = 0;
648         foreach $count (sort { $b <=> $a } keys %count) {
649             my $requester = join(', ', sort keys %{ $count{$count} });
650             $total      += $count * scalar(keys %{ $count{$count} });
651             $users      += scalar(keys %{ $count{$count} });
652             push(@list, "$count by $requester");
653         }
654         unshift(@list, "\037$total TOTAL REQUESTS; $users UNIQUE REQUESTERS\037");
655         # should not the above value be the same as collected by
656         # 'requested'? soemthing weird is going on!
657
658         my $prefix = 'rank of top factoid requesters: ';
659         return &formListReply(0, $prefix, @list);
660
661     } elsif ($type =~ /^seefix$/i) {
662         my @list = &searchTable('factoids', 'factoid_key',
663                         'factoid_value', '^see ');
664         my @newlist;
665         my $fixed = 0;
666         my %loop;
667         my $f;
668
669         for (@list) {
670             my $factoid = $_;
671             my $val = &getFactInfo($factoid, 'factoid_value');
672
673             next unless ($val =~ /^see( also)? (.*?)\.?$/i);
674
675             my $redirf  = lc $2;
676             my $redir   = &getFactInfo($redirf, 'factoid_value');
677
678             if ($redirf =~ /^\Q$factoid\W$/i) {
679                 &delFactoid($factoid);
680                 $loop{$factoid} = 1;
681             }
682
683             if (defined $redir) {       # good.
684                 &setFactInfo($factoid,'factoid_value',"<REPLY> see $redir");
685                 $fixed++;
686             } else {
687                 push(@newlist, $redirf);
688             }
689         }
690
691         # parse the results.
692         &msg($who, "Fixed $fixed factoids.");
693         &msg($who, 'Self looped factoids removed: '. keys %loop ) if (scalar keys %loop);
694
695         my $prefix = "Loose link (dead) redirections in factoids ";
696         return &formListReply(1, $prefix, @newlist);
697
698     } elsif ($type =~ /^(2|too)long$/i) {
699         my @list;
700         my $query;
701
702         # factoid_key.
703         $query = "SELECT factoid_key FROM factoids WHERE length(factoid_key) >= $param{'maxKeySize'}";
704         my $sth = $dbh->prepare($query);
705         $sth->execute;
706         while (my @row = $sth->fetchrow_array) {
707             push(@list,$row[0]);
708         }
709         $sth->finish;
710
711         # factoid_value.
712         $query = "SELECT factoid_key,factoid_value FROM factoids WHERE length(factoid_value) >= $param{'maxDataSize'}";
713         $sth = $dbh->prepare($query);
714         $sth->execute;
715         while (my @row = $sth->fetchrow_array) {
716             push(@list,sprintf("\002%s\002 - %s", length($row[1]), $row[0]));
717         }
718         $sth->finish;
719
720         if (scalar @list == 0) {
721             return 'good. no factoids exceed length.';
722         }
723
724         # parse the results.
725         my $prefix = 'factoid key||value exceeding length ';
726         return &formListReply(1, $prefix, @list);
727
728     } elsif ($type =~ /^unrequest(ed)?$/i) {
729         # TODO: use sqlSelect()
730         my ($count) = &sqlRawReturn("SELECT COUNT(*) FROM factoids WHERE requested_count = '0'");
731
732         return "Unrequested factoids: $count";
733     }
734
735     return "error: invalid type => '$type'.";
736 }
737
738 sub CmdListAuth {
739     my ($query) = @_;
740     my $maxshow = &::getChanConfDefault('maxListReplyCount', 15, $chan);
741     my @list = &searchTable('factoids','factoid_key', 'created_by', "^$query!");
742     @list=grep(!/\#DEL\#$/,@list) if (scalar(@list) > $maxshow);
743
744     my $prefix = "factoid author list by '$query' ";
745     &performStrictReply( &formListReply(1, $prefix, @list) );
746 }
747
748 1;
749
750 # vim:ts=4:sw=4:expandtab:tw=80