File:  [LON-CAPA] / loncom / interface / lonviewclasslist.pm
Revision 1.20: download - view: text, annotated - select for diffs
Wed Sep 27 14:52:27 2023 UTC (7 months, 1 week ago) by raeburn
Branches: MAIN
CVS tags: version_2_11_4_msu, HEAD
- No breadcrumbs trail in modal pop-up when previewing aboutme, syllabus,
  roster, and pdf documents from links in Course Editor.
- Breadcrumbs trails for "Supplemental" and "Main" content more consistent:
  - No Main Menu link as first item if symb or folderpath available
  - No Return to Last location link/icon if symb or folderpath available
- Don't set supplementalflag to 1 for documents uploaded to Main Content
  area which require "showdoc", so breadcrumb trail is available to students.

    1: # The LearningOnline Network with CAPA
    2: # Handler to display the classlist 
    3: #
    4: # $Id: lonviewclasslist.pm,v 1.20 2023/09/27 14:52:27 raeburn Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: #
   10: # LON-CAPA is free software; you can redistribute it and/or modify
   11: # it under the terms of the GNU General Public License as published by
   12: # the Free Software Foundation; either version 2 of the License, or
   13: # (at your option) any later version.
   14: #
   15: # LON-CAPA is distributed in the hope that it will be useful,
   16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18: # GNU General Public License for more details.
   19: #
   20: # You should have received a copy of the GNU General Public License
   21: # along with LON-CAPA; if not, write to the Free Software
   22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   23: #
   24: # /home/httpd/html/adm/gpl.txt
   25: #
   26: # http://www.lon-capa.org/
   27: #
   28: ###############################################################
   29: ##############################################################
   30: 
   31: package Apache::lonviewclasslist;
   32: 
   33: use strict;
   34: use Apache::loncoursedata();
   35: use Apache::loncommon();
   36: use Apache::lonhtmlcommon();
   37: use Apache::courseprefs();
   38: use Apache::Constants qw(:common :http REDIRECT);
   39: use Apache::lonlocal;
   40: use Apache::lonnet;
   41: 
   42: 
   43: ###################################################################
   44: ###################################################################
   45: 
   46: =pod
   47: 
   48: =item &handler
   49: 
   50: The typical handler you see in all these modules.  Takes $r, the
   51: http request, as an argument.  
   52: 
   53: =cut
   54: 
   55: ###################################################################
   56: ###################################################################
   57: sub handler {
   58:     my $r=shift;
   59:     if ($r->header_only) {
   60:         &Apache::loncommon::content_type($r,'text/html');
   61:         $r->send_http_header;
   62:         return OK;
   63:     }
   64:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
   65:                                  ['register','forceedit','action',
   66:                                   'symb','todocs','only_body']);
   67:     if (! ($env{'request.course.fn'})) {
   68:         $env{'user.error.msg'}=
   69:             "/adm/viewclasslist:not in course role";
   70:         return HTTP_NOT_ACCEPTABLE; 
   71:     }
   72:     &Apache::loncommon::content_type($r,'text/html');
   73:     $r->send_http_header;
   74:     #
   75:     my $start_page;
   76:     if ($env{'form.register'}) {
   77:         $start_page = &Apache::loncommon::start_page('Classlist',undef,
   78:                              {'force_register' => $env{'form.register'}});
   79:     } else {
   80:         my $args = {};
   81:         if ($env{'form.only_body'}) {
   82:             $args->{'only_body'} = 1;
   83:         } else {
   84:             my $brcrum = [{'href' => 'adm/viewclasslist',
   85:                            'text' => 'View Classlist'},];
   86:             $args->{'bread_crumbs'} = $brcrum;
   87:         }
   88:         $start_page = &Apache::loncommon::start_page('Classlist',undef,
   89:                                                      $args);
   90:     }
   91:     $r->print(<<ENDHEADER);
   92: $start_page
   93: ENDHEADER
   94: 
   95:     # Get classlist view settings
   96:     my %viewsettings = &retrieve_view_settings();
   97:     my $crstype = &Apache::loncommon::course_type();
   98: 
   99:     if (($env{'form.forceedit'}) || ($env{'form.action'} eq 'setconfig'))  {
  100:         if (&Apache::lonnet::allowed('opa',$env{'request.course.id'})) {
  101:             my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
  102:             my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
  103:             my $rosterprefs = &roster_prefs($crstype);
  104:             my $allitems = {};
  105:             if ($env{'form.action'} eq 'setconfig') {
  106:                 my %values=&Apache::lonnet::dump('environment',$cdom,$cnum);
  107:                 if (keys(%values) > 0) {
  108:                     my ($numchanged,%changes,%disallowed);
  109:                     my $prefs = {
  110:                                     classlists => $rosterprefs,
  111:                                 };
  112:                     $changes{'classlists'} = {};
  113:                     &Apache::courseprefs::process_changes($cdom,$cnum,'classlists',\%values,
  114:                                                           $rosterprefs,
  115:                                                           $changes{'classlists'},
  116:                                                           $allitems,\%disallowed,$crstype);
  117:                     my $message;
  118:                     if (keys(%{$changes{'classlists'}}) > 0) {
  119:                         my $actions = ['classlists'];
  120:                         $message =
  121:                             &Apache::courseprefs::store_changes($cdom,$cnum,$actions,
  122:                                                                 $actions,$prefs,\%values,
  123:                                                                 \%changes,$crstype);
  124:                     } else {
  125:                         if ($crstype eq 'Community') {
  126:                             $message = &mt('No changes made to community settings.');
  127:                         } else {
  128:                             $message = &mt('No changes made to course settings.');
  129:                         }
  130:                     }
  131:                     $r->print(&Apache::loncommon::confirmwrapper($message));
  132:                } else {
  133:                     $r->print('<div class="LC_info">'.
  134:                               &mt('Unable to retrieve current settings.').'<br />'.
  135:                               &mt('No changes saved.').
  136:                               '</div>');
  137:                }
  138:            } else {
  139:                my $current = {};
  140:                my @settings = ('student_classlist_view','student_classlist_opt_in',
  141:                                'student_classlist_portfiles');
  142:                foreach my $setting (@settings) {
  143:                    $current->{$setting} = $env{"course.$env{'request.course.id'}.$setting"};
  144:                }
  145:                my ($output,$rowtotal) =
  146:                    &Apache::courseprefs::print_config_box($r,$cdom,$cnum,'display',
  147:                                                           'viewableroster',
  148:                                                           $rosterprefs,$current,
  149:                                                           $allitems,$crstype);
  150:                if ($output) {
  151:                    $r->print('<form method="post" name="display" action="/adm/viewclasslist">'."\n".
  152:                              '<input type="hidden" name="action" value="setconfig" />'."\n".
  153:                              '<input type="hidden" name="register" value="'.$env{'form.register'}.'" />'."\n".
  154:                              '<input type="hidden" name="forceedit" value="'.$env{'form.forceedit'}.'" />'."\n");
  155:                    if ($env{'form.symb'}) {
  156:                         $r->print('<input type="hidden" name="symb" value="'.$env{'form.symb'}.'" />'."\n");
  157:                    }
  158:                    if ($env{'form.symb'}) {
  159:                         $r->print('<input type="hidden" name="todocs" value="'.$env{'form.todocs'}.'" />'."\n");
  160:                    }
  161:                    $r->print('<div class="LC_left_float">'.
  162:                              $output.
  163:                              '</div><br clear="all" />'.
  164:                              '<input type="submit" value="'.&mt('Save').'" />'.
  165:                              '</form>');
  166:                } else {
  167:                    $r->print('<div class="LC_info">');
  168:                    if ($crstype eq 'Community') {
  169:                        $r->print(&mt('No member-viewable community roster settings available.'));
  170:                    } else {
  171:                        $r->print(&mt('No student-viewable course roster settings available.'));
  172:                    }
  173:                    $r->print('</div>');
  174:                }
  175:            }
  176:         } else {
  177:             $r->print('<div class="LC_info">');
  178:             if ($crstype eq 'Community') {
  179:                 $r->print(&mt('You do not have rights to modify member-viewable community roster settings.'));
  180:             } else {
  181:                 $r->print(&mt('You do not have rights to modify student-viewable course roster settings.'));
  182:             }
  183:             $r->print('</div>');
  184:         }
  185:     } else {
  186: 
  187:         # Print classlist
  188:         if (keys(%viewsettings) > 0) {
  189:             $r->print(&html_classlist($r,$crstype,\%viewsettings));
  190:         } else {
  191:             $r->print('<div class="LC_info">');
  192:             if ($crstype eq 'Community') {
  193:                 $r->print(&mt("Display of a member-viewable community roster is not currently enabled."));
  194:             } else {
  195:                 $r->print(&mt("Display of a student-viewable course roster is not currently enabled."));
  196:             }
  197:             $r->print('</div>');
  198:         }
  199:     }
  200:     #
  201:     # Finish up
  202:     $r->print(&Apache::loncommon::end_page());
  203:     return OK;
  204: }
  205: 
  206: sub retrieve_view_settings {
  207:     my %viewsettings;
  208:     if (exists($env{'request.course.id'})) {
  209:         my $cid = $env{'request.course.id'};
  210:         my $viewpermission = 'course.'.$cid.'.student_classlist_view';
  211:         my $student_opt_in = 'course.'.$cid.'.student_classlist_opt_in';
  212:         my $portfiles_link = 'course.'.$cid.'.student_classlist_portfiles';
  213:         if (exists($env{$viewpermission}) &&
  214:             $env{$viewpermission} =~ /^(all|section)$/) {
  215:             $viewsettings{'permission'} = $env{$viewpermission};
  216:             if ($viewsettings{'permission'} =~ /^section$/i) {
  217:                 $viewsettings{'limit_to_section'} = 1;
  218:             } else {
  219:                 $viewsettings{'limit_to_section'} = 0;
  220:             }
  221:             $viewsettings{'student_opt_in'} = $env{$student_opt_in};
  222:             $viewsettings{'portfiles_link'} = $env{$portfiles_link};
  223:         }
  224:     }
  225:     return %viewsettings;
  226: }
  227: 
  228: sub roster_prefs {
  229:     my ($crstype) = @_;
  230:     my %lt;
  231:     if ($crstype eq 'Community') {
  232:         %lt = &Apache::lonlocal::texthash (
  233:                   svrs => 'Member-viewable roster settings',
  234:                   stuv => 'Member-viewable membership list options',
  235:                   stul => 'Member agreement needed to be listed',
  236:         );
  237:     } else {
  238:         %lt = &Apache::lonlocal::texthash(
  239:                   svrs => 'Student-viewable roster settings',
  240:                   stuv => 'Student-viewable classlist options',
  241:                   stul => 'Student agreement needed to be listed',
  242:         );
  243:     }
  244:     $lt{'incl'} = &mt('Include link to accessible portfolio files');
  245: 
  246:     return 
  247:         { text => $lt{'svrs'},
  248:           header => [ {col1 => 'Setting',
  249:                        col2 => $lt{'stuv'}}],
  250:           ordered => ['student_classlist_view',
  251:                       'student_classlist_opt_in',
  252:                       'student_classlist_portfiles'],
  253:           itemtext => {
  254:                        student_classlist_view        => $lt{'stuv'},
  255:                        student_classlist_opt_in      => $lt{'stul'},
  256:                        student_classlist_portfiles   => $lt{'incl'},
  257:                       },
  258:         };
  259: }
  260: 
  261: sub html_classlist {
  262:     my ($r,$crstype,$viewsettings) = @_;
  263:     my ($Str,$title,$secdisplay,$cid,$cdom,$cnum,$listtype,%publicroster);
  264:     my $fullroster = &Apache::loncoursedata::get_classlist();
  265:     my $classlist;
  266: 
  267:     my $singular = 'student';
  268:     my $plural = 'students';
  269:     my $titleplural = 'Students';
  270:     my $heading = &mt('Student-viewable course roster');
  271: 
  272:     if ($crstype eq 'Community') {
  273:         $singular = 'member';
  274:         $plural = 'members';
  275:         $titleplural = 'Members';
  276:         $heading = &mt('Member-viewable community roster');
  277:     }
  278: 
  279:     if ($env{'form.action'} eq 'setenv') {
  280:         $Str .= &process_student_prefs($crstype);
  281:     }
  282: 
  283:     $Str .= '<h2>'.$heading.'</h2>';
  284: 
  285:     $cid = $env{'request.course.id'};
  286:     $cdom = $env{'course.'.$cid.'.domain'};
  287:     $cnum = $env{'course.'.$cid.'.num'};
  288: 
  289:     my $title;
  290:     if ($viewsettings->{'limit_to_section'}) {
  291:         if ($env{'request.course.sec'} eq '') {
  292:             $title = &mt($titleplural.' with no section');
  293:             $listtype = 'without a section';
  294:         } else {
  295:             $title = &mt($titleplural.' in section "[_1]"',
  296:                          $env{'request.course.sec'});
  297:             $listtype = 'in the section';
  298:             $secdisplay = " ($env{'request.course.sec'}) ";
  299:         }
  300:     } else {
  301:         $title = &mt($titleplural.' in any section');
  302:         $listtype = 'in the course';
  303:         if ($crstype eq 'Community') {
  304:             $listtype = 'in the community';
  305:         }
  306:     }
  307:     if ($viewsettings->{'student_opt_in'}) {
  308:         if ($env{'request.role'} =~ /^st/)  {
  309:             $Str .= &print_roster_form($crstype);
  310:         }
  311:         %publicroster = &Apache::lonnet::dump('publicroster',$cdom,$cnum);
  312:     }
  313: 
  314:     $Str .= '<h3>'.$title.'</h3>';
  315: 
  316:     my $fullcount = 0;
  317:     my $publiccount = 0;
  318:     my $displaycount = 0;
  319:     my $sectionidx  = &Apache::loncoursedata::CL_SECTION();
  320:     my $statusidx   = &Apache::loncoursedata::CL_STATUS();
  321: 
  322:     foreach my $student (keys(%{$fullroster})) {
  323:         my $section  = $fullroster->{$student}->[$sectionidx];
  324:         my $status   = $fullroster->{$student}->[$statusidx];
  325:         next if (lc($status) ne 'active');
  326:         if ($viewsettings->{'limit_to_section'}) {
  327:             next if ($section ne $env{'request.course.sec'});
  328:         }
  329:         $fullcount ++;
  330:         if ($viewsettings->{'student_opt_in'}) {
  331:             if ($publicroster{$student}) {
  332:                 $classlist->{$student} = $fullroster->{$student};
  333:                 $publiccount ++;
  334:             }
  335:         } else {
  336:             $classlist->{$student} = $fullroster->{$student};
  337:         }
  338:     }
  339:     if ($viewsettings->{'student_opt_in'}) {
  340:         $displaycount = $publiccount;
  341:         if ($fullcount > $publiccount) {
  342:             if ($publiccount) {
  343:                 $Str .= &mt('Only '.$plural.' who have opted to be listed in the roster ([_1] out of [_2] '.$plural.') are shown.',$publiccount,$fullcount).'<br />';
  344:             } else {
  345:                 if ($fullcount == 1) {
  346:                     $Str .= &mt('The single '.$singular.' '.$listtype.'[_1] has opted not to be listed in the roster.',$secdisplay);
  347:                 } else {
  348:                     $Str .= &mt('None of the [_1] '.$plural.' '.$listtype.'[_2] have opted to be listed in the roster.',$fullcount,$secdisplay);
  349:                 }
  350:                 return $Str;
  351:             }
  352:         } else {
  353:             if ($fullcount > 1) {
  354:                 $Str .= &mt('All [_1] '.$plural.' '.$listtype.'[_2] have opted to be listed in the roster.',$fullcount,$secdisplay); 
  355:             } elsif ($fullcount == 1) {
  356:                 $Str .= &mt('The single '.$singular.' '.$listtype.'[_1] has opted to be listed in the roster.',$secdisplay);
  357:             }
  358:         }
  359:     } else {
  360:         $displaycount = $fullcount;
  361:         if ($fullcount > 1) {
  362:             $Str .= &mt('All [_1] '.$plural.' '.$listtype.'[_2] are listed in the roster.',$fullcount,$secdisplay);
  363:         } elsif ($fullcount == 1) {
  364:             $Str .= &mt('There is only a single '.$singular.' '.$listtype.'[_1]',$secdisplay);
  365:         }
  366:     }
  367:     undef($fullroster);
  368: 
  369:     if (!$displaycount) {
  370:         $Str .= &mt('There are currently no '.$plural.' to display.');
  371:         return $Str;
  372:     }
  373: 
  374:     # Set up a couple variables.
  375:     my $usernameidx = &Apache::loncoursedata::CL_SNAME();
  376:     my $domainidx   = &Apache::loncoursedata::CL_SDOM();
  377:     my $fullnameidx = &Apache::loncoursedata::CL_FULLNAME();
  378: 
  379:     # Sort the students
  380:     my $sortby = $fullnameidx;
  381:     my @Sorted_Students = sort {
  382:         lc($classlist->{$a}->[$sortby])  cmp lc($classlist->{$b}->[$sortby])
  383:         } (keys(%$classlist));
  384:     $Str .= '<br />'.&Apache::loncommon::start_data_table()."\n".
  385:             &Apache::loncommon::start_data_table_header_row()."\n".
  386:         '<th></th>'. # for the count
  387:         '<th>'.&mt('Name').'</th>'.
  388:         '<th>'.&mt('Username').'</th>';
  389:     if (! $viewsettings->{'limit_to_section'}) {
  390:         $Str .= '<th>'.&mt('Section').'</th>';
  391:     }
  392:     if ($viewsettings->{'portfiles_link'}) {
  393:         $Str .= '<th>'.&mt('Available Portfolio files').'</th>';
  394:     }
  395:     $Str .= &Apache::loncommon::end_data_table_header_row();
  396:     my $count ++;
  397:     foreach my $student (@Sorted_Students) {
  398:         my $username = $classlist->{$student}->[$usernameidx];
  399:         my $domain   = $classlist->{$student}->[$domainidx];
  400:         my $fullname = $classlist->{$student}->[$fullnameidx];
  401:         if ($fullname =~ /^\s*$/) {
  402:             $fullname = &mt('Name not given');
  403:         }
  404:         my $section  = $classlist->{$student}->[$sectionidx];
  405:         if ($section eq '') {
  406:             $section = &mt('none');
  407:         }
  408:         $Str .= &Apache::loncommon::start_data_table_row()."\n".
  409:             '<td>'.$count++.'</td>'.
  410:             '<td>'.&Apache::loncommon::aboutmewrapper($fullname,
  411:                                                       $username,
  412:                                                       $domain).'</td>'.
  413:             '<td>'.('&nbsp;'x2).
  414:             &Apache::loncommon::messagewrapper
  415:             ('<img src="/adm/lonIcons/mailto.gif" border="0" />&nbsp;'.
  416:              $username.':'.$domain,$username,$domain).'</td>';
  417:         if (! $viewsettings->{'limit_to_section'}) {
  418:             $Str .= '<td>'.$section.'</td>';
  419:         }
  420:         if ($viewsettings->{'portfiles_link'}) {
  421:             my $filecounts = &Apache::lonaboutme::portfolio_files($r,'showlink',undef,undef,$domain,$username,$fullname);
  422:             my $link;
  423:             if (ref($filecounts) eq 'HASH') {
  424:                 $link = &mt('[quant,_1,file,files,No files]',$filecounts->{'both'});
  425:                 if ($filecounts->{'both'} > 0) {
  426:                     $link = '<a href="/adm/'.$domain.'/'.$username.'/aboutme/portfolio?classlist">'.$link.'</a>'; 
  427:                 }
  428:             } else {
  429:                 $link = '<span class="LC_error">'.&mt("Error retrieving file information.").'</span>';
  430:             }
  431:             $Str .= '<td>'.$link.'</td>';
  432:         }
  433:         $Str .= &Apache::loncommon::end_data_table_row()."\n";
  434:     }
  435:     $Str .= &Apache::loncommon::end_data_table();
  436:     return $Str;
  437: }
  438: 
  439: sub print_roster_form {
  440:     my ($crstype) = @_;
  441:     my $cid = $env{'request.course.id'};
  442:     my $showinroster = $env{'environment.internal.'.$cid.'.showinroster'};
  443:     my ($showoff,$showon);
  444:     if ($showinroster) {
  445:         $showon = ' checked="checked" ';
  446:         $showoff = ' ';
  447:     } else {
  448:         $showoff = ' checked="checked" ';
  449:         $showon = ' ';
  450:     }
  451:     my $singular = 'student';
  452:     if ($crstype eq 'Community') {
  453:         $singular = 'member';
  454:     }
  455:     my $output =
  456:         '<div class="LC_left_float">'
  457:        .'<fieldset><legend>'.&mt('Your roster setting').'</legend>';
  458:     if ($showinroster) {
  459:         $output .= &mt("You are currently listed in the $singular-viewable roster.");
  460:     } else {
  461:         $output .=  &mt("You are currently [_1]not[_2] listed in the $singular-viewable roster.",'<b>','</b>');
  462:     }
  463:     $output .= '<br />'.&mt('Include yourself in the roster?').'&nbsp;&nbsp;'.
  464:         '<form name="studentparm" method="post" action="">'.
  465:         '<span class="LC_nobreak"><label><input type="radio" name="showinroster" value="1"'.$showon.'/>'.&mt('Yes').'</label>&nbsp;&nbsp;<label>'.
  466:         '<input type="radio" name="showinroster" value="0"'.$showoff.'/>'.&mt('No').
  467:         '</label></span><br /><br />'.
  468:         '<input type="hidden" name="action" value="setenv" />'.
  469:         '<input type="submit" name="studentsubmit" value="'.&mt('Save').'" />'.
  470:         '</form></fieldset></div><br clear="all" />';
  471:     return $output;
  472: }
  473: 
  474: sub process_student_prefs {
  475:     my ($crstype) = @_;
  476:     my $cid = $env{'request.course.id'};
  477:     my $cdom = $env{'course.'.$cid.'.domain'};
  478:     my $cnum = $env{'course.'.$cid.'.num'};
  479:     my $uname = $env{'user.name'};
  480:     my $udom = $env{'user.domain'};
  481:     my $student = $uname.':'.$udom;
  482:     my %pubroster = &Apache::lonnet::get('publicroster',[$student],$cdom,$cnum);
  483:     my $visibility = &mt('off');
  484:     my $showinroster = $env{'form.showinroster'};
  485:     if ($showinroster) {
  486:         $visibility = &mt('on');
  487:     }
  488:     my $sturoster = 0;
  489:     if ($pubroster{$student}) {
  490:         $sturoster = 1;
  491:     }
  492: 
  493:     my $singular = 'student';
  494:     if ($crstype eq 'Community') {
  495:         $singular = 'member';
  496:     }
  497:     my $output;
  498:     if ($sturoster ne $showinroster) {
  499:         my %changeHash = (
  500:             'environment.internal.'.$cid.'.showinroster' => $showinroster,
  501:         );
  502:         my $putresult = &Apache::lonnet::put('environment',
  503:                                              \%changeHash,$udom,$uname);
  504:         if ($putresult eq 'ok') {
  505:             &Apache::lonnet::appenv(\%changeHash);
  506:             my $result = &Apache::lonnet::put('publicroster',{$student => $showinroster,},$cdom,$cnum);
  507:             if ($result eq 'ok') {
  508:                 $output .=
  509:                     &Apache::lonhtmlcommon::confirm_success(
  510:                         &mt("Display of your name in the $singular-viewable roster set to [_1].",'<b>'.$visibility.'</b>'));
  511:             } else {
  512:                 $output .=
  513:                     &Apache::lonhtmlcommon::confirm_success(
  514:                         &mt('Error occurred saving display setting.'),1);
  515:             }
  516:         } else {
  517:             $output .=
  518:                 &Apache::lonhtmlcommon::confirm_success(
  519:                     &mt('Error occurred saving display setting.'),1);
  520:         }
  521:     } else {
  522:         $output .=
  523:             &Apache::lonhtmlcommon::confirm_success(
  524:                 &mt("Display of your name in the $singular-viewable roster unchanged (set to [_1]).",'<b>'.$visibility.'</b>'));
  525:     }
  526:     $output = &Apache::loncommon::confirmwrapper($output);
  527:     return $output;
  528: }
  529: 
  530: 
  531: 
  532: 
  533: ###################################################################
  534: ###################################################################
  535: 
  536: 1;
  537: __END__
  538: 
  539: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>