Diff for /loncom/interface/lonnavmaps.pm between versions 1.466 and 1.475

version 1.466, 2011/11/07 20:05:56 version 1.475, 2011/12/21 20:21:49
Line 225  automatically. Line 225  automatically.
   
 =over 4  =over 4
   
 =item * B<iterator>: default: constructs one from %env  =item * B<iterator: default: constructs one from %env
   
 A reference to a fresh ::iterator to use from the navmaps. The  A reference to a fresh ::iterator to use from the navmaps. The
 rendering will reflect the options passed to the iterator, so you can  rendering will reflect the options passed to the iterator, so you can
Line 487  use DateTime(); Line 487  use DateTime();
   
 # For debugging  # For debugging
   
 use Data::Dumper;  # use Data::Dumper;
   
   
 # symbolic constants  # symbolic constants
Line 542  my %colormap = Line 542  my %colormap =
 # is not yet done and due in less than 24 hours  # is not yet done and due in less than 24 hours
 my $hurryUpColor = "#FF0000";  my $hurryUpColor = "#FF0000";
   
 my $future_slots_checked = 0;  
 my $future_slots = 0;  
   
 sub addToFilter {  sub addToFilter {
     my $hashIn = shift;      my $hashIn = shift;
     my $addition = shift;      my $addition = shift;
Line 618  sub getDescription { Line 615  sub getDescription {
         return &Apache::lonhtmlcommon::direct_parm_link(&mt("Not currently assigned.",$res->symb(),'opendate'),$part);          return &Apache::lonhtmlcommon::direct_parm_link(&mt("Not currently assigned.",$res->symb(),'opendate'),$part);
     }      }
     if ($status == $res->OPEN_LATER) {      if ($status == $res->OPEN_LATER) {
         return &mt("Open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start')),$res->symb(),'opendate',$part);          return &mt("Open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start'),$res->symb(),'opendate',$part));
     }      }
     if ($res->simpleStatus($part) == $res->OPEN) {      if ($res->simpleStatus($part) == $res->OPEN) {
         unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) {          unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) {
Line 635  sub getDescription { Line 632  sub getDescription {
                 return &mt('Reserved - next open [_1]',                  return &mt('Reserved - next open [_1]',
                            timeToHumanString($slot_time,'start'));                             timeToHumanString($slot_time,'start'));
             } elsif ($slot_status == $res->RESERVABLE) {              } elsif ($slot_status == $res->RESERVABLE) {
                 return &mt('Reservable ending [_1]',                  return &mt('Reservable, reservations close [_1]',
                            timeToHumanString($slot_time,'end'));                             timeToHumanString($slot_time,'end'));
             } elsif ($slot_status == $res->RESERVABLE_LATER) {              } elsif ($slot_status == $res->RESERVABLE_LATER) {
                 return &mt('Reservable starting [_1]',                  return &mt('Reservable, reservations open [_1]',
                            timeToHumanString($slot_time,'start'));                             timeToHumanString($slot_time,'start'));
             } elsif ($slot_status == $res->NOT_IN_A_SLOT) {              } elsif ($slot_status == $res->NOT_IN_A_SLOT) {
                 return &mt('Reserve a time/place to work');                  return &mt('Reserve a time/place to work');
Line 652  sub getDescription { Line 649  sub getDescription {
     if ($status == $res->OPEN) {      if ($status == $res->OPEN) {
         if ($due) {          if ($due) {
     if ($res->is_practice()) {      if ($res->is_practice()) {
  return &mt("Closes [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start')),$res->symb(),'duedate',$part);   return &mt("Closes [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'duedate',$part));
     } else {      } else {
  return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end')),$res->symb(),'duedate',$part);   return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part));
     }      }
         } else {          } else {
             return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part);              return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part);
         }          }
     }      }
     if ($status == $res->PAST_DUE_ANSWER_LATER) {      if ($status == $res->PAST_DUE_ANSWER_LATER) {
         return &mt("Answer open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start')),$res->symb(),'answerdate',$part);          return &mt("Answer open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start'),$res->symb(),'answerdate',$part));
     }      }
     if ($status == $res->PAST_DUE_NO_ANSWER) {      if ($status == $res->PAST_DUE_NO_ANSWER) {
  if ($res->is_practice()) {   if ($res->is_practice()) {
     return &mt("Closed [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start')),$res->symb(),'answerdate,duedate',$part);      return &mt("Closed [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'answerdate,duedate',$part));
  } else {   } else {
     return &mt("Was due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end')),$res->symb(),'answerdate,duedate',$part);      return &mt("Was due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'answerdate,duedate',$part));
  }   }
     }      }
     if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)      if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)
Line 700  sub getDescription { Line 697  sub getDescription {
             }              }
         }          }
         if ($due) {          if ($due) {
             return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end')),$res->symb(),'duedate',$part) .              return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part)) .
                 " $triesString";                  " $triesString";
         } else {          } else {
             return &Apache::lonhtmlcommon::direct_parm_link(&mt("No due date"),$res->symb(),'duedate',$part)." $triesString";              return &Apache::lonhtmlcommon::direct_parm_link(&mt("No due date"),$res->symb(),'duedate',$part)." $triesString";
Line 1013  sub render_resource { Line 1010  sub render_resource {
     # Is this the current resource?      # Is this the current resource?
     if (!$params->{'displayedHereMarker'} &&       if (!$params->{'displayedHereMarker'} && 
         $resource->symb() eq $params->{'here'} ) {          $resource->symb() eq $params->{'here'} ) {
         $curMarkerBegin = '<em>';          $curMarkerBegin = '<span class="LC_current_nav_location">';
         $curMarkerEnd = '</em>';          $curMarkerEnd = '</span>';
  $params->{'displayedHereMarker'} = 1;   $params->{'displayedHereMarker'} = 1;
     }      }
   
Line 1135  sub render_long_status { Line 1132  sub render_long_status {
         $result .= getDescription($resource, $part);          $result .= getDescription($resource, $part);
         if ($color) {$result .= "</b></font>"; }          if ($color) {$result .= "</b></font>"; }
     }      }
       if ($resource->is_map()) {
           if (&Apache::lonnet::allowed('mdc')) {
               if ($resource->symb=~/\_\_\_[^\_]+\_\_\_uploaded/) {
                  $result.="&nbsp;<a href='/adm/coursedocs?command=direct&symb=".&escape($resource->symb())."'>".
                                 "<span class='LC_setting'>".&mt("Edit Content").'</span></a>&nbsp;';
               }
           }
       }
     if ($resource->is_map() && &advancedUser() && $resource->randompick()) {      if ($resource->is_map() && &advancedUser() && $resource->randompick()) {
         $result .= &mt('(randomly select [_1])', $resource->randompick());          $result .= &mt('(randomly select [_1])', $resource->randompick());
     }      }
Line 1389  sub render { Line 1394  sub render {
         }          }
     }      }
   
   
     # (re-)Locate the jump point, if any      # (re-)Locate the jump point, if any
     # Note this does not take filtering or hidden into account... need      # Note this does not take filtering or hidden into account... need
     # to be fixed?      # to be fixed?
Line 1497  END Line 1503  END
             }              }
  }   }
  $result.='</form>';   $result.='</form>';
           if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) {
               my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
               if ($env{'course.'.$env{'request.course.id'}.'.url'} eq 
                   "uploaded/$cdom/$cnum/default.sequence") {
                   &add_linkitem($args->{'linkitems'},'edittoplevel',
                                 "javascript:gocmd('/adm/coursedocs','direct');",
                                 'Content Editor');
               }
           }
     }      }
   
     if ($args->{'caller'} eq 'navmapsdisplay') {      if ($args->{'caller'} eq 'navmapsdisplay') {
Line 1641  END Line 1657  END
     $curRes = shift(@resources);      $curRes = shift(@resources);
  } else {   } else {
     $curRes = $it->next($closeAllPages);      $curRes = $it->next($closeAllPages);
   
  }   }
  if (!$curRes) { last; }   if (!$curRes) { last; }
   
Line 1848  sub add_linkitem { Line 1865  sub add_linkitem {
 sub show_linkitems_toolbar {  sub show_linkitems_toolbar {
     my ($linkitems,$condition)=@_;      my ($linkitems,$condition)=@_;
     my @linkorder = ('firsthomework','everything','uncompleted',      my @linkorder = ('firsthomework','everything','uncompleted',
                      'changefolder','clearbubbles');                       'changefolder','clearbubbles','edittoplevel');
     my $result .='<td align="left">'."\n".       my $result .='<td align="left">'."\n". 
                  '<span class="LC_nobreak">'."\n".                   '<span class="LC_nobreak">'."\n".
                  '<ul id="LC_toolbar">';                   '<ul id="LC_toolbar">';
Line 1987  sub new { Line 2004  sub new {
     # assume there are course hashes for the specific requested user@domamin:      # assume there are course hashes for the specific requested user@domamin:
     #      #
   
     if (($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'})) {      if ( ($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'})) {
   
  # tie the nav hash   # tie the nav hash
   
Line 2012  sub new { Line 2029  sub new {
     } else {      } else {
  $self->change_user($self->{USERNAME}, $self->{DOMAIN});   $self->change_user($self->{USERNAME}, $self->{DOMAIN});
     }      }
           
       my $d = Data::Dumper->new([$self]);
   
     return $self;      return $self;
 }  }
   
Line 2047  sub change_user { Line 2066  sub change_user {
     &Apache::lonmap::loadmap($cnum, $cdom, $self->{USERNAME}, $self->{DOMAIN}, \%big_hash);      &Apache::lonmap::loadmap($cnum, $cdom, $self->{USERNAME}, $self->{DOMAIN}, \%big_hash);
     $self->{NAV_HASH} = \%big_hash;      $self->{NAV_HASH} = \%big_hash;
   
   
   
     # Now clear the parm cache and reconstruct the parm hash fromt he big_hash      # Now clear the parm cache and reconstruct the parm hash fromt he big_hash
     # param.xxxx keys.      # param.xxxx keys.
   
Line 2062  sub change_user { Line 2083  sub change_user {
     }      }
   
     $self->{PARM_HASH} = \%parm_hash;      $self->{PARM_HASH} = \%parm_hash;
      
   
   
           
Line 3054  sub new { Line 3076  sub new {
     if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) {       if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) { 
         my $firstResource = $resource->map_start();          my $firstResource = $resource->map_start();
         my $finishResource = $resource->map_finish();          my $finishResource = $resource->map_finish();
         return    my $result;
             Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,   my $rdump  = Data::Dumper->new([$result]);
                                               $finishResource, $self->{FILTER},   $result =  Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
                                               $self->{ALREADY_SEEN},        $finishResource, $self->{FILTER},
                                               $self->{CONDITION},       $self->{ALREADY_SEEN}, 
       $self->{FORCE_TOP});       $self->{CONDITION},
        $self->{FORCE_TOP});
    return $result;
              
                   
     }      }
   
Line 3079  sub new { Line 3104  sub new {
     $self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1;      $self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1;
   
     bless ($self);      bless ($self);
       my $selfDump = Data::Dumper->new([$self]);
   
     return $self;      return $self;
 }  }
Line 3094  sub next { Line 3120  sub next {
     # do so.      # do so.
     if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0}) {      if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0}) {
         $self->{HAVE_RETURNED_0} = 1;          $self->{HAVE_RETURNED_0} = 1;
    my $nextTopLevel = $self->{NAV_MAP}->getById('0.0');
   
         return $self->{NAV_MAP}->getById('0.0');          return $self->{NAV_MAP}->getById('0.0');
     }      }
     if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {      if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {
Line 3113  sub next { Line 3141  sub next {
         if ($self->{RECURSIVE_DEPTH} == 0) {          if ($self->{RECURSIVE_DEPTH} == 0) {
             $self->{RECURSIVE_ITERATOR_FLAG} = 0;              $self->{RECURSIVE_ITERATOR_FLAG} = 0;
         }          }
   
         return $next;          return $next;
     }      }
   
     if (defined($self->{FORCE_NEXT})) {      if (defined($self->{FORCE_NEXT})) {
         my $tmp = $self->{FORCE_NEXT};          my $tmp = $self->{FORCE_NEXT};
         $self->{FORCE_NEXT} = undef;          $self->{FORCE_NEXT} = undef;
   
         return $tmp;          return $tmp;
     }      }
   
Line 3189  sub next { Line 3217  sub next {
     # So we need to look at all the resources we can get to from here,      # So we need to look at all the resources we can get to from here,
     # categorize them if we haven't seen them, remember if we have a new      # categorize them if we haven't seen them, remember if we have a new
     my $nextUnfiltered = $here->getNext();      my $nextUnfiltered = $here->getNext();
   
   
     my $maxDepthAdded = -1;      my $maxDepthAdded = -1;
           
     for (@$nextUnfiltered) {      for (@$nextUnfiltered) {
Line 3222  sub next { Line 3252  sub next {
         $self->{RECURSIVE_ITERATOR_FLAG} = 1;          $self->{RECURSIVE_ITERATOR_FLAG} = 1;
         my $firstResource = $self->{HERE}->map_start();          my $firstResource = $self->{HERE}->map_start();
         my $finishResource = $self->{HERE}->map_finish();          my $finishResource = $self->{HERE}->map_finish();
   
         $self->{RECURSIVE_ITERATOR} =           $self->{RECURSIVE_ITERATOR} = 
             Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,              Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
                                               $finishResource, $self->{FILTER},                                                $finishResource, $self->{FILTER},
Line 3240  sub next { Line 3269  sub next {
         return $self->next($closeAllPages);          return $self->next($closeAllPages);
     }      }
   
       my $hereResource = $self->{HERE};
   
     return $self->{HERE};      return $self->{HERE};
   
 }  }
Line 3406  sub next { Line 3437  sub next {
     my $nextUnfiltered;      my $nextUnfiltered;
     if ($self->{DIRECTION} == FORWARD()) {      if ($self->{DIRECTION} == FORWARD()) {
         $nextUnfiltered = $self->{HERE}->getNext();          $nextUnfiltered = $self->{HERE}->getNext();
   
     } else {      } else {
         $nextUnfiltered = $self->{HERE}->getPrevious();          $nextUnfiltered = $self->{HERE}->getPrevious();
     }      }
Line 5065  sub status { Line 5097  sub status {
     }      }
   
     # Otherwise, it's untried and open      # Otherwise, it's untried and open
     return OPEN;       return OPEN;
 }  }
   
 sub check_for_slot {  sub check_for_slot {
     my $self = shift;      my $self = shift;
     my $part = shift;      my $part = shift;
       my $symb = $self->symb();
     my ($use_slots,$available,$availablestudent) = $self->slot_control($part);      my ($use_slots,$available,$availablestudent) = $self->slot_control($part);
     if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) {      if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) {
         my @slots = (split(/:/,$availablestudent),split(/:/,$available));          my @slots = (split(/:/,$availablestudent),split(/:/,$available));
Line 5078  sub check_for_slot { Line 5111  sub check_for_slot {
         my $cdom=$env{'course.'.$cid.'.domain'};          my $cdom=$env{'course.'.$cid.'.domain'};
         my $cnum=$env{'course.'.$cid.'.num'};          my $cnum=$env{'course.'.$cid.'.num'};
         my $now = time;          my $now = time;
           my $num_usable_slots = 0;
         if (@slots > 0) {          if (@slots > 0) {
             my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);              my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);
             if (&Apache::lonnet::error(%slots)) {              if (&Apache::lonnet::error(%slots)) {
                 return (UNKNOWN);                  return (UNKNOWN);
             }              }
             my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots);              my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime');
             my ($checkedin,$checkedinslot);              my ($checkedin,$checkedinslot);
             foreach my $slot_name (@sorted_slots) {              foreach my $slot_name (@sorted_slots) {
                 next if (!defined($slots{$slot_name}) ||                  next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name}));
                          !ref($slots{$slot_name}));  
                 my $end = $slots{$slot_name}->{'endtime'};                  my $end = $slots{$slot_name}->{'endtime'};
                 my $start = $slots{$slot_name}->{'starttime'};                  my $start = $slots{$slot_name}->{'starttime'};
                 my $ip = $slots{$slot_name}->{'ip'};                  my $ip = $slots{$slot_name}->{'ip'};
                 if ($self->simpleStatus() == OPEN) {                  if ($self->simpleStatus() == OPEN) {
                     my $startreserve = $slots{$slot_name}->{'startreserve'};  
                     my @proctors;  
                     if ($slots{$slot_name}->{'proctor'} ne '') {  
                         @proctors = split(',',$slots{$slot_name}->{'proctor'});  
                     }  
                     if ($end > $now) {                      if ($end > $now) {
                         ($checkedin,$checkedinslot) = $self->checkedin();                          if ($start > $now) {
                         if ($startreserve < $now) {                              return (RESERVED_LATER,$start,$slot_name);
                             if ($start > $now) {                          } else {
                                 return (RESERVED_LATER,$start,$slot_name);                              if ($ip ne '') {
                             } else {                                  if (!&Apache::loncommon::check_ip_acc($ip)) {
                                 if ($ip ne '') {                                      return (RESERVED_LOCATION,$ip,$slot_name);
                                     if (!&Apache::loncommon::check_ip_acc($ip)) {  
                                         return (RESERVED_LOCATION,$ip,$slot_name);  
                                     }  
                                 }   
                                 if (@proctors > 0) {  
                                     unless ((grep(/^\Q$checkedin\E/,@proctors)) &&  
                                         ($checkedinslot eq $slot_name)) {  
                                         return (NEEDS_CHECKIN,undef,$slot_name);   
                                     }  
                                 }                                  }
                                 return (RESERVED,$end,$slot_name);  
                             }                              }
                         } else {                              my @proctors;
                             if ($start > $now) {                              if ($slots{$slot_name}->{'proctor'} ne '') {
                                 return (RESERVABLE,$startreserve,$slot_name);                                  @proctors = split(',',$slots{$slot_name}->{'proctor'});
                               }
                               if (@proctors > 0) {
                                   ($checkedin,$checkedinslot) = $self->checkedin();
                                   unless ((grep(/^\Q$checkedin\E/,@proctors)) &&
                                           ($checkedinslot eq $slot_name)) {
                                       return (NEEDS_CHECKIN,undef,$slot_name); 
                                   }
                             }                              }
                               return (RESERVED,$end,$slot_name);
                         }                          }
                     }                      }
                   } elsif ($end > $now) {
                       $num_usable_slots ++;
                 }                  }
             }              }
             my ($is_correct,$got_grade);              my ($is_correct,$got_grade);
Line 5142  sub check_for_slot { Line 5170  sub check_for_slot {
                     return (CORRECT);                       return (CORRECT); 
                 }                  }
             }              }
             return(NOT_IN_A_SLOT);              if ($num_usable_slots) {
         } else {  
             if (!$future_slots_checked) {  
                 $future_slots = &get_future_slots($cdom,$cnum,$now);  
                 $future_slots_checked = 1;  
             }  
             if ($future_slots) {  
                 return(NOT_IN_A_SLOT);                  return(NOT_IN_A_SLOT);
             }              }
             return(NOTRESERVABLE);  
         }          }
     }          my $reservable = &Apache::lonnet::get_reservable_slots($cnum,$cdom,$env{'user.name'},
     return;                                                                 $env{'user.domain'});
 }          if (ref($reservable) eq 'HASH') {
               if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) {
 sub get_future_slots {                  foreach my $slot (reverse (@{$reservable->{'now_order'}})) {
     my ($cdom,$cnum,$now) = @_;                      if (($reservable->{'now'}{$slot}{'symb'} eq '') ||
     my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum);                          ($reservable->{'now'}{$slot}{'symb'} eq $symb)) {
     my $future_slots = 0;                          return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'});
     foreach my $slot (keys(%slots)) {                      }
         if (($slots{$slot}->{'starttime'} > $now) &&                  }
             ($slots{$slot}->{'endtime'} > $now)) {              }
             $future_slots ++;              if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) {
                   foreach my $slot (@{$reservable->{'future_order'}}) {
                       if (($reservable->{'future'}{$slot}{'symb'} eq '') ||
                           ($reservable->{'future'}{$slot}{'symb'} eq $symb)) {
                           return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'});
                       }
                   }
               }
         }          }
           return(NOTRESERVABLE);
     }      }
     return $future_slots;      return;
 }  }
   
 sub CLOSED { return 23; }  sub CLOSED { return 23; }

Removed from v.1.466  
changed lines
  Added in v.1.475


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