Diff for /loncom/interface/lonnavmaps.pm between versions 1.394 and 1.402

version 1.394, 2006/12/20 23:25:13 version 1.402, 2007/10/05 18:48:20
Line 38  use Apache::lonnet; Line 38  use Apache::lonnet;
 use POSIX qw (floor strftime);  use POSIX qw (floor strftime);
 use Data::Dumper; # for debugging, not always   use Data::Dumper; # for debugging, not always 
 use Time::HiRes qw( gettimeofday tv_interval );  use Time::HiRes qw( gettimeofday tv_interval );
 use lib '/home/httpd/lib/perl/';  
 use LONCAPA;  use LONCAPA;
   
 # symbolic constants  # symbolic constants
Line 86  my %colormap = Line 85  my %colormap =
       $resObj->PARTIALLY_CORRECT      => '#006600'        $resObj->PARTIALLY_CORRECT      => '#006600'
       );        );
 # And a special case in the nav map; what to do when the assignment  # And a special case in the nav map; what to do when the assignment
 # is not yet done and due in less then 24 hours  # is not yet done and due in less than 24 hours
 my $hurryUpColor = "#FF0000";  my $hurryUpColor = "#FF0000";
   
 sub close {  sub close {
Line 171  sub getLinkForResource { Line 170  sub getLinkForResource {
         if (defined($item)) { $res = $item; }          if (defined($item)) { $res = $item; }
     }      }
   
     return ($res->link(),$res->shown_symb());      if ($res) {
    return ($res->link(),$res->shown_symb());
       }
       return;
 }  }
   
 # Convenience function: This separates the logic of how to create  # Convenience function: This separates the logic of how to create
Line 196  sub getDescription { Line 198  sub getDescription {
     }      }
     if ($status == $res->OPEN) {      if ($status == $res->OPEN) {
         if ($res->duedate($part)) {          if ($res->duedate($part)) {
             return &mt("Due")."  " .timeToHumanString($res->duedate($part),'end');      if ($res->is_practice()) {
    return &mt("Closes ")."  " .timeToHumanString($res->duedate($part),'start');
       } else {
    return &mt("Due")."  " .timeToHumanString($res->duedate($part),'end');
       }
         } else {          } else {
             return &mt("Open, no due date");              return &mt("Open, no due date");
         }          }
Line 205  sub getDescription { Line 211  sub getDescription {
         return &mt("Answer open")." " . timeToHumanString($res->answerdate($part),'start');          return &mt("Answer open")." " . timeToHumanString($res->answerdate($part),'start');
     }      }
     if ($status == $res->PAST_DUE_NO_ANSWER) {      if ($status == $res->PAST_DUE_NO_ANSWER) {
         return &mt("Was due")." " . timeToHumanString($res->duedate($part),'end');   if ($res->is_practice()) {
       return &mt("Closed")." " . timeToHumanString($res->duedate($part),'start');
    } else {
       return &mt("Was due")." " . timeToHumanString($res->duedate($part),'end');
    }
     }      }
     if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)      if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)
  && $res->handgrade($part) ne 'yes') {   && $res->handgrade($part) ne 'yes') {
Line 239  sub getDescription { Line 249  sub getDescription {
     }      }
 }  }
   
 # Convenience function, so others can use it: Is the problem due in less then  # Convenience function, so others can use it: Is the problem due in less than
 # 24 hours, and still can be done?  # 24 hours, and still can be done?
   
 sub dueInLessThan24Hours {  sub dueInLessThan24Hours {
Line 254  sub dueInLessThan24Hours { Line 264  sub dueInLessThan24Hours {
 }  }
   
 # Convenience function, so others can use it: Is there only one try remaining for the  # Convenience function, so others can use it: Is there only one try remaining for the
 # part, with more then one try to begin with, not due yet and still can be done?  # part, with more than one try to begin with, not due yet and still can be done?
 sub lastTry {  sub lastTry {
     my $res = shift;      my $res = shift;
     my $part = shift;      my $part = shift;
Line 323  sub timeToHumanString { Line 333  sub timeToHumanString {
         my $tense = $inPast ? " ago" : "";          my $tense = $inPast ? " ago" : "";
         my $prefix = $inPast ? "" : "in ";          my $prefix = $inPast ? "" : "in ";
                   
         # Less then a minute          # Less than a minute
         if ( $delta < $minute ) {          if ( $delta < $minute ) {
             if ($delta == 1) { return "${prefix}1 second$tense"; }              if ($delta == 1) { return "${prefix}1 second$tense"; }
             return "$prefix$delta seconds$tense";              return "$prefix$delta seconds$tense";
         }          }
   
         # Less then an hour          # Less than an hour
         if ( $delta < $hour ) {          if ( $delta < $hour ) {
             # If so, use minutes              # If so, use minutes
             my $minutes = floor($delta / 60);              my $minutes = floor($delta / 60);
Line 337  sub timeToHumanString { Line 347  sub timeToHumanString {
             return "$prefix$minutes minutes$tense";              return "$prefix$minutes minutes$tense";
         }          }
                   
         # Is it less then 24 hours away? If so,          # Is it less than 24 hours away? If so,
         # display hours + minutes          # display hours + minutes
         if ( $delta < $hour * 24) {          if ( $delta < $hour * 24) {
             my $hours = floor($delta / $hour);              my $hours = floor($delta / $hour);
Line 363  sub timeToHumanString { Line 373  sub timeToHumanString {
     return $timeStr.&Apache::lonlocal::gettimezone($time);      return $timeStr.&Apache::lonlocal::gettimezone($time);
  }   }
   
         # Less then 5 days away, display day of the week and          # Less than 5 days away, display day of the week and
         # HH:MM          # HH:MM
   
         if ( $delta < $day * 5 ) {          if ( $delta < $day * 5 ) {
Line 428  to compute due to the amount of data tha Line 438  to compute due to the amount of data tha
 processed.  processed.
   
 Apache::lonnavmaps provides an object model for manipulating this  Apache::lonnavmaps provides an object model for manipulating this
 information in a higher-level fashion then directly manipulating   information in a higher-level fashion than directly manipulating 
 the hash. It also provides access to several auxilary functions   the hash. It also provides access to several auxilary functions 
 that aren't necessarily stored in the Big Hash, but are a per-  that aren't necessarily stored in the Big Hash, but are a per-
 resource sort of value, like whether there is any feedback on   resource sort of value, like whether there is any feedback on 
Line 474  Apache::lonnavmaps::render({}). Line 484  Apache::lonnavmaps::render({}).
 =head2 Overview of Columns  =head2 Overview of Columns
   
 The renderer will build an HTML table for the navmap and return  The renderer will build an HTML table for the navmap and return
 it. The table is consists of several columns, and a row for each  it. The table consists of several columns, and a row for each
 resource (or possibly each part). You tell the renderer how many  resource (or possibly each part). You tell the renderer how many
 columns to create and what to place in each column, optionally using  columns to create and what to place in each column, optionally using
 one or more of the prepared columns, and the renderer will assemble  one or more of the prepared columns, and the renderer will assemble
Line 605  instruct the renderer to render only a p Line 615  instruct the renderer to render only a p
 the source of the map you want to process, like  the source of the map you want to process, like
 '/res/103/jerf/navmap.course.sequence'.  '/res/103/jerf/navmap.course.sequence'.
   
   =item * B<include_top_level_map>: default: false
   
   If you need to include the top level map (meaning the course) in the
   rendered output set this to true
   
 =item * B<navmap>: default: constructs one from %env  =item * B<navmap>: default: constructs one from %env
   
 A reference to a navmap, used only if an iterator is not passed in. If  A reference to a navmap, used only if an iterator is not passed in. If
Line 975  sub render_long_status { Line 990  sub render_long_status {
         $params->{'multipart'} && $part eq "0";          $params->{'multipart'} && $part eq "0";
                                   
     my $color;      my $color;
     if ($resource->is_problem()) {      if ($resource->is_problem() || $resource->is_practice()) {
         $color = $colormap{$resource->status};          $color = $colormap{$resource->status};
                   
         if (dueInLessThan24Hours($resource, $part) ||          if (dueInLessThan24Hours($resource, $part) ||
Line 985  sub render_long_status { Line 1000  sub render_long_status {
     }      }
           
     if ($resource->kind() eq "res" &&      if ($resource->kind() eq "res" &&
         $resource->is_problem() &&          ($resource->is_problem() || $resource->is_practice()) &&
         !$firstDisplayed) {          !$firstDisplayed) {
         if ($color) {$result .= "<font color=\"$color\"><b>"; }          if ($color) {$result .= "<font color=\"$color\"><b>"; }
         $result .= getDescription($resource, $part);          $result .= getDescription($resource, $part);
         if ($color) {$result .= "</b></font>"; }          if ($color) {$result .= "</b></font>"; }
     }      }
     if ($resource->is_map() && advancedUser() && $resource->randompick()) {      if ($resource->is_map() && &advancedUser() && $resource->randompick()) {
         $result .= '(randomly select ' . $resource->randompick() .')';          $result .= &mt('(randomly select [_1])', $resource->randompick());
       }
       if ($resource->is_map() && &advancedUser() && $resource->randomorder()) {
           $result .= &mt('(randomly ordered)');
     }      }
   
     # Debugging code      # Debugging code
Line 1234  sub render { Line 1252  sub render {
   
             $args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition);              $args->{'iterator'} = $it = $navmap->getIterator($firstResource, $finishResource, $filterHash, $condition);
         } else {          } else {
             $args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition);              $args->{'iterator'} = $it = $navmap->getIterator(undef, undef, $filterHash, $condition,undef,$args->{'include_top_level_map'});
         }          }
     }      }
   
Line 1802  See iterator documentation below. Line 1820  See iterator documentation below.
 use strict;  use strict;
 use GDBM_File;  use GDBM_File;
 use Apache::lonnet;  use Apache::lonnet;
   use LONCAPA;
   
 sub new {  sub new {
     # magic invocation to create a class instance      # magic invocation to create a class instance
Line 1914  sub generate_email_discuss_status { Line 1933  sub generate_email_discuss_status {
           
     foreach my $msgid (@keys) {      foreach my $msgid (@keys) {
  if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {   if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {
     my $plain=              my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid,
  &LONCAPA::unescape(&LONCAPA::unescape($msgid));                  $symb,$error) = &Apache::lonmsg::unpackmsgid($msgid);
     if ($plain=~/ \[([^\]]+)\]\:/) {              &Apache::lonenc::check_decrypt(\$symb); 
  my $url=$1;              if (($fromcid ne '') && ($fromcid ne $cid)) {
  if ($plain=~/\:Error \[/) {                  next;
     $error{$url}.=','.$msgid;               }
  } else {              if (defined($symb)) {
     $feedback{$url}.=','.$msgid;                  if (defined($error) && $error == 1) {
  }                      $error{$symb}.=','.$msgid;
     }                  } else {
                       $feedback{$symb}.=','.$msgid;
                   }
               } else {
                   my $plain=
                       &LONCAPA::unescape(&LONCAPA::unescape($msgid));
                   if ($plain=~/ \[([^\]]+)\]\:/) {
                       my $url=$1;
                       if ($plain=~/\:Error \[/) {
                           $error{$url}.=','.$msgid;
                       } else {
                           $feedback{$url}.=','.$msgid;
                       }
                   }
               }
  }   }
     }      }
           
     #url's of resources that have feedbacks      #symbs of resources that have feedbacks (will be urls pre-2.3)
     $self->{FEEDBACK} = \%feedback;      $self->{FEEDBACK} = \%feedback;
     #or errors      #or errors (will be urls pre 2.3)
     $self->{ERROR_MSG} = \%error;      $self->{ERROR_MSG} = \%error;
     $self->{DISCUSSION_TIME} = \%discussiontime;      $self->{DISCUSSION_TIME} = \%discussiontime;
     $self->{EMAIL_STATUS} = \%emailstatus;      $self->{EMAIL_STATUS} = \%emailstatus;
Line 2043  sub discussion_info { Line 2076  sub discussion_info {
   
     my $ressymb = $self->wrap_symb($symb);      my $ressymb = $self->wrap_symb($symb);
     # keys used to store bulletinboard postings use 'unwrapped' symb.       # keys used to store bulletinboard postings use 'unwrapped' symb. 
     my $discsymb = $self->unwrap_symb($ressymb);      my $discsymb = &escape($self->unwrap_symb($ressymb));
     my $version = $self->{DISCUSSION_DATA}{'version:'.$discsymb};      my $version = $self->{DISCUSSION_DATA}{'version:'.$discsymb};
     if (!$version) { return; }      if (!$version) { return; }
   
Line 2116  sub unwrap_symb { Line 2149  sub unwrap_symb {
 sub getFeedback {   sub getFeedback { 
     my $self = shift;      my $self = shift;
     my $symb = shift;      my $symb = shift;
       my $source = shift;
   
     $self->generate_email_discuss_status();      $self->generate_email_discuss_status();
   
     if (!defined($self->{FEEDBACK})) { return ""; }      if (!defined($self->{FEEDBACK})) { return ""; }
           
     return $self->{FEEDBACK}->{$symb};      my $feedback;
       if ($self->{FEEDBACK}->{$symb}) {
           $feedback = $self->{FEEDBACK}->{$symb};
           if ($self->{FEEDBACK}->{$source}) {
               $feedback .= ','.$self->{FEEDBACK}->{$source};
           }
       } else {
           if ($self->{FEEDBACK}->{$source}) {
               $feedback = $self->{FEEDBACK}->{$source};
           }
       }
       return $feedback;
 }  }
   
 # Private method: Get the errors for that resource (by source).  # Private method: Get the errors for that resource (by source).
 sub getErrors {   sub getErrors { 
     my $self = shift;      my $self = shift;
       my $symb = shift;
     my $src = shift;      my $src = shift;
   
     $self->generate_email_discuss_status();      $self->generate_email_discuss_status();
   
     if (!defined($self->{ERROR_MSG})) { return ""; }      if (!defined($self->{ERROR_MSG})) { return ""; }
     return $self->{ERROR_MSG}->{$src};  
       my $errors;
       if ($self->{ERROR_MSG}->{$symb}) {
           $errors = $self->{ERROR_MSG}->{$symb};
           if ($self->{ERROR_MSG}->{$src}) {
               $errors .= ','.$self->{ERROR_MSG}->{$src};
           }
       } else {
           if ($self->{ERROR_MSG}->{$src}) {
               $errors = $self->{ERROR_MSG}->{$src};
           }
       }
       return $errors;
 }  }
   
 =pod  =pod
Line 2158  the given map. This is one of the proper Line 2216  the given map. This is one of the proper
   
 # The strategy here is to cache the resource objects, and only construct them  # The strategy here is to cache the resource objects, and only construct them
 # as we use them. The real point is to prevent reading any more from the tied  # as we use them. The real point is to prevent reading any more from the tied
 # hash then we have to, which should hopefully alleviate speed problems.  # hash than we have to, which should hopefully alleviate speed problems.
   
 sub getById {  sub getById {
     my $self = shift;      my $self = shift;
Line 2232  sub finishResource { Line 2290  sub finishResource {
 # the actual lookup; parmval caches the results.  # the actual lookup; parmval caches the results.
 sub parmval {  sub parmval {
     my $self = shift;      my $self = shift;
     my ($what,$symb)=@_;      my ($what,$symb,$recurse)=@_;
     my $hashkey = $what."|||".$symb;      my $hashkey = $what."|||".$symb;
   
     if (defined($self->{PARM_CACHE}->{$hashkey})) {      if (defined($self->{PARM_CACHE}->{$hashkey})) {
         return $self->{PARM_CACHE}->{$hashkey};          return $self->{PARM_CACHE}->{$hashkey};
     }      }
   
     my $result = $self->parmval_real($what, $symb);      my $result = $self->parmval_real($what, $symb, $recurse);
     $self->{PARM_CACHE}->{$hashkey} = $result;      $self->{PARM_CACHE}->{$hashkey} = $result;
     return $result;      return $result;
 }  }
Line 2349  sub parmval_real { Line 2407  sub parmval_real {
  if (defined($partgeneral)) { return $partgeneral; }   if (defined($partgeneral)) { return $partgeneral; }
     }      }
     if ($recurse) { return undef; }      if ($recurse) { return undef; }
     my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$what);      my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$rwhat);
     if (defined($pack_def)) { return $pack_def; }      if (defined($pack_def)) { return $pack_def; }
     return '';      return '';
 }  }
Line 2359  sub parmval_real { Line 2417  sub parmval_real {
 =item * B<getResourceByUrl>(url,multiple):  =item * B<getResourceByUrl>(url,multiple):
   
 Retrieves a resource object by URL of the resource, unless the optional  Retrieves a resource object by URL of the resource, unless the optional
 multiple parameter is included in wahich caes an array of resource   multiple parameter is included in which case an array of resource 
 objects is returned. If passed a resource object, it will simply return    objects is returned. If passed a resource object, it will simply return  
 it, so it is safe to use this method in code like  it, so it is safe to use this method in code like
 "$res = $navmap->getResourceByUrl($res)"  "$res = $navmap->getResourceByUrl($res)"
Line 2394  all matching resources. Line 2452  all matching resources.
   
 =item * B<hasResource>(map, filterFunc, recursive, showall):  =item * B<hasResource>(map, filterFunc, recursive, showall):
   
 Convience method for  Convenience method for
   
  scalar(retrieveResources($map, $filterFunc, $recursive, 1, $showall)) > 0   scalar(retrieveResources($map, $filterFunc, $recursive, 1, $showall)) > 0
   
Line 2472  sub retrieveResources { Line 2530  sub retrieveResources {
   
     my @resources = ();      my @resources = ();
   
       if (&$filterFunc($map)) {
    push(@resources, $map);
       }
   
     # Run down the iterator and collect the resources.      # Run down the iterator and collect the resources.
     my $curRes;      my $curRes;
   
Line 2481  sub retrieveResources { Line 2543  sub retrieveResources {
                 next;                  next;
             }              }
   
             push @resources, $curRes;              push(@resources, $curRes);
   
             if ($bailout) {              if ($bailout) {
                 return @resources;                  return @resources;
Line 2628  be the tokens described above. Line 2690  be the tokens described above.
   
 Also note there is some old code floating around that trys to track  Also note there is some old code floating around that trys to track
 the depth of the iterator to see when it's done; do not copy that   the depth of the iterator to see when it's done; do not copy that 
 code. It is difficult to get right and harder to understand then  code. It is difficult to get right and harder to understand than
 this. They should be migrated to this new style.  this. They should be migrated to this new style.
   
 =cut  =cut
Line 2812  sub next { Line 2874  sub next {
         $self->{HAVE_RETURNED_0} = 1;          $self->{HAVE_RETURNED_0} = 1;
         return $self->{NAV_MAP}->getById('0.0');          return $self->{NAV_MAP}->getById('0.0');
     }      }
       if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {
    $self->{HAVE_RETURNED_0_BEGIN_MAP} = 1;
    return $self->BEGIN_MAP();
       }
   
     if ($self->{RECURSIVE_ITERATOR_FLAG}) {      if ($self->{RECURSIVE_ITERATOR_FLAG}) {
         # grab the next from the recursive iterator           # grab the next from the recursive iterator 
Line 2913  sub next { Line 2979  sub next {
     }      }
   
     # Is this the end of a branch? If so, all of the resources examined above      # Is this the end of a branch? If so, all of the resources examined above
     # led to lower levels then the one we are currently at, so we push a END_BRANCH      # led to lower levels than the one we are currently at, so we push a END_BRANCH
     # marker onto the stack so we don't forget.      # marker onto the stack so we don't forget.
     # Example: For the usual A(BC)(DE)F case, when the iterator goes down the      # Example: For the usual A(BC)(DE)F case, when the iterator goes down the
     # BC branch and gets to C, it will see F as the only next resource, but it's      # BC branch and gets to C, it will see F as the only next resource, but it's
Line 3249  X<symb> X<resource, symb> Line 3315  X<symb> X<resource, symb>
 All resources also have B<symb>s, which uniquely identify a resource  All resources also have B<symb>s, which uniquely identify a resource
 in a course. Many internal LON-CAPA functions expect a symb. A symb  in a course. Many internal LON-CAPA functions expect a symb. A symb
 carries along with it the URL of the resource, and the map it appears  carries along with it the URL of the resource, and the map it appears
 in. Symbs are much larger then resource IDs.  in. Symbs are much larger than resource IDs.
   
 =cut  =cut
   
Line 3325  false. Line 3391  false.
   
 =item * B<randompick>:  =item * B<randompick>:
   
 Returns true for a map if the randompick feature is being used on the  Returns the number of randomly picked items for a map if the randompick
 map. (?)  feature is being used on the map. 
   
   =item * B<randomorder>:
   
   Returns true for a map if the randomorder feature is being used on the
   map.
   
 =item * B<src>:  =item * B<src>:
   
Line 3358  sub randompick { Line 3429  sub randompick {
     my $self = shift;      my $self = shift;
     return $self->parmval('randompick');      return $self->parmval('randompick');
 }  }
   sub randomorder { 
       my $self = shift;
       return ($self->parmval('randomorder') =~ /^yes$/i);
   }
 sub link {  sub link {
     my $self=shift;      my $self=shift;
     if ($self->encrypted()) { return &Apache::lonenc::encrypted($self->src); }      if ($self->encrypted()) { return &Apache::lonenc::encrypted($self->src); }
Line 3434  sub compTitle { Line 3509  sub compTitle {
     }      }
     return $title;      return $title;
 }  }
   
 =pod  =pod
   
 B<Predicate Testing the Resource>  B<Predicate Testing the Resource>
Line 3520  sub contains_problem { Line 3596  sub contains_problem {
     }      }
     return 0;      return 0;
 }  }
   sub map_contains_problem {
       my $self=shift;
       if ($self->is_map()) {
    my $has_problem=
       $self->hasResource($self,sub { $_[0]->is_problem() },1);
    return $has_problem;
       }
       return 0;
   }
 sub is_sequence {  sub is_sequence {
     my $self=shift;      my $self=shift;
     return $self->navHash("is_map_", 1) &&       return $self->navHash("is_map_", 1) && 
Line 3626  sub map_type { Line 3711  sub map_type {
   
 # These functions will be responsible for returning the CORRECT  # These functions will be responsible for returning the CORRECT
 # VALUE for the parameter, no matter what. So while they may look  # VALUE for the parameter, no matter what. So while they may look
 # like direct calls to parmval, they can be more then that.  # like direct calls to parmval, they can be more than that.
 # So, for instance, the duedate function should use the "duedatetype"  # So, for instance, the duedate function should use the "duedatetype"
 # information, rather then the resource object user.  # information, rather than the resource object user.
   
 =pod  =pod
   
Line 3742  sub duedate { Line 3827  sub duedate {
 }  }
 sub handgrade {  sub handgrade {
     (my $self, my $part) = @_;      (my $self, my $part) = @_;
       my @response_ids = $self->responseIds($part);
       if (@response_ids) {
    foreach my $response_id (@response_ids) {
       if (lc($self->parmval("handgrade",$part.'_'.$response_id))
    eq 'yes') {
    return 'yes';
       }
    }
       }
     return $self->parmval("handgrade", $part);      return $self->parmval("handgrade", $part);
 }  }
 sub maxtries {  sub maxtries {
Line 3883  sub discussion_info { Line 3977  sub discussion_info {
 sub getFeedback {  sub getFeedback {
     my $self = shift;      my $self = shift;
     my $source = $self->src();      my $source = $self->src();
       my $symb = $self->symb();
     if ($source =~ /^\/res\//) { $source = substr $source, 5; }      if ($source =~ /^\/res\//) { $source = substr $source, 5; }
     return $self->{NAV_MAP}->getFeedback($source);      return $self->{NAV_MAP}->getFeedback($symb,$source);
 }  }
   
 sub getErrors {  sub getErrors {
     my $self = shift;      my $self = shift;
     my $source = $self->src();      my $source = $self->src();
       my $symb = $self->symb();
     if ($source =~ /^\/res\//) { $source = substr $source, 5; }      if ($source =~ /^\/res\//) { $source = substr $source, 5; }
     return $self->{NAV_MAP}->getErrors($source);      return $self->{NAV_MAP}->getErrors($symb,$source);
 }  }
   
 =pod  =pod

Removed from v.1.394  
changed lines
  Added in v.1.402


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