1: #!/usr/bin/perl
2:
3: =pod
4:
5: =head1 NAME
6:
7: register.cgi - a universal script for club regiter
8:
9: =head1 SYNOPSIS
10:
11: register.cgi?[I<options>]
12:
13: =head1 DESCRIPTION
14:
15: The script draws the hierarchy in the form suitable for WWW
16:
17: =head1 AUTHOR
18:
19: Boris Veytsman
20:
21: =head1 DATE
22:
23: $Date: 2002/01/28 17:14:29 $
24:
25: =head1 REVISION
26:
27: $Revision: 1.11 $
28:
29: =cut
30:
31:
32: ###################################################
33: # Starting up
34: ###################################################
35:
36: use strict;
37: use vars qw(%ENV);
38: use CGI qw(:standard);
39: use DBI;
40: use POSIX qw(locale_h);
41:
42: setlocale(LC_CTYPE,'russian');
43: $ENV{'LANG'}='ru_RU.KOI8-R';
44: my ($SENDMAIL) = "mail";
45: my $TO = 'borisv@lk.net, igra@gorlovka.net, erudit@mail.od.ua';
46: my $FROM = 'borisv@lk.net';
47:
48: my $date='$Date: 2002/01/28 17:14:29 $';
49: $date =~ s/[^ ]* ([^ ]*) .*/$1/;
50:
51:
52: my $dbh = DBI->connect("DBI:mysql:chgk", "piataev", "")
53: or do {
54: print h1("Временные проблемы") . "База данных временно не
55: работает. Заходите попозже.";
56: print &Include_virtual("../dimrub/db/reklama.html");
57: print end_html;
58: die "Can't connect to DB chgk\n";
59: };
60:
61: print header(-charset=>'koi8-r');
62:
63:
64: ##################################################
65: # Printing top
66: ##################################################
67: print start_html(-"title"=>'Register of Clubs',
68: -author=>'borisv@lk.net',
69: -background=>"../images/map.jpg");
70: print &Include_virtual("../dimrub/db/reklama.html");
71: print <<END;
72: <table>
73: <tr>
74: <td background=../images/compass.gif valign=top>
75: END
76:
77: ################################################
78: # NAVIGATION PANEL
79: ################################################
80:
81: my $self=url();
82:
83:
84:
85: ###############################################
86: # The navigation panel has three special lines
87: ###############################################
88: print <<END;
89: <dl>
90: <dt><a href="$self">Home</a></dt>
91: <dt><a href="$self?rid=1&level=1000&clubs=0">Все регионы</a></dt>
92: <dt><a href="$self?rid=1&level=1000&clubs=1">Все клубы</a></dt>
93: <dt><a href="$self?addclub=1">Добавить клуб</a></dt>
94: <dt><a href="$self?whoiswho=1">Кто есть кто</a></dt>
95: END
96:
97: #################################################
98: # And the navpanel itself
99: ##################################################
100:
101: print ListRegions(dbh=>$dbh,rid=>1,level=>1,tag=>'dt',
102: self=>$self);
103:
104: print <<END;
105: </dl>
106: END
107:
108:
109:
110: print <<END;
111: </td>
112: <td width=100% valign=top>
113: END
114:
115:
116: ######################################################
117: # MAIN PANEL
118: ######################################################
119:
120: #
121: # First, we introduce ourselves
122: #
123: print <<END;
124:
125: <h1 align=center>
126: Журнал "Игра"<br>
127: и<br>
128: <a href="http:/znatoki/klub/znat.html"><img
129: ismap border=0 src= "http:../images/logo.gif"
130: alt="Интернет Клуб Что? Где? Когда?" width=319 height=27></a>
131: <br>ПРЕДСТАВЛЯЮТ<br>
132: Регистр Клубов Интеллектуальных Игр
133: </h1>
134: END
135:
136: #
137: # Now check the parameters...
138: #
139: if (param('rid')) {
140: my $rid = param('rid');
141: $rid =~ s/(\d*)/$1/;
142: print ListRegions(dbh=>$dbh,rid=>$rid,
143: level=>param('level'),
144: clubs=>param('clubs'),
145: tag=>'h2',
146: self=>$self);
147: } elsif (param('cid')) {
148: my $cid = param('cid');
149: $cid =~ s/(\d*)/$1/;
150: print ClubInfo(dbh=>$dbh,cid=>$cid,
151: self=>$self);
152: } elsif (param('pid')) {
153: my $pid = param('pid');
154: $pid =~ s/(\d*)/$1/;
155: print ListPerson(dbh=>$dbh,pid=>$pid,
156: self=>$self,
157: positions=>1,
158: displayperson=>1);
159: } elsif (param('whoiswho')) {
160: print PrintWhoIsWho(dbh=>$dbh,
161: self=>$self);
162: } elsif (param('addclub')) {
163: print AddClub();
164: } elsif (param('Submit')) {
165: print SendLetter();
166: } else {
167: print <<END;
168: <dl>
169: <dt><a href="$self?rid=1&level=1000&clubs=0">Все регионы</a></dt>
170: <dt><a href="$self?rid=1&level=1000&clubs=1">Все клубы</a></dt>
171: <dt><a href="$self?addclub=1">Добавить клуб или изменить сведения
172: о клубе</a></dt>
173: <dt><a href="$self?whoiswho=1">Кто есть кто</a></dt>
174: </dl>
175: <p align=center>
176: END
177: print &Include_virtual("../boris/register/regions.html");
178: print <<END;
179: </p>
180: END
181: }
182:
183: ####################################################################
184: # And the bottom of the page
185: ###################################################################
186: my $sth=$dbh->prepare("select count(*) from Clubs");
187: $sth->execute;
188: my ($count) = $sth->fetchrow_array;
189: $sth->finish;
190:
191: print "<p align=center>";
192: print "Всего клубов: $count<br>\n";
193: print "Эту страничку посмотрели ";
194: print `/home/piataev/public_html/cgi-bin/counter.sh /znatoki/cgi-bin/register.cgi`;
195: print " раз(а)</p>\n";
196:
197: print <<END;
198: <hr>
199: <address>
200: <img width = 60 height = 80 src="../images/owl.gif" alt = "owl">
201: <a href="http://users.lk.net/~borisv">
202: Boris Veytsman</a>, $date
203: </address>
204: </body>
205: </html>
206: END
207:
208:
209: print <<END;
210: </td>
211: </tr>
212: </table>
213: END
214:
215: print end_html;
216:
217: exit 0;
218:
219: ###################################################
220: # Parsing included file
221: ##################################################
222: sub Include_virtual {
223: my ($fn, $output) = (@_, '');
224:
225: open F , $fn
226: or return; #die "Can't open the file $fn: $!\n";
227:
228: while (<F>) {
229: if (/<!--#include/o) {
230: s/<!--#include virtual="\/(.*)" -->/&Include_virtual($1)/e;
231: }
232: if (/<!--#exec/o) {
233: s/<!--#exec.*cmd\s*=\s*"([^"]*)".*-->/`$1`/e;
234: }
235: $output .= $_;
236: }
237: return $output;
238: }
239:
240:
241:
242: #############################################################
243: # Listing the given region and optionally its children
244: #############################################################
245:
246:
247: sub ListRegions {
248: my %args = @_;
249: my $sth = $args{'dbh'}->prepare("
250: SELECT Name FROM Regions WHERE RID=$args{'rid'}");
251: $sth->execute;
252: if (!$sth->rows) {
253: return "";
254: }
255: my ($name)=$sth->fetchrow_array;
256: $name="<a href=\"$self?rid=$args{'rid'}&level=100&clubs=1\">$name</a>";
257: my $result="<$args{'tag'}>$name</$args{'tag'}>\n";
258: if ($args{'level'}>0) { # Print children
259:
260: # Frist, we print clubs
261: if ($args{'clubs'}) {
262: $result .= ListRegionURLs(%args);
263: $result .= ListClubs(%args);
264: }
265: $sth=$args{'dbh'}->prepare("
266: SELECT Child FROM RegionRegion WHERE Parent=$args{'rid'}");
267: $sth->execute;
268: if ($sth->rows) {
269: my @kids=();
270: while (my ($kid)=$sth->fetchrow_array) {
271: push @kids,"rid=$kid";
272: }
273: my $clause = join(' OR ', @kids);
274: $result .= "<dl>\n";
275: $sth=$args{'dbh'}->prepare("
276: SELECT rid FROM Regions WHERE $clause ORDER BY Name");
277: $sth->execute;
278: while (my ($kid)=$sth->fetchrow_array) {
279: $result .= ListRegions(
280: %args,'rid'=>$kid,
281: 'level'=>$args{'level'}-1,
282: 'tag'=>'dt');
283: }
284: $result .= "</dl>\n";
285: }
286: }
287: return $result;
288: }
289:
290: ############################################################
291: # List the URLs of a given region
292: ###########################################################
293: sub ListRegionURLs {
294: my %args = @_;
295: my $sth;
296: $sth = $args{'dbh'}->prepare("
297: SELECT URL FROM Regions WHERE rid=$args{'rid'} and NOT ISNULL(URL)");
298:
299: $sth->execute;
300:
301: if (!$sth->rows) {
302: return "";
303: }
304:
305: my $result;
306:
307: $result=<<END;
308: <dl><dt>Странички:</dt>
309: <dd><dl>\n
310: END
311:
312: while (my ($string)=$sth->fetchrow_array) {
313: $string=htmlize($string);
314: $result .= p($string);
315: }
316: $result .= "</dl></dd></dl>\n";
317: return $result;
318: }
319:
320:
321: ############################################################
322: # List the clubs of a given region or a given association
323: ###########################################################
324: sub ListClubs {
325: my %args = @_;
326: my $sth;
327: if ($args{'cid'}) {
328: $sth = $args{'dbh'}->prepare("
329: SELECT Child FROM ClubClub WHERE Parent=$args{'cid'}");
330: } else {
331: $sth = $args{'dbh'}->prepare("
332: SELECT cid FROM ClubRegion WHERE rid=$args{'rid'}");
333: }
334:
335: $sth->execute;
336:
337: if (!$sth->rows) {
338: return "";
339: }
340:
341: my $result;
342:
343: if ($args{'cid'}) {
344:
345: $result=<<END;
346: <h3>Клубы:</h3>
347: <dl>\n
348: END
349: } else {
350:
351: $result=<<END;
352: <dl><dt>Клубы:</dt>
353: <dd><dl>\n
354: END
355: }
356: my @clubs=();
357: while (my ($club)=$sth->fetchrow_array) {
358: push @clubs,"cid=$club";
359: }
360: my $clause = join(' OR ', @clubs);
361: $sth=$args{'dbh'}->prepare("
362: SELECT cid, Name FROM Clubs WHERE $clause ORDER BY Name");
363: $sth->execute;
364: while (my ($cid,$Name)=$sth->fetchrow_array) {
365: $result .= dt("<a href=\"$self?cid=$cid\">$Name</a>\n");
366: }
367: $result .= "</dl></dd></dl>\n";
368: }
369:
370:
371: ############################################################
372: # List the association a given club belongs to
373: ###########################################################
374: sub ListParents {
375: my %args = @_;
376: my $sth;
377:
378: $sth = $args{'dbh'}->prepare("
379: SELECT Parent FROM ClubClub WHERE Child=$args{'cid'}");
380:
381: $sth->execute;
382:
383: if (!$sth->rows) {
384: return "";
385: }
386:
387: my $result;
388:
389: $result=<<END;
390: <h3>Коллективный член ассоциаций:</h3>
391: <dl>\n
392: END
393:
394: my @clubs=();
395: while (my ($club)=$sth->fetchrow_array) {
396: push @clubs,"cid=$club";
397: }
398: my $clause = join(' OR ', @clubs);
399: $sth=$args{'dbh'}->prepare("
400: SELECT cid, Name FROM Clubs WHERE $clause ORDER BY Name");
401: $sth->execute;
402: while (my ($cid,$Name)=$sth->fetchrow_array) {
403: $result .= dt("<a href=\"$self?cid=$cid\">$Name</a>\n");
404: }
405: $result .= "</dl></dd></dl>\n";
406: }
407:
408: #############################################################
409: # The longest subroutine in the list...
410: #############################################################
411: sub ClubInfo {
412: my %args = @_;
413: my $sth = $args{'dbh'}->prepare("
414: SELECT * FROM Clubs WHERE cid=$args{'cid'}");
415: $sth->execute;
416:
417: if (!$sth->rows) {
418: return "";
419: }
420:
421: my $result="";
422: my $club=$sth->fetchrow_hashref;
423: $result .= h2($club->{'Name'});
424:
425: if (my $string=$club->{'Address'}) {
426: $string =~ s/\n/<br>\n/g;
427: $result .= h3('Адрес')."\n".p($string);
428: }
429:
430: if (my $string=$club->{'URL'}) {
431: $string = htmlize($string);
432: $result .= h3('Домашняя страничка')."\n".p($string);
433: }
434:
435: if (my $string=$club->{'Phone'}) {
436: $result .= h3('Телефон')."\n".p($string);
437: }
438:
439: if (my $string=$club->{'Fax'}) {
440: $result .= h3('Факс')."\n".p($string);
441: }
442:
443: if (my $string=$club->{'Email'}) {
444: $string = htmlize($string,'mailto:');
445: $result .= h3('E-mail')."\n".p($string);
446: }
447:
448:
449: $result .= ListPeople(%args);
450:
451: $result .= ListParents(%args);
452:
453: $result .= ListClubs(%args);
454:
455:
456: if (my $string=$club->{'DoB'}) {
457: $result .= h3('История создания клуба')."\n".p($string);
458: }
459:
460: if (my $string=$club->{'Sponsor'}) {
461: $result .= h3('Спонсор')."\n".p($string);
462: }
463:
464: if (my $string=$club->{'Meetings'}) {
465: $result .= h3('Форма деятельности клуба')."\n".p($string);
466: }
467:
468: if (my $string=$club->{'AdultTeams'}) {
469: $result .= h3('Взрослые команды')."\n".p($string);
470:
471: }
472:
473: if (my $string=$club->{'KidTeams'}) {
474: $result .= h3('Детские команды')."\n".p($string);
475:
476: }
477:
478: if (my $string=$club->{'ForeignFests'}) {
479: $result .= h3('Иногородние фестивали, традиционно посещаемые командами клуба')."\n".p($string);
480:
481: }
482:
483: if (my $string=$club->{'Braglist'}) {
484: $result .= h3('Высшие достижения команд клуба')."\n".p($string);
485:
486: }
487:
488: if (my $string=$club->{'OwnFests'}) {
489: $result .= h3('Фестивали, организуемые клубом')."\n".p($string);
490:
491: }
492:
493:
494: return $result;
495:
496: }
497:
498:
499: ##############################################################
500: # Adding a href=... The second optional argument may be
501: # 'mailto:'
502: ##############################################################
503:
504: sub htmlize {
505: my($string,$proto)=@_;
506: $string =~ s/^\s+//;
507: $string =~ s/\s+$//;
508: my @entities = split /\s+/, $string;
509: my @hrefs=map {"<a href=\"$proto$_\">$_</a>"} @entities;
510: return join(", ",@hrefs);
511: }
512:
513:
514: ##############################################################
515: # List the bosses....
516: ##############################################################
517: sub ListPeople {
518: my %args = @_;
519: my $sth = $args{'dbh'}->prepare("
520: SELECT pid,Position FROM ClubPeople WHERE cid=$args{'cid'} ORDER BY Weight DESC");
521: $sth->execute;
522:
523: if (!$sth->rows) {
524: return "";
525: }
526:
527: my $result=h3('Руководство');
528: while (my($pid,$Position)=$sth->fetchrow_array) {
529: $result .= h4($Position);
530: $result .= ListPerson(%args,pid=>$pid);
531: }
532: return $result;
533: }
534:
535: ##############################################################
536: # Listing one person
537: #############################################################
538: sub ListPerson {
539: my %args=@_;
540: my $sth = $args{'dbh'}->prepare("
541: SELECT * FROM People WHERE pid=$args{'pid'}");
542: $sth->execute;
543:
544: if (!$sth->rows) {
545: return "";
546: }
547:
548: my $result="";
549: my @entries=();
550: my $person=$sth->fetchrow_hashref;
551: if (my $string = $person->{'Name'}) {
552: if ($args{'displayperson'}) {
553: $result=h2($string);
554: } else {
555: push @entries,
556: "<a href=\"$args{'self'}?pid=$args{'pid'}\">$string</a>";
557: }
558: }
559: if (my $string=$person->{'Address'}) {
560: push @entries, "Адрес: $string";
561: }
562:
563: if (my $string=$person->{'URL'}) {
564: $string = htmlize($string);
565: push @entries, "Домашнаяя страничка: $string";
566: }
567:
568: if (my $string=$person->{'Phone'}) {
569: push @entries, "Телефон: $string";
570: }
571:
572: if (my $string=$person->{'Fax'}) {
573: push @entries, "Факс: $string";
574: }
575:
576: if (my $string=$person->{'Email'}) {
577: $string = htmlize($string,'mailto:');
578: push @entries, "E-mail: $string";
579: }
580:
581: $result.=p(join('; ',@entries).".");
582: if ($args{'positions'}) {
583: my $sth=$dbh->prepare("SELECT cid,Position FROM ClubPeople
584: WHERE pid=$args{'pid'} ORDER by Weight");
585: $sth->execute;
586: $result .= "<dl>\n";
587: while (my ($cid,$Position)=$sth->fetchrow_array) {
588: my $sth1=$dbh->prepare("Select Name from Clubs where
589: cid=$cid");
590: $sth1->execute;
591: my ($Name)=$sth1->fetchrow_array;
592: $sth1->finish;
593: $result .= "<dd><strong>$Position,</strong> ";
594: $result .= "<a href=\"$args{self}?cid=$cid\">$Name</a></dd>\n";
595: }
596: $sth->finish;
597: $result .= "</dl>\n";
598: }
599: return $result;
600:
601: }
602:
603:
604: #########################################################
605: # Adding club
606: #########################################################
607: sub AddClub {
608: my $result=h2("Добавить клуб или изменить информацию о клубе");
609:
610:
611: $result .= start_form;
612:
613: $result .= h3("Контактная информация");
614: $result .= p("Адрес, телефон, email и т.д. ниже -- НЕ адреса руководства
615: клуба (их Вы введёте ниже),
616: а официальные адреса самого клуба. Если отдельного адреса,
617: телефона, и т.д. у клуба нет, просто оставьте
618: поля пустыми");
619: $result .= table(Tr(td(["Название клуба",
620: textfield(-name=>'Name',
621: -size=>60)])),
622: Tr(td(["Официальный адрес клуба",
623: textarea(-name=>'Address',
624: -rows=>5,
625: -columns=>60)])),
626: Tr(td(["Страничка клуба",
627: textfield(-name=>'URL',
628: -size=>60)])),
629: Tr(td(["Телефон клуба",
630: textfield(-name=>'Phone',
631: -size=>60)])),
632: Tr(td(["Факс клуба",
633: textfield(-name=>'Fax',
634: -size=>60)])),
635: Tr(td(["E-mail клуба",
636: textfield(-name=>'Email',
637: -size=>60)])),
638: );
639: $result .= h3("Руководство клуба");
640: $result .= p("Адреса и телефоны ниже будут опубликованы. Если Вы не хотите
641: афишировать чьи-то адреса и телефоны, просто оставьте соответствующие поля
642: пустыми");
643: $result .= "<ol>\n";
644: for(my $i=1;$i<=5;$i++) {
645: $result .=li;
646: $result .= table(
647:
648: Tr(td(["Должность",
649: textfield(-name=>"Position$i",
650: -size=>50)])),
651: Tr(td(["ФИО",
652: textfield(-name=>"Name$i",
653: -size=>50)])),
654: Tr(td(["Адрес",
655: textarea(-name=>"Address$i",
656: -columns=>50,
657: -rows=>5)])),
658: Tr(td(["Телефон",
659: textfield(-name=>"Phone$i",
660: -size=>50)])),
661: Tr(td(["Факс",
662: textfield(-name=>"Fax$i",
663: -size=>50)])),
664: Tr(td(["Email",
665: textfield(-name=>"Email$i",
666: -size=>50)])),
667: Tr(td(["Домашняя страничка",
668: textfield(-name=>"URL$i",
669: -size=>50)])),
670: );
671: }
672: $result .= "</ol>\n";
673: $result .= h3("Ассоциации и объединения");
674: $result .= table(
675: Tr(td(["Ассоциации, членом котрых является клуб",
676: textarea(-name=>'Parents',
677: -rows=>5,
678: -columns=>60)])),
679: Tr(td(["Для ассоциаций: коллективные члены ассоциации",
680: textarea(-name=>'Members',
681: -rows=>5,
682: -columns=>60)])),
683: );
684: $result .= h3("Жизнь клуба");
685: $result .= table(
686: Tr(td(["История создания клуба",
687: textarea(-name=>'DoB',
688: -rows=>5,
689: -columns=>60)])),
690: Tr(td(["Основной спонсор клуба",
691: textarea(-name=>'Sponsor',
692: -rows=>5,
693: -columns=>60)])),
694: Tr(td(["Основные формы деятельности клуба",
695: textarea(-name=>'Meetings',
696: -rows=>5,
697: -columns=>60)])),
698: Tr(td(["Взрослые команды",
699: textarea(-name=>'AdultTeams',
700: -rows=>5,
701: -columns=>60)])),
702: Tr(td(["Детские команды",
703: textarea(-name=>'KidTeams',
704: -rows=>5,
705: -columns=>60)])),
706: Tr(td(["Иногородние фестивали, на которые ездят команды клуба",
707: textarea(-name=>'ForeignFests',
708: -rows=>5,
709: -columns=>60)])),
710: Tr(td(["Высшие достижения команд клуба",
711: textarea(-name=>'Braglist',
712: -rows=>5,
713: -columns=>60)])),
714: Tr(td(["Фестивали, которые организовывает клуб",
715: textarea(-name=>'OwnFests',
716: -rows=>5,
717: -columns=>60)])),
718: );
719:
720: $result .= h3("География клуба (для будущей карты)");
721: $result .= table(
722: Tr(td(["Долгота",
723: textfield(-name=>"Longitude",
724: -size=> 60)])),
725: Tr(td(["Широта",
726: textfield(-name=>"Latitude",
727: -size=> 60)])),
728: );
729:
730: $result .= h3("Дополнительные вопросы");
731: $result .= table(
732:
733: Tr(td(["Что вам больше всего нравится в журнале 'Игра'?",
734: textarea(-name=>'IgraA',
735: -rows=>5,
736: -columns=>60)])),
737: Tr(td(["Что вам больше всего не нравится в журнале 'Игра'?",
738: textarea(-name=>'IgraB',
739: -rows=>5,
740: -columns=>60)])),
741: Tr(td(["Что бы вы хотели увидеть в журнале 'Игра' - то
742: чего нет в настоящее время?",
743: textarea(-name=>'IgraC',
744: -rows=>5,
745: -columns=>60)])),
746: );
747:
748: $result .= h3("Кто регистрировал");
749: $result .= table(
750: Tr(td(["Имя",
751: textfield(-name=>'RegistrarName',
752: -size=>60)])),
753: Tr(td(["Email",
754: textfield(-name=>'RegistrarEmail',
755: -size=>60)])),
756: );
757:
758: $result .= p("Нажав кнопку 'Submit', Вы отправите Вашу регистрационную
759: карточку службе поддержки регистра. Пожалуйста, подождите несколько дней, пока
760: Ваша информация будет обработана и попадёт в регистр");
761: $result .= submit(-name=>'Submit');
762: $result .= end_form;
763: return $result;
764: }
765:
766: ###################################################################
767: # Sending the letter with results
768: #####################################################################
769: sub SendLetter {
770: open(MAIL,"| $SENDMAIL -s 'Registracionnaya kartochka kluba' $TO");
771: print MAIL <<END;
772: MIME-Version: 1.0
773: Content-type: text/plain; charset=koi8-r
774:
775: END
776: foreach my $key (param) {
777: my $value = param($key);
778: if ($value =~ /^\s*$/) {
779: next;
780: }
781: print MAIL "$key=$value\n\n";
782: }
783:
784:
785: close MAIL;
786: return p("Спасибо за регистрацию. Ваши данные приняты и после ".
787: "обработки будут внесены в базу данных");
788: }
789:
790: ###############################################################
791: # Printing Who is Who list
792: ###############################################################
793: sub PrintWhoIsWho {
794: my %args =@_;
795: my $result = h2("Кто есть кто");
796: $result .= "\n<dl>\n";
797: my $sth = $dbh->prepare("SELECT pid,Name FROM People ORDER BY Name");
798: $sth->execute;
799: while (my($pid,$Name)=$sth->fetchrow_array) {
800: $result .= dd("<a href=\"$args{'self'}?pid=$pid\">$Name</a>");
801: $result .= "\n";
802: }
803: $sth->finish;
804: $result .= "</dl>\n";
805: return $result;
806: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>