Diff for /loncom/homework/Attic/lonproblem.pm between versions 1.1 and 1.4

version 1.1, 2000/01/21 20:01:28 version 1.4, 2001/08/06 18:35:51
Line 1 Line 1
 # The LearningOnline Network with CAPA  # The LON-CAPA problem handler
   #
 # Problem Handler  # Problem Handler
 #  #
 # 12/15-01/21 Gerd Kortemeyer  # 12/15-01/21,01/24 Gerd Kortemeyer
   # 4/12 Guy Albertelli
   # 8/6 Scott Harrison
   
 package Apache::lonproblem;  package Apache::lonproblem;
   
Line 11  use Safe; Line 14  use Safe;
 use Apache::File;  use Apache::File;
   
 # ================================================================ Main Handler  # ================================================================ Main Handler
   
 sub handler {  sub handler {
 my $r=shift;      my $r=shift;
 my @parsecontents;      my @parsecontents;
 my $parsestring;      my $parsestring;
 my $outstring;      my $outstring;
       
 {      {
   my $fh=Apache::File->new($r->filename);   my $fh=Apache::File->new($r->filename);
   @parsecontents=<$fh>;   @parsecontents=<$fh>;
 }      }
       
 $parsestring=join('',@parsecontents);      $parsestring=join('',@parsecontents);
       
 print "<form>";      print "<form>";
       
 &xmlparse($r,$parsestring,'web');      &xmlparse($r,$parsestring,'web');
       
 print "\n---------------\n";      print "\n---------------\n";
 print "<form>";      print "<form>";
 &xmlparse($r,$parsestring,'edit');      &xmlparse($r,$parsestring,'edit');
 $outstring=xmlparse($parsestring,'modified');      $outstring=xmlparse($parsestring,'modified');
 print "\n---------------\n$outstring\n";      print "\n---------------\n$outstring\n";
 return 1; #change to ok      return 1; #change to ok
 }  }
   
 # ============================================================= Parsing Routine  # ============================================================= Parsing Routine
 # Takes $parsestring and $target  # Takes $parsestring and $target
   
 sub xmlparse {  sub xmlparse {
     
       my ($r,$parsestring,$target) = @_;
     
       my $safeeval   = new Safe 'Script';
     
       my $parsereval = new Safe 'Parser';
       
       my $parser=HTML::TokeParser->new(\$parsestring);
     
       my $outtext='';
     
   # ---------------------------------------------------------------- Handled tags
   
 my ($r,$parsestring,$target) = @_;      my %toptoplevel  = ( 'problem'    => 'Problem',
    'entryform'  => 'Entry Form',
 my $safeeval = new Safe;   'survey'     => 'Survey',
    'graded'     => 'Manually Graded' );
     
     
   # --------------------------------------------------------------- Toplevel Tags
   
       my %topleveltags = ( 'block'   => 'Condition Block',
    'part'    => 'Problem Part',
    'include' => 'Include Section',
    'answer'  => 'Answerfield',
    'script'  => 'Script', 
    'outtext' => 'Text Block' );
    
   # ---------------------------------------------------------- Preregistered Tags
   
 my $parser=HTML::TokeParser->new(\$parsestring);      my %includetags  = ( 'scriptlib' => 'Script Library',
    'parserlib' => 'Parser Library' );
   # -------------------------------------------------------------Answer type Tags
   
 my $outtext='';      my %answertags   = ( 'capaanswer' => 'CAPA Standard Answers');
   
 # ---------------------------------------------------------------- Handled tags  # -------------------------------------------------------------------- All Tags
   
 my %toptoplevel  = ( 'problem'    => 'Problem',  
                      'entryform'  => 'Entry Form',  
                      'survey'     => 'Survey' );  
   
 my %answertags   = ( 'item'       => 'Question Item',  
                      'inlinetext' => 'Inline Text' );  
   
 my %includetags  = ( 'codelib' => 'Code Library' );  
   
 my %topleveltags = ( 'block'   => 'Condition Block',  
                      'answer'  => 'Answer Field',  
                      'include' => 'Include Section',  
                      'script'  => 'Script',   
                      'outtext' => 'Text Block' );  
   
 my %xmltags      = ( %answertags, %includetags,   
                      %topleveltags, %toptoplevel );  
   
 my $toplevel     = '';  
 my $above        = '';  
   
 my %answertypes  = ( 'true_false'      => 'True/False',  
                      'multiple_choice' => 'Multiple Choice',  
                      'numerical'       => 'Numerical',  
                      'numerical_units' => 'Numerical with Units' );  
   
       my %xmltags      = ( %includetags, %topleveltags, %toptoplevel, 
    %answertags );
     
       my $toplevel     = '';
       my $above        = '';
     
 # --------------------------------------------------- Depth counter for editing  # --------------------------------------------------- Depth counter for editing
   
 my @depthcounter=();      my @depthcounter = ();
 my $depth=-1;      my $depth = -1;
 my $olddepth=-1;      my $olddepth = -1;
   
 # ----------------------------------------------------------------------- Stack  # ----------------------------------------------------------------------- Stack
   
 my @stack=('');      my @stack = ('');
   
 # -------------------------------------------------------------- Init $saveeval  # -------------------------------------------------------------- Init $saveeval
       
       &init_safeeval($safeeval);
   
 if ($target eq 'web') {  # ---------------------------------------------------------- Parse $parsestring
    &init_safeeval($safeeval);  
       my $token;
   
       while ($token = $parser->get_token) {
   # =============================================================================
    if ($token->[0] eq 'S') {
   # =================================================================== Start Tag
   # --------------------------------------------------------------- Depth Counter
       if (defined($xmltags{$token->[1]})) {
    if ($depth<$olddepth-1) {
       $#depthcounter--;
       $olddepth=$depth;
    }
    $depth++;
    $depthcounter[$depth]++;
    if ($depthcounter[$depth] == 1) {
       $olddepth = $depth;
    }
       }  
   # -----------------------------------------------------------------------------
   
   
       if ($target eq 'web') {
    my $sub = "start_$token->[1]";
    {
       no strict 'refs';
       if (defined (&$sub)) { 
    &$sub($r,$token,$parser,$safeeval,\@stack); 
       } else {
    $stack[$#stack] .= $token->[4];
       }
    }
       }
         
       if ($target eq 'edit') {
    my $depthlabel = join('_',@depthcounter);
    if (defined($xmltags{$token->[1]})) {
       if (defined($topleveltags{$token->[1]})) {
    &insertmenu($r,$xmltags{$token->[1]},
       $depthlabel,\%topleveltags);
    $toplevel = $token->[1];
       } else {
    if ($toplevel eq 'answer') {
       &insertmenu($r,$xmltags{$token->[1]},
    $depthlabel,\%answertags);
    }
       }
       my $sub = "start_edit_$token->[1]";
       {
    no strict 'refs';
    if (defined (&$sub)) { 
       &$sub($r,$token,$parser,$xmltags{$token->[1]},
     $depthlabel,$above,\%answertypes,\@stack); 
    }
       } 
    } else {
       $stack[$#stack] .= $token->[4];
    }
       }
       
       if ($target eq 'modified') {
       }
       
   # =============================================================================
    } elsif ($token->[0] eq 'E') {
   # ===================================================================== End Tag
   
       if ($target eq 'web') {
    my $sub = "end_$token->[1]";
    {
       no strict 'refs';
       if (defined (&$sub)) { 
    &$sub($r,$token,$parser,$safeeval,\@stack);
       } else {
    $stack[$#stack] .= $token->[2];
       }
    }
       }
       
       if ($target eq 'edit') {
    if (defined($xmltags{$token->[1]})) {
       my $sub = "end_edit_$token->[1]";
       {
    no strict 'refs';
    if (defined (&$sub)) { 
       &$sub($r,$token,$above,\@stack); 
    }
       } 
    } 
       }
       
       if ($target eq 'modified') {
       }
   # --------------------------------------------------------------- Depth Counter
       if (defined($xmltags{$token->[1]})) { $depth--; }
   # -----------------------------------------------------------------------------
   # =============================================================================
    } elsif ($token->[0] eq 'T') {
   # ================================================================= Parsed Text
       $stack[$#stack] .= $token->[1];
    }
       }
       
       return $outtext;
 }  }
   # =============================================================================
   
 # ---------------------------------------------------------- Parse $parsestring  # --------------------------------------------------------------- Execute Token
   
 my $token;  
   
 while ($token=$parser->get_token) {  
    if ($token->[0] eq 'S') {  # ------------------------------------------------- Helper Routines for Editing
 # ------------------------------------------------------------------- Start Tag  
       if (defined($xmltags{$token->[1]})) {  sub rawprint {
          if ($depth<$olddepth-1) {    my ($r,$data) = @_;
             $#depthcounter--;    $r->print($data);
             $olddepth=$depth;  
          }  
          $depth++;  
          $depthcounter[$depth]++;  
          if ($depthcounter[$depth]==1) {  
             $olddepth=$depth;  
          }  
       }    
       if ($target eq 'web') {  
          my $sub="start_$token->[1]";  
          {  
            no strict 'refs';  
            if (defined (&$sub)) {   
               &$sub($r,$token,$parser,$safeeval,\@stack);   
            } else {  
               $stack[$#stack].=$token->[4];  
            }  
          }  
       }  
       if ($target eq 'edit') {  
          my $depthlabel=join('_',@depthcounter);  
          if (defined($xmltags{$token->[1]})) {  
             if (defined($topleveltags{$token->[1]})) {  
                &insertmenu($r,$xmltags{$token->[1]},  
                            $depthlabel,\%topleveltags);  
               $toplevel=$token->[1];  
             } else {  
                 if ($toplevel eq 'answer') {  
                    &insertmenu($r,$xmltags{$token->[1]},  
                                $depthlabel,\%answertags);  
                 }  
             }  
             my $sub="start_edit_$token->[1]";  
             {  
               no strict 'refs';  
               if (defined (&$sub)) {   
                  &$sub($r,$token,$parser,$xmltags{$token->[1]},  
                        $depthlabel,$above,\%answertypes,\@stack);   
               }  
             }   
          } else {  
             $stack[$#stack].=$token->[4];  
          }  
       }  
       if ($target eq 'modified') {  
       }  
    } elsif ($token->[0] eq 'E') {  
 # --------------------------------------------------------------------- End Tag  
       if ($target eq 'web') {  
          my $sub="end_$token->[1]";  
          {  
            no strict 'refs';  
            if (defined (&$sub)) {   
               &$sub($r,$token,$parser,$safeeval,\@stack);  
            } else {  
               $stack[$#stack].=$token->[2];  
            }  
          }  
       }  
       if ($target eq 'edit') {  
          if (defined($xmltags{$token->[1]})) {  
             my $sub="end_edit_$token->[1]";  
             {  
               no strict 'refs';  
               if (defined (&$sub)) {   
                  &$sub($r,$token,$above,\@stack);   
               }  
             }   
          }   
       }  
       if ($target eq 'modified') {  
       }  
       if (defined($xmltags{$token->[1]})) { $depth--; }  
    } elsif ($token->[0] eq 'T') {  
 # ------------------------------------------------------------------------ Text  
       $stack[$#stack].=$token->[1];  
    }  
 }  }
   
 return $outtext;  sub insertmenu {
       my ($r,$description,$depthlabel,$xmltagsref) = @_;
       &rawprint($r,'<br><table bgcolor="#DDDD33" width="100%"><tr><td>');
       &rawprint($r,"\n".'<select name="mod_menu_'.$depthlabel.'">'."\n");
       &rawprint($r,'<option value="no_changes" selected>(no changes)</option>');
       &rawprint($r,"\n".
         '<option value="delete">Delete '.$description.
         ' Below</option>');
       my $key;
       foreach $key (keys %$xmltagsref) {
    &rawprint($r,"\n".
     '<option value="insert_'.$key.'">Insert '.
     $$xmltagsref{$key}.'</option>');
       }
       &rawprint($r,"\n".'</select></td></tr></table><br>'."\n");
 }  }
   
   # =============================================================================
   # ================================================ Routines for Safe Evaluation
 # =============================================================================  # =============================================================================
   
 # -------------------------------------------- Initialize routines in $safeeval  # -------------------------------------------- Initialize routines in $safeeval
   
 sub init_safeeval {  sub init_safeeval {
    my $safeeval=shift;      my $safeeval = shift;
    my $initprg=<<'ENDINIT';       my $initprg =<<'ENDINIT'; 
   
 # -------------------------------------------- Initializations inside $safeeval  # -------------------------------------------- Initializations inside $safeeval
   
 $e=25;      $e = 25;
 $c=20;      $c = 20;
   
 ENDINIT    ENDINIT
 # ---------------------------------------------------------------- Execute that  # ---------------------------------------------------------------- Execute that
    $safeeval->reval($initprg);      $safeeval->reval($initprg);
 }  
   
 # ------------------------------------------------- Helper Routines for Editing  
   
 sub rawprint {  
    my ($r,$data)=@_;  
    $r->print($data);  
 }  }
   
 sub insertmenu {  # ----------------------------------------------- Routines that use Safe Spaces
    my ($r,$description,$depthlabel,$xmltagsref)=@_;  
    &rawprint($r,'<br><table bgcolor="#DDDD33" width="100%"><tr><td>');  
    &rawprint($r,"\n".'<select name="mod_menu_'.$depthlabel.'">'."\n");  
    &rawprint($r,'<option value="no_changes" selected>(no changes)</option>');  
    &rawprint($r,"\n".  
                 '<option value="delete">Delete '.$description.  
                                                ' Below</option>');  
    my $key;  
    foreach $key (keys %$xmltagsref) {  
       &rawprint($r,"\n".  
                    '<option value="insert_'.$key.'">Insert '.  
                    $$xmltagsref{$key}.'</option>');  
    }  
    &rawprint($r,"\n".'</select></td></tr></table><br>'."\n");  
 }  
    
 # ----------------------------------------------- Helper Routines for Renderers  
   
 sub printout {  sub printout {
    my ($r,$data,$safeeval)=@_;      my ($r,$data,$safespace) = @_;
    $r->print($safeeval->reval('return qq('.$data.');'));      $r->print($safespace->reval('return qq('.$data.');'));
 }  }
   
 sub runfile {  sub runfile {
    my ($r,$filename,$safeeval)=@_;      my ($r,$filename,$safespace) = @_;
    my $includespath=$r->dir_config('lonIncludes');      my $includefile;
    $safeeval->rdo($includespath.'/'.$filename);         if ($filename =~ /^\//) {
    $includefile = $filename;
       } else {
    $includefile = $r->dir_config('lonIncludes');
    $includefile .= '/'.$filename;
       }
       if (-e $includefile) {
    $safespace->rdo($includefile);
       }   
 }  }
   
 sub run {  sub run {
    my ($expression,$safeeval)=@_;      my ($expression,$safespace) = @_;
    $safeeval->reval($expression);         $safespace->reval($expression);   
 }  }
   
 sub booleanexpr {  sub booleanexpr {
    my ($expression,$safeeval)=@_;      my ($expression,$safespace) = @_;
    return $safeeval->reval('return '.$expression.';');      return $safespace->reval('return '.$expression.';');
 }  }
   
 # -------------------------------------------------- Tag Handlers for Rendering  
   # =============================================================================
   # ================================================== Tag Handlers for Rendering
   # =============================================================================
   
 sub start_block {  sub start_block {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    if (!booleanexpr($token->[2]{'condition'},$safeeval)) {      if (!booleanexpr($token->[2]{'condition'},$safeeval)) {
       my $blockdepth=0;   my $blockdepth = 0;
       my $nexttoken;   my $nexttoken;
       while ($nexttoken=$parser->get_tag()) {    while ($nexttoken=$parser->get_tag()) { 
          if ($nexttoken->[0] eq 'block') { $blockdepth++ };      if ($nexttoken->[0] eq 'block') { $blockdepth++ };
          if ($nexttoken->[0] eq '/block') {      if ($nexttoken->[0] eq '/block') {
             if ($blockdepth==0) {    if ($blockdepth == 0) { 
                return;       return; 
             } else {   } else {
                $blockdepth--;      $blockdepth--;
             }   }
          }      }
       }   }
    }      }
    return;      return;
 }  }
   
 sub start_script {  sub start_script {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    $stackref->[$#$stackref+1]='';      $stackref->[$#$stackref+1] = '';
 }  }
   
 sub end_script {  sub end_script {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    &run($stackref->[$#$stackref],$safeeval);      &run($stackref->[$#$stackref],$safeeval);
    $#$stackref--;      $#$stackref--;
 }  }
   
 sub start_outtext {  sub start_outtext {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    $stackref->[$#$stackref+1]='';      $stackref->[$#$stackref+1] = '';
 }  }
   
 sub end_outtext {  sub end_outtext {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    &printout($r,$stackref->[$#$stackref],$safeeval);      &printout($r,$stackref->[$#$stackref],$safeeval);
    $#$stackref--;      $#$stackref--;
 }  }
   
 sub start_inlinetext {  sub start_inlinetext {
    &start_outtext(@_);      &start_outtext(@_);
 }  }
   
 sub end_inlinetext {  sub end_inlinetext {
    &end_outtext(@_);      &end_outtext(@_);
 }  }
   
 sub start_codelib {  sub start_scriptlib {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    &runfile($r,$parser->get_text('/codelib'),$safeeval);      &runfile($r,$parser->get_text('/scriptlib'),$safeeval);
 }  }
   
   sub start_parserlib {
       my ($r,$token,$parser,$safeeval,$stackref) = @_;
       &runfile($r,$parser->get_text('/parserlib'),$parsereval);
   }
   
   
 sub start_answer {  sub start_answer {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    $stackref->[$#$stackref+1]='<answer>::'.      $stackref->[$#$stackref+1] = '<answer>::'.
      join(':',map{$_.':'.$token->[2]->{$_}} @{$token->[3]});      join(':',map{$_.':'.$token->[2]->{$_}} @{$token->[3]});   
    $stackref->[$#$stackref+1]='';      $stackref->[$#$stackref+1] = '';
 }  }
   
 sub end_answer {  sub end_answer {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    my @itemtexts;      my @itemtexts;
    my @itemargs;      my @itemargs;
    my $stackpointer=$#$stackref;      my $stackpointer = $#$stackref;
    while (($stackref->[$stackpointer]!~'<answer>::') && ($stackpointer>0)) {       while (($stackref->[$stackpointer] !~ '<answer>::') &&
       $stackpointer--;      ($stackpointer > 0)) { 
    }   $stackpointer--; 
    my %answerargs=split(/:/,$stackref->[$stackpointer]);      }
       my %answerargs=split(/:/,$stackref->[$stackpointer]);
 }  }
   
 sub start_item {  sub start_item {
    my ($r,$token,$parser,$safeeval,$stackref)=@_;      my ($r,$token,$parser,$safeeval,$stackref) = @_;
    $stackref->[$#$stackref+1]='<item>::'.      $stackref->[$#$stackref+1] = '<item>::'.
      join(':',map{$_.':'.$token->[2]->{$_}} @{$token->[3]});      join(':',map{$_.':'.$token->[2]->{$_}} @{$token->[3]});   
    $stackref->[$#$stackref+1]='';      $stackref->[$#$stackref+1]='';
 }  }
   
 sub end_item {}  sub end_item {}
   
 # ------------------------------------------------------------ Edit Tag Handler  # =============================================================================
   # ==================================================== Tag Handlers for Editing
   # =============================================================================
   
 sub start_edit_outtext {  sub start_edit_outtext {
    my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,      my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,
        $stackref)=@_;   $stackref) = @_;
    &rawprint($r,"\n<h3>$description</h3>".      &rawprint($r,"\n<h3>$description</h3>".
      '<textarea rows="10" cols="80" name="data_'.$depthlabel.'">');        '<textarea rows="10" cols="80" name="data_'.$depthlabel.'">');
    $stackref->[$#$stackref+1]='';      $stackref->[$#$stackref+1] = '';
 }  }
   
 sub end_edit_outtext {  sub end_edit_outtext {
    my ($r,$token,$above,$stackref)=@_;      my ($r,$token,$above,$stackref) = @_;
    &rawprint($r,$stackref->[$#$stackref]."</textarea>\n");         &rawprint($r,$stackref->[$#$stackref]."</textarea>\n");   
    $#$stackref--;      $#$stackref--;
 }  }
   
 sub start_edit_script {  sub start_edit_script {
    &start_edit_outtext(@_);      &start_edit_outtext(@_);
 }  }
   
 sub end_edit_script {  sub end_edit_script {
    &end_edit_outtext(@_);      &end_edit_outtext(@_);
 }  }
   
 sub start_edit_inlinetext {  sub start_edit_inlinetext {
    &start_edit_outtext(@_);      &start_edit_outtext(@_);
 }  }
   
 sub end_edit_inlinetext {  sub end_edit_inlinetext {
    &end_edit_inlinetext(@_);      &end_edit_inlinetext(@_);
 }  }
   
 sub start_edit_block {  sub start_edit_block {
    my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,      my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,
        $stackref)=@_;   $stackref) = @_;
    my $bgcolor=$depthlabel;      my $bgcolor = $depthlabel;
    $bgcolor=~s/\_//g;      $bgcolor =~ s/\_//g;
    $bgcolor=substr(length($bgcolor),-1,1);      $bgcolor = substr(length($bgcolor),-1,1);
    $bgcolor=~tr/1-5/A-E/;      $bgcolor =~ tr/1-5/A-E/;
    $bgcolor=$bgcolor.'FFF'.$bgcolor.'A';      $bgcolor = $bgcolor.'FFF'.$bgcolor.'A';
    &rawprint($r,"\n".'<br><table border="2" cellpadding="10" bgcolor="#'.      &rawprint($r,"\n".'<br><table border="2" cellpadding="10" bgcolor="#'.
                 $bgcolor.        $bgcolor.
                 '" width="100%"><tr><td><h3>'.$description.'</h3>');        '" width="100%"><tr><td><h3>'.$description.'</h3>');
 }  }
   
 sub end_edit_block {  sub end_edit_block {
    my ($r,$token,$above,$stackref)=@_;      my ($r,$token,$above,$stackref) = @_;
    &rawprint($r,"\n".'</td></tr></table><br>');      &rawprint($r,"\n".'</td></tr></table><br>');
 }  }
   
 sub start_edit_answer {  sub start_edit_answer {
    my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,      my ($r,$token,$parser,$description,$depthlabel,$above,$answertyperef,
        $stackref)=@_;   $stackref) = @_;
    start_edit_block(@_);      start_edit_block(@_);
    $above=$token->[2]{'type'};      $above = $token->[2]{'type'};
    &rawprint($r,"\n".'<select name="mod_type_'.$depthlabel.'">');      &rawprint($r,"\n".'<select name="mod_type_'.$depthlabel.'">');
    my $key;      my $key;
    foreach $key (keys %$answertyperef) {      foreach $key (keys %$answertyperef) {
       &rawprint($r,"\n".'<option value="'.$key.'"');   &rawprint($r,"\n".'<option value="'.$key.'"');
       if ($above eq $key) { &rawprint($r,' selected'); }   if ($above eq $key) { &rawprint($r,' selected'); }
       &rawprint($r,'>'.$$answertyperef{$key}.'</option>');   &rawprint($r,'>'.$$answertyperef{$key}.'</option>');
    }      }
    &rawprint($r,"\n".'</select>'."\n");      &rawprint($r,"\n".'</select>'."\n");
 }  }
   
 sub end_edit_answer {  sub end_edit_answer {
    my ($r,$token,$above,$stackref)=@_;      my ($r,$token,$above,$stackref)=@_;
    end_edit_block(@_);      end_edit_block(@_);
 }  }
   
 sub start_edit_include {  sub start_edit_include {
Line 420  sub end_edit_problem { Line 470  sub end_edit_problem {
 }  }
   
 1;  1;
 __END__  
   
   __END__
     
   
   
   

Removed from v.1.1  
changed lines
  Added in v.1.4


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