Diff for /loncom/homework/default_homework.lcpm between versions 1.64 and 1.150

version 1.64, 2003/06/24 20:41:56 version 1.150, 2010/10/18 19:47:31
Line 26 Line 26
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 #  #
 # Guy Albertelli  
 #  
 # 05/25/2001 H. K. Ng  
 # 05/31/2001 H. K. Ng  
 # 12/21/2001 Matthew  
 #  
 #init some globals  #init some globals
 $hidden::RANDOMINIT=0;  $hidden::RANDOMINIT=0;
 $pi=atan2(1,1)*4;  $pi=atan2(1,1)*4;
 $rad2deg=180.0/$pi;  $rad2deg=180.0/$pi;
 $deg2rad=$pi/180.0;  $deg2rad=$pi/180.0;
 $"=' ';  $"=' ';
   use strict;
   {
       my $n = 0;
       my $total = 0;
       my $num_left = 0;
       my @order;
       my $type;
   
       sub init_permutation {
    my ($size,$requested_type) = @_;
    @order = (0..$size-1);
    $n = $size;
    $type = $requested_type;
    if ($type eq 'ordered') {
       $total = $num_left = 1;
    } elsif ($type eq 'unordered') {
       $total = $num_left = &factorial($size);
    } else {
       die("Unkown type: $type");
    }
       }
   
       sub get_next_permutation {
    if ($num_left == $total) {
       $num_left--;
       return \@order;
    }
   
    # Find largest index j with a[j] < a[j+1]
   
    my $j = scalar(@order) - 2;
    while ($order[$j] > $order[$j+1]) {
       $j--;
    }
   
    # Find index k such that a[k] is smallest integer
    # greater than a[j] to the right of a[j]
   
    my $k = scalar(@order) - 1;
    while ($order[$j] > $order[$k]) {
       $k--;
    }
   
    # Interchange a[j] and a[k]
   
    @order[($k,$j)] = @order[($j,$k)];
   
    # Put tail end of permutation after jth position in increasing order
   
    my $r = scalar(@order) - 1;
    my $s = $j + 1;
   
    while ($r > $s) {
       @order[($s,$r)]=@order[($r,$s)];
       $r--;
       $s++;
    }
   
    $num_left--;
    return(\@order);
       }
       
       sub get_permutations_left {
    return $num_left;
       }
   }
   
   sub check_commas {
       my ($response)=@_;
       #print("$response ");
       my @numbers=split(',',$response);
       #print(" numbers ".join('-',@numbers)." ");
       if (scalar(@numbers) > 1) {
           #print(" numbers[0] ".$numbers[0]." "); 
    if (length($numbers[0]) > 3 || length($numbers[0]) == 0) { return -1; }
    shift(@numbers);
    #print(" numbers ".scalar(@numbers)." ");
    while (scalar(@numbers) > 1) {
       #print(" numbers ".join('-',@numbers)." ");
       if (length($numbers[0]) != 3) { return -2; }
       shift(@numbers);
    }
    my ($number)=split('\.',$numbers[0]);
    #print(" number ".$number." ");
    #print(" numbers[0] ".$numbers[0]." ");
    if (length($number) != 3) { return -3; }
       } else {
    my ($number)=split('\.',$numbers[0]);
    if (length($number) > 3) { return -4; }
       }
       return 1;
   }
   
   
 sub caparesponse_check {  sub caparesponse_check {
   #not properly used yet: calc      my ($answer,$response)=@_;
   #not to be used: $ans_fmt      #not properly used yet: calc
   my ($type,$tol,$sig,$ans_fmt,$unit,$calc,$samples) =      #not to be used: $ans_fmt
     eval $_[2].      my $type=$LONCAPA::CAPAresponse_args{'type'};
       ';return ($type,$tol,$sig,$ans_fmt,$unit,$calc,$samples);';      my $tol=$LONCAPA::CAPAresponse_args{'tol'};
       my $sig=$LONCAPA::CAPAresponse_args{'sig'};
   my $tol_type=''; # gets it's value from whether tol has a % or not done      my $ans_fmt=$LONCAPA::CAPAresponse_args{'format'};
   my $sig_lbound=''; #done      my $unit=$LONCAPA::CAPAresponse_args{'unit'};
   my $sig_ubound=''; #done      my $calc=$LONCAPA::CAPAresponse_args{'calc'};
   my ($answer,$response,$expr)=@_;      my $samples=$LONCAPA::CAPAresponse_args{'samples'};
       
       my $tol_type=''; # gets it's value from whether tol has a % or not done
   #type's definitons come from capaParser.h      my $sig_lbound=''; #done
   my $message='';      my $sig_ubound=''; #done
   #remove leading and trailing whitespace  
   if ($response=~ /^\s|\s$/) {  
     $response=~ s:^\s+|\s+$::g;      #type's definitons come from capaParser.h
     $message .="Removed ws now :$response:\n";  
   } else {      #remove leading and trailing whitespace
     $message .="no ws in :$response:\n";      if (!defined($response)) {
   }   $response='';
       }
   if (length($response) > 500) { return "TOO_LONG: Answer too long"; }      if ($response=~ /^\s|\s$/) {
    $response=~ s:^\s+|\s+$::g;
   if ($type eq '' ) {   &LONCAPA_INTERNAL_DEBUG("Removed ws now :$response:");
     $message .= "Didn't find a type :$type:$expr: defaulting\n";      }
     if ( $answer eq ($answer *1.0)) { $type = 2;  
     } else { $type = 3; }      #&LONCAPA_INTERNAL_DEBUG(" type is $type ");
   } else {      if ($type eq 'cs' || $type eq 'ci') {
          if ($type eq 'cs')    { $type = 4;   #for string answers make sure all places spaces occur, there is 
     } elsif ($type eq 'ci')    { $type = 3;          #really only 1 space, in both the answer and the response
     } elsif ($type eq 'mc')    { $type = 5;   $answer=~s/ +/ /g;
     } elsif ($type eq 'fml')   { $type = 8;   $response=~s/ +/ /g;
     } elsif ($type eq 'subj')  { $type = 7;      } elsif ($type eq 'mc') {
     } elsif ($type eq 'float') { $type = 2;   $answer=~s/[\s,]//g;
     } elsif ($type eq 'int')   { $type = 1;   $response=~s/[\s,]//g;
     } else { return "ERROR: Unknown type of answer: $type" }      }
   }      if ($type eq 'float' && $unit=~/\$/) {
    if ($response!~/^\$|\$$/)  { return ('NO_UNIT', undef); }
   my $points;   $response=~s/\$//g;
   my $id_list;      }
   #formula type setup the sample points      if ($type eq 'float' && $unit=~/\,/ && (&check_commas($response)<0)) {
   if ($type eq '8') {   return "COMMA_FAIL:";
     ($id_list,$points)=split(/@/,$samples);      }
     $message.="Found :$id_list:$points: points in $samples\n";      $ans_fmt=~s/\W//g;
   }      $unit=~s/[\$,]//g;
   if ($tol eq '') {      if ($type eq 'float') { $response=~s/,//g; }
     $tol=0.0;  
     $tol_type=1; #TOL_ABSOLUTE      if (length($response) > 500) { return ('TOO_LONG',undef); }
   } else {  
     if ($tol =~ /%$/) {      if ($type eq '' ) {
       chop $tol;   &LONCAPA_INTERNAL_DEBUG("Didn't find a type :$type: defaulting");
       $tol_type=2; #TOL_PERCENTAGE   if ( $answer eq ($answer *1.0)) { $type = 2;
     } else {        } else { $type = 3; }
       $tol_type=1; #TOL_ABSOLUTE      } else {
     }   if    ($type eq 'cs')    { $type = 4; }
   }   elsif ($type eq 'ci')    { $type = 3 }
    elsif ($type eq 'mc')    { $type = 5; }
   if ($sig eq '') {   elsif ($type eq 'fml')   { $type = 8; }
     $sig_lbound = 0; #SIG_LB_DEFAULT          elsif ($type eq 'math')  { $type = 9; }
     $sig_ubound =15; #SIG_UB_DEFAULT   elsif ($type eq 'subj')  { $type = 7; }
   } else {   elsif ($type eq 'float') { $type = 2; }
     ($sig_lbound,$sig_ubound) = split /,/,$sig;   elsif ($type eq 'int')   { $type = 1; }
     if (!defined($sig_lbound)) {   else { return ('ERROR', "Unknown type of answer: $type") }
       $sig_lbound = 0; #SIG_LB_DEFAULT      }
       $sig_ubound =15; #SIG_UB_DEFAULT  
     }      my $points;
     if (!defined($sig_ubound)) { $sig_ubound=$sig_lbound; }      my $id_list;
   }      #formula type setup the sample points
   my $result = &caparesponse_capa_check_answer($response,$answer,$type,      if ($type eq '8') {
        $tol_type,$tol,   ($id_list,$points)=split(/@/,$samples);
        $sig_lbound,$sig_ubound,   &LONCAPA_INTERNAL_DEBUG("Found :$id_list:$points: points in $samples");
        $ans_fmt,$unit,$calc,$id_list,      }
        $points,$external::randomseed);      if ($tol eq '') {
    $tol=0.0;
   if    ($result == '1') { $result='EXACT_ANS'; }    $tol_type=1; #TOL_ABSOLUTE
   elsif ($result == '2') { $result='APPROX_ANS'; }      } else {
   elsif ($result == '3') { $result='SIG_FAIL'; }   if ($tol =~ /%$/) {
   elsif ($result == '4') { $result='UNIT_FAIL'; }      chop $tol;
   elsif ($result == '5') { $result='NO_UNIT'; }      $tol_type=2; #TOL_PERCENTAGE
   elsif ($result == '6') { $result='UNIT_OK'; }   } else {
   elsif ($result == '7') { $result='INCORRECT'; }      $tol_type=1; #TOL_ABSOLUTE
   elsif ($result == '8') { $result='UNIT_NOTNEEDED'; }   }
   elsif ($result == '9') { $result='ANS_CNT_NOT_MATCH'; }      }
   elsif ($result =='10') { $result='SUB_RECORDED'; }  
   elsif ($result =='11') { $result='BAD_FORMULA'; }      ($sig_ubound,$sig_lbound)=&LONCAPA_INTERNAL_get_sigrange($sig);
   elsif ($result =='12') { $result='WANTED_NUMERIC'; }  
   else  {$result = "ERROR: Unknown Result:$result:$@:";}      my $reterror="";
       my $result;
   return "$result:\nError $error:\nAnswer $answer:\nResponse $response:\n type-$type|$tol|$tol_type|$sig:$sig_lbound:$sig_ubound|$unit|\n$message$expr";      if (($type eq '9') || ($type eq '8')) {
 }          if ($response=~/\=/) {
               return ('BAD_FORMULA','Please submit just an expression, not an equation.');
 sub get_array_args {          } elsif ($response =~ /\,/ and $response !~ /^\s*\{.*\}\s*$/) {
   my ($expr,$arg)=@_;              return ('BAD_FORMULA');
   # do these first, because who knows what varname the instructor might have used          }
   # but it probably isn't $CAPARESPONSE_CHECK_LIST_answer      }
   my $CAPARESPONSE_CHECK_LIST_answer = eval $expr.';return $'.$arg; #' stupid emacs      if ($type eq '9') {
   my $GET_ARRAY_ARGS_result="expr is $expr\narg is $arg\nfirst answer guess is $CAPARESPONSE_CHECK_LIST_answer\n";        $result = &maxima_check(&maxima_cas_formula_fix($response),&maxima_cas_formula_fix($answer),\$reterror);
   my @GET_ARRAY_ARGS_list;      } else {
   if ($CAPARESPONSE_CHECK_LIST_answer =~ /^\s*[\$\@]/) {   if ($type eq '8') { # fml type
     (@GET_ARRAY_ARGS_list) = eval $CAPARESPONSE_CHECK_LIST_answer;      $response = &capa_formula_fix($response);
   }      $answer   = &capa_formula_fix($answer);
   $GET_ARRAY_ARGS_result.="error:$@:\n";   }
   # if the eval fails just use what is in the answer exactly         $result = &caparesponse_capa_check_answer($response,$answer,$type,
   if (!(@GET_ARRAY_ARGS_list) || !defined($GET_ARRAY_ARGS_list[0])) {   $tol_type,$tol,
     $GET_ARRAY_ARGS_result.="list zero is undefined\n";   $sig_lbound,$sig_ubound,
     $GET_ARRAY_ARGS_list[0]=$CAPARESPONSE_CHECK_LIST_answer;   $ans_fmt,$unit,$calc,$id_list,
   }   $points,$external::randomseed,
   return $GET_ARRAY_ARGS_result,@GET_ARRAY_ARGS_list;   \$reterror);
       }
       if    ($result == '1') { $result='EXACT_ANS'; } 
       elsif ($result == '2') { $result='APPROX_ANS'; }
       elsif ($result == '3') { $result='SIG_FAIL'; }
       elsif ($result == '4') { $result='UNIT_FAIL'; }
       elsif ($result == '5') { $result='NO_UNIT'; }
       elsif ($result == '6') { $result='UNIT_OK'; }
       elsif ($result == '7') { $result='INCORRECT'; }
       elsif ($result == '8') { $result='UNIT_NOTNEEDED'; }
       elsif ($result == '9') { $result='ANS_CNT_NOT_MATCH'; }
       elsif ($result =='10') { $result='SUB_RECORDED'; }
       elsif ($result =='11') { $result='BAD_FORMULA'; }
       elsif ($result =='12' && !$response) { $result='MISSING_ANSWER'; }
       elsif ($result =='12') { $result='WANTED_NUMERIC'; }
       elsif ($result =='13') { $result='UNIT_INVALID_INSTRUCTOR'; }
       elsif ($result =='141') { $result='UNIT_INVALID_STUDENT'; }
       elsif ($result =='142') { $result='UNIT_INVALID_STUDENT'; }
       elsif ($result =='143') { $result='UNIT_INVALID_STUDENT'; }
       elsif ($result =='15') { $result='UNIT_IRRECONCIBLE'; }
       else  {$result = "ERROR: Unknown Result:$result:$@:";}
   
       &LONCAPA_INTERNAL_DEBUG("RetError $reterror: Answer $answer: Response $response:  type-$type|$tol|$tol_type|$sig:$sig_lbound:$sig_ubound|$unit|");
       &LONCAPA_INTERNAL_DEBUG(" $answer $response $result ");
       return ($result,$reterror);
 }  }
   
   
 sub caparesponse_check_list {  sub caparesponse_check_list {
   my ($response,$expr)=@_;      my $responses=$LONCAPA::CAPAresponse_args{'response'};
 #  $expr =~ s/\\/\\\\/g;      &LONCAPA_INTERNAL_DEBUG("args ".join(':',%LONCAPA::CAPAresponse_args));
 #  $expr =~ s/\'/\\\'/g;      my $type = $LONCAPA::CAPAresponse_args{'type'};
 #  my ($result,@list) = &get_array_args($expr,'answer');      my $answerunit=$LONCAPA::CAPAresponse_args{'unit'};
 #  $expr =~ s/\\\'/\'/g;      &LONCAPA_INTERNAL_DEBUG("Got type :$type: answer unit :$answerunit:\n");
 #  $expr =~ s/\\\\/\\/g;      
   my ($result,@list);      my $num_input_lines =
   @list=@CAPARESPONSE_CHECK_LIST_answer;   scalar(@{$LONCAPA::CAPAresponse_answer->{'answers'}});
   my $aresult='';      
   my $current_answer;      if ($type ne '' ) {
   my $answers=join(':',@list);   if (scalar(@$responses) < $num_input_lines) {
   $result.="Got response :$answers:\n";      return 'MISSING_ANSWER';
   my @responselist;   }
   my $type =eval $expr.';return $type;';   if (scalar(@$responses) > $num_input_lines) {
   if ($type ne '' && $#list > 0) {      return 'EXTRA_ANSWER';
     (@responselist)=split /,/,$response;   }
   } else {  
     (@responselist)=($response);      }
   }  
   my $unit='';      foreach my $which (0..($num_input_lines-1)) {
   $result.="Initial final response :$responselist['-1']:\n";   my $answer_size = 
   if ($type eq '' || $type eq 'float') {      scalar(@{$LONCAPA::CAPAresponse_answer->{'answers'}[$which]});
     #for numerical problems split off the unit   if ($type ne '' 
     if ( $responselist['-1']=~ /(.*[^\s])\s+([^\s]+)/ ) {      && $answer_size > 1) {
       $responselist['-1']=$1;      $responses->[$which]=[split(/,/,$responses->[$which])];
       $unit=$2;   } else {
     }      $responses->[$which]=[$responses->[$which]];
   }   }
   $result.="Final final response :$responselist['-1']:\n";      }
   $result.=":$#list: answers\n";      foreach my $which (0..($num_input_lines-1)) {
   $unit=~s/\s//;   my $answer_size = 
   my $i=0;      scalar(@{$LONCAPA::CAPAresponse_answer->{'answers'}[$which]});
   my $awards='';   my $response_size = 
   for ($i=0; $i<@list;$i++) {      scalar(@{$responses->[$which]});
     $result.="trying answer :$list[$i]:\n";   if ($answer_size > $response_size) {
     my $thisanswer=$list[$i];      return 'MISSING_ANSWER';
 #    $thisanswer=~ s/\\/\\\\/g;   }
 #    $thisanswer =~ s/\'/\\\'/g;   if ($answer_size < $response_size) {
     $result.="trying answer :$thisanswer:\n";      return 'EXTRA_ANSWER';
     if ($unit eq '') {   }
       $aresult=&caparesponse_check($thisanswer,$responselist[$i],      }
      $expr);  
     } else {      &LONCAPA_INTERNAL_DEBUG("Initial final response :$responses->[0][-1]:");
       $aresult=&caparesponse_check($thisanswer,$responselist[$i]." $unit",      my $unit;
    $expr);      if ($type eq 'float' || $type eq '') {
     }   #for numerical problems split off the unit
     my ($temp)=split /:/, $aresult;  # if ( $responses->[0][-1]=~ /(.*[^\s])\s+([^\s]+)/ ) {
     $awards.="$temp,";          if ( $responses->[0][-1]=~ /^([\d\.\,\s\$]*(?:(?:[xX\*]10[\^\*]*|[eE]*)[\+\-]*\d*)*(?:^|\S)\d+)([\$\s\w\^\*\/\(\)\+\-]*[^\d\.\s\,][\$\s\w\^\*\/\(\)\+\-]*)$/ ) {
     $result.=$aresult;      $responses->[0][-1]=$1;
   }      $unit=&capa_formula_fix($2);
   chop $awards;              &LONCAPA_INTERNAL_DEBUG("Found unit :$unit:");
   return "$awards:\n$result";   }
       }
       &LONCAPA_INTERNAL_DEBUG("Final final response :$responses->[0][-1]:$unit:");
       $unit=~s/\s//;
       my $error;
       foreach my $response (@$responses) {
          foreach my $element (@$response) {
             if (($type eq 'float') || (($type eq '') && ($unit ne ''))) {
                 $element =~ s/\s//g;
             }
             my $appendunit=$unit;
   # Deal with percentages
   # unit is unit entered by student, answerunit is unit by author
   # Deprecated: divide answer by 100 if student entered percent,
   # but author did not. Too much confusion
   #          if (($unit=~/\%/) && ($answerunit ne '%'))  {
   #             $element=$element/100;
   #             $appendunit=~s/\%//;
   #          }    
   # Author entered percent, student did not
             if (($unit!~/\%/) && ($answerunit=~/\%/)) {
                $element=$element*100;
                $appendunit='%'.$appendunit;
             }
   # Zero does not need a dimension
             if (($element==0) && ($unit!~/\w/) && ($answerunit=~/\w/)) {
                $appendunit=$answerunit;
             }
             if ($appendunit ne '') {
                 $element .= " $appendunit";
             }  
             &LONCAPA_INTERNAL_DEBUG("Made response element :$element:");
          }
       }
       
       foreach my $thisanswer (@{ $LONCAPA::CAPAresponse_answer->{'answers'} }) {
    if (!defined($thisanswer)) {
       return ('ERROR','answer was undefined');
    }
       }
   
       my $allow_control_char = 0;
       my $control_chars_removed = 0;
       if ($type eq 'cs' || $type eq 'ci') {
           if (ref($LONCAPA::CAPAresponse_answer->{'answers'}) eq 'ARRAY') {
               foreach my $strans (@{$LONCAPA::CAPAresponse_answer->{'answers'}}) {
                   if ($strans =~ /[\000-\037]/) {
                       $allow_control_char = 1;
                   }
               }
           }
       }
   
   #    &LONCAPA_INTERNAL_DEBUG(&LONCAPA_INTERNAL_Dumper($responses));
       my %memoized;
       if ($LONCAPA::CAPAresponse_answer->{'type'}  eq 'ordered') {
    for (my $i=0; $i<scalar(@$responses);$i++) {
       my $answer   = $LONCAPA::CAPAresponse_answer->{'answers'}[$i];
       my $response = $responses->[$i];
       my $key = "$answer\0$response";
       my (@awards,@msgs);
       for (my $j=0; $j<scalar(@$response); $j++) {
                   if ($type eq 'cs' || $type eq 'ci') {
                       unless ($allow_control_char) {
                           if ($response->[$j] =~ /[\000-\037]/) { 
                               $response->[$j] =~ s/[\000-\037]//g;
                               $control_chars_removed = 1;
                           }  
                       }
                   }
    my ($award,$msg) = &caparesponse_check($answer->[$j],
          $response->[$j]);
                   if ($type eq 'cs' || $type eq 'ci') {
                       $error = &verify_stringresponse($type,$award,$response->[$j],
                                                       $answer->[$j]);
                   }
    push(@awards,$award);
    push(@msgs,  $msg);
       }
       my ($award,$msg) = 
    &LONCAPA_INTERNAL_FINALIZEAWARDS(\@awards,\@msgs);
       $memoized{$key} = [$award,$msg];
    }
       } else {
    #FIXME broken with unorder responses where one is a <value>
           #      and the other is a <vector> (need to delay parse til
           #      inside the loop?)
    foreach my $response (@$responses) {
       my $response_size = scalar(@{$response});
       foreach my $answer (@{ $LONCAPA::CAPAresponse_answer->{'answers'} }) {
    my $key = "$answer\0$response";
    my $answer_size =  scalar(@{$answer});
    my ($award,$msg);
    if ($answer_size > $response_size) {
       $award = 'MISSING_ANSWER';
    } elsif ($answer_size < $response_size) {
       $award = 'EXTRA_ANSWER';
    } else {
       my (@awards,@msgs);
       for (my $j=0; $j<scalar(@$response); $j++) {
                           if ($type eq 'cs' || $type eq 'ci') {
                               unless ($allow_control_char) {
                                   if ($response->[$j] =~ /[\000-\037]/) {
                                       $response->[$j] =~ s/[\000-\037]//g;
                                       $control_chars_removed = 1;
                                   }
                               }
                           }
    my ($award,$msg) = &caparesponse_check($answer->[$j],
          $response->[$j]);
                           if ($type eq 'cs' || $type eq 'ci') {
                               $error = &verify_stringresponse($type,$award,$response->[$j],
                                                               $answer->[$j]);
                           }
    push(@awards,$award);
    push(@msgs,  $msg);
       }
       ($award,$msg) = 
    &LONCAPA_INTERNAL_FINALIZEAWARDS(\@awards,\@msgs);
    }
    $memoized{$key} = [$award,$msg];
       }
    }
       }
   
       my ($final_award,$final_msg);
       &init_permutation(scalar(@$responses),
         $LONCAPA::CAPAresponse_answer->{'type'});
   
       # possible FIXMEs
       # - significant time is spent calling non-safe space routine
       #   from safe space
       # - early outs could be possible with classifying awards is to stratas
       #   and stopping as so as hitting the top strata 
       # - some early outs also might be possible with check ing the 
       #   memoized hash of results (is correct even possible? etc.)
   
       my (@final_awards,@final_msg);
       while( &get_permutations_left() ) {
    my $order = &get_next_permutation();
    my (@awards, @msgs, $i);
    foreach my $thisanswer (@{ $LONCAPA::CAPAresponse_answer->{'answers'} }) {
       my $key = "$thisanswer\0".$responses->[$order->[$i]];
       push(@awards,$memoized{$key}[0]);
       push(@msgs,$memoized{$key}[1]);
       $i++;
   
    }
    &LONCAPA_INTERNAL_DEBUG(" all awards ".join(':',@awards));
   
    my ($possible_award,$possible_msg) = 
       &LONCAPA_INTERNAL_FINALIZEAWARDS(\@awards,\@msgs);
    &LONCAPA_INTERNAL_DEBUG(" pos awards ".$possible_award);
    push(@final_awards,$possible_award);
    push(@final_msg,$possible_msg);
       }
   
       &LONCAPA_INTERNAL_DEBUG(" all final_awards ".join(':',@final_awards));
       my ($final_award,$final_msg) = 
    &LONCAPA_INTERNAL_FINALIZEAWARDS(\@final_awards,\@final_msg,undef,1);
       return ($final_award,$final_msg,$error,$control_chars_removed);
   }
   
   sub verify_stringresponse {
       my ($type,$award,$resp,$ans) = @_;
       return if ($award eq 'EXACT_ANS');
       my $error;
       if ($resp =~ /^\s|\s$/) {
           $resp =~ s{^\s+|\s+$}{}g;
       }
       if ($ans =~ /^\s|\s$/) {
           $ans =~ s{^\s+|\s+$}{}g;
       }
       if ($type eq 'ci') {
           $resp = lc($resp);
           $ans = lc($ans);
       }
       if ($resp eq $ans) {
           if ($award eq 'INCORRECT') {
               $error = 'MISGRADED';
           }
       }
       return $error;
   }
   
   sub cas {
       my ($system,$input,$library)=@_;
       my $output;
       my $dump;
       if ($system eq 'maxima') {
          $output=&maxima_eval($input,$library);
       } elsif ($system eq 'R') {
          ($output,$dump)=&r_eval($input,$library,0);
       } else {
          $output='Error: unrecognized CAS';
       }
       return $output;
   }
   
   sub cas_hashref {
       my ($system,$input,$library)=@_;
       if ($system eq 'maxima') {
          return 'Error: unsupported CAS';
       } elsif ($system eq 'R') {
          return &r_eval($input,$library,1);
       } else {
          return 'Error: unrecognized CAS';
       }
   }
   
   #
   # cas_hashref_entry takes a list of indices and gets the entry in a hash generated by Rreturn.
   # Call: cas_hashref_entry(Rvalue, index1, index2, ...) where Rvalue is a hash returned by Rreturn.
   # Rentry will return the first scalar value it encounters (ignoring excess indices).
   # If an invalid key is given, it returns undef.
   #
   sub cas_hashref_entry {
       return &Rentry(@_);
   }
   
   #
   # cas_hashref_array takes a list of indices and gets a column array from a hash generated by Rreturn.
   # Call: cas_hashref_array(Rvalue, index1, index2, ...) where Rvalue is a hash returned by Rreturn.
   # If an invalid key is given, it returns undef.
   #
   sub cas_hashref_array {
       return &Rarray(@_);
 }  }
   
 sub tex {  sub tex {
   if ( $external::target eq "tex" ) {      if ( $external::target eq "tex" ) {
     return $_[0];   return $_[0];
   } else {      } else {
     return $_[1];   return $_[1];
   }      }
 }  }
   
 sub var_in_tex {  sub var_in_tex {
   if ( $external::target eq "tex" ) {      if ( $external::target eq "tex" ) {
     return $_[0];   return $_[0];
   } else {      } else {
     return "";   return "";
   }      }
 }  }
   
 sub web {  sub web {
   if ( $external::target eq "tex" ) {      if ( $external::target eq "tex" ) {
     return $_[1];   return $_[1];
   } else {  
     if ( $external::target eq "web" || $external::target eq "answer") {  
       return $_[2];  
     } else {      } else {
       return $_[0];   if ( $external::target eq "web" || $external::target eq "answer") {
       return $_[2];
    } else {
       return $_[0];
    }
     }      }
   }  
 }  }
   
 sub html {  sub html {
   if ( $external::target eq "web" ) {      if ( $external::target eq "web" ) {
     return shift;   return shift;
   }      }
 }  }
   
 sub hinton {  sub hinton {
   return 0;      return 0;
 }  }
   
 sub random {  sub random {
Line 249  sub random { Line 588  sub random {
     if ( ! $hidden::RANDOMINIT ) {      if ( ! $hidden::RANDOMINIT ) {
  if ($external::randomseed == 0) { $external::randomseed=1; }   if ($external::randomseed == 0) { $external::randomseed=1; }
  if ($external::randomseed =~/,/) {   if ($external::randomseed =~/,/) {
     my ($num1,$num2)=split(/,/,$seed);      my ($num1,$num2)=split(/,/,$external::randomseed);
       &random_set_seed(1,abs($num1));
    } elsif ($external::randomseed =~/:/) {
       my ($num1,$num2)=split(/:/,$external::randomseed);
     &random_set_seed(abs($num1),abs($num2));      &random_set_seed(abs($num1),abs($num2));
  } else {   } else {
     &random_set_seed(1,int(abs($external::randomseed)));      &random_set_seed(1,int(abs($external::randomseed)));
Line 264  sub random { Line 606  sub random {
 }  }
   
 sub random_normal {  sub random_normal {
   my ($item_cnt,$seed,$av,$std_dev) = @_;      my ($item_cnt,$seed,$av,$std_dev) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_normal($item_cnt,$av,$std_dev);      @retArray=&math_random_normal($item_cnt,$av,$std_dev);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_beta {  sub random_beta {
   my ($item_cnt,$seed,$aa,$bb) = @_;      my ($item_cnt,$seed,$aa,$bb) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_beta($item_cnt,$aa,$bb);      @retArray=&math_random_beta($item_cnt,$aa,$bb);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_gamma {  sub random_gamma {
   my ($item_cnt,$seed,$a,$r) = @_;      my ($item_cnt,$seed,$a,$r) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_gamma($item_cnt,$a,$r);      @retArray=&math_random_gamma($item_cnt,$a,$r);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_exponential {  sub random_exponential {
   my ($item_cnt,$seed,$av) = @_;      my ($item_cnt,$seed,$av) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_exponential($item_cnt,$av);      @retArray=&math_random_exponential($item_cnt,$av);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_poisson {  sub random_poisson {
   my ($item_cnt,$seed,$mu) = @_;      my ($item_cnt,$seed,$mu) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_poisson($item_cnt,$mu);      @retArray=&math_random_poisson($item_cnt,$mu);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_chi {  sub random_chi {
   my ($item_cnt,$seed,$df) = @_;      my ($item_cnt,$seed,$df) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_chi_square($item_cnt,$df);      @retArray=&math_random_chi_square($item_cnt,$df);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_noncentral_chi {  sub random_noncentral_chi {
   my ($item_cnt,$seed,$df,$nonc) = @_;      my ($item_cnt,$seed,$df,$nonc) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_noncentral_chi_square($item_cnt,$df,$nonc);      @retArray=&math_random_noncentral_chi_square($item_cnt,$df,$nonc);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_f {  sub random_f {
   my ($item_cnt,$seed,$dfn,$dfd) = @_;      my ($item_cnt,$seed,$dfn,$dfd) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_f($item_cnt,$dfn,$dfd);      @retArray=&math_random_f($item_cnt,$dfn,$dfd);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_noncentral_f {  sub random_noncentral_f {
   my ($item_cnt,$seed,$dfn,$dfd,$nonc) = @_;      my ($item_cnt,$seed,$dfn,$dfd,$nonc) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_noncentral_f($item_cnt,$dfn,$dfd,$nonc);      @retArray=&math_random_noncentral_f($item_cnt,$dfn,$dfd,$nonc);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_multivariate_normal {  sub random_multivariate_normal {
   my ($item_cnt,$seed,$mean,$covar) = @_;      my ($item_cnt,$seed,$mean,$covar) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_multivariate_normal($item_cnt,@$mean,@$covar);      my @retArray=&math_random_multivariate_normal($item_cnt,@$mean,@$covar);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_multinomial {  sub random_multinomial {
   my ($item_cnt,$seed,@p) = @_;      my ($item_cnt,$seed,@p) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_multinomial($item_cnt,@p);      my @retArray=&math_random_multinomial($item_cnt,@p);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_permutation {  sub random_permutation {
   my ($seed,@inArray) = @_;      my ($seed,@inArray) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_permutation(@inArray);      @retArray=&math_random_permutation(@inArray);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_uniform {  sub random_uniform {
   my ($item_cnt,$seed,$low,$high) = @_;      my ($item_cnt,$seed,$low,$high) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_uniform($item_cnt,$low,$high);      @retArray=&math_random_uniform($item_cnt,$low,$high);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_uniform_integer {  sub random_uniform_integer {
   my ($item_cnt,$seed,$low,$high) = @_;      my ($item_cnt,$seed,$low,$high) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_uniform_integer($item_cnt,$low,$high);      @retArray=&math_random_uniform_integer($item_cnt,$low,$high);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_binomial {  sub random_binomial {
   my ($item_cnt,$seed,$nt,$p) = @_;      my ($item_cnt,$seed,$nt,$p) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_binomial($item_cnt,$nt,$p);      @retArray=&math_random_binomial($item_cnt,$nt,$p);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub random_negative_binomial {  sub random_negative_binomial {
   my ($item_cnt,$seed,$ne,$p) = @_;      my ($item_cnt,$seed,$ne,$p) = @_;
   my @oldseed=&random_get_seed();      my @oldseed=&random_get_seed();
   my @retArray;      my @retArray;
   &random_set_seed_from_phrase($seed);      &random_set_seed_from_phrase($seed);
   @retArray=&math_random_negative_binomial($item_cnt,$ne,$p);      @retArray=&math_random_negative_binomial($item_cnt,$ne,$p);
   &random_set_seed(@oldseed);      &random_set_seed(@oldseed);
   return @retArray;      return @retArray;
 }  }
   
 sub abs { abs(shift) }  sub abs { CORE::abs(shift) }
 sub sin { sin(shift) }  sub sin { CORE::sin(shift) }
 sub cos { cos(shift) }  sub cos { CORE::cos(shift) }
 sub exp { exp(shift) }  sub exp { CORE::exp(shift) }
 sub int { int(shift) }  sub int { CORE::int(shift) }
 sub log { log(shift) }  sub log { CORE::log(shift) }
 sub atan2 { atan2($_[0],$_[1]) }  sub atan2 { CORE::atan2($_[0],$_[1]) }
 sub sqrt { sqrt(shift) }  sub sqrt { CORE::sqrt(shift) }
   
 sub tan  { CORE::sin($_[0]) / CORE::cos($_[0]) }  sub tan  { CORE::sin($_[0]) / CORE::cos($_[0]) }
 #sub atan { atan2($_[0], 1); }  #sub atan { atan2($_[0], 1); }
Line 487  sub floor  {return (($_[0]-CORE::int($_[ Line 829  sub floor  {return (($_[0]-CORE::int($_[
 #sub floor {return int($_[0]); }  #sub floor {return int($_[0]); }
   
 sub format {  sub format {
   my ($value,$fmt)=@_;      my ($value,$fmt)=@_;
   my $dollarmode;      my ($dollarmode,$commamode,$alwaysperiod,$options);
   if ($fmt =~ /^\$(.*)/) { $fmt=$1; $dollarmode=1; }       if ($fmt =~ /^([^\d]*)(.*)/) { $options=$1; $fmt=$2; } 
   my $result=sprintf('%.'.$fmt,$value);      #if ($options =~ /\$/) { $dollamode=1; }
   $result=~s/(E[+-]*)0/$1/;      #if ($options =~ /,/)  { $commamode=1; }
   if ($dollarmode) {$result=&dollarmode($result);}      if ($options =~ /\./) { $alwaysperiod=1; }
   return $result;      my $result;
       if ($fmt=~/s$/i) {
    $result=&format_significant_figures($value,$fmt);
       } else {
    $fmt=~s/e/E/g;
    $result=sprintf('%.'.$fmt,$value);
    if ($alwaysperiod && $fmt eq '0f') { $result .='.'; }
    $result=~s/(E[+-]*)0/$1/;
       }
       #if ($dollarmode) {$result=&dollarformat($result);}
       #if ($commamode) {$result=&commaformat($result);}
       return $result;
   }
   
   sub chemparse {
       my ($reaction) = @_;
       my @tokens = split(/(\s\+|\->|<=>|<\-|\.)/,$reaction);
       my $formula = '';
       foreach my $token (@tokens) {
    if ($token eq '->' ) {
       $formula .= '<m>\ensuremath{\rightarrow}</m> ';
       next;
    }
    if ($token eq '<-' ) {
       $formula .= '<m>\ensuremath{\leftarrow}</m> ';
       next;
    }  
    if ($token eq '<=>') {
       if ($external::target eq 'web' &&
    &EXT('request.browser.unicode')) {
    $formula .= '&#8652; ';
       } else {
    $formula .= &web('<=> ','<m>\ensuremath{\rightleftharpoons}</m> ',
    '&lt;=&gt; ');
       }
       next;
    }
    if ($token eq '.') {
     $formula =~ s/(\&nbsp\;| )$//;
     $formula .= '&middot;';
     next;
    }
    $token =~ /^\s*([\d|\/]*(?:&frac\d\d)?)(.*)/;
           $formula .= $1 if ($1 ne '1');  # stoichiometric coefficient
   
    my $molecule = $2;
    # subscripts
    $molecule =~ s|(?<=[a-zA-Z\)\]\s])(\d+)|<sub>$1</sub>|g;
    # superscripts
    $molecule =~ s|\^(\d*[+\-]*)|<sup>$1</sup>|g;
    # strip whitespace
    $molecule =~ s/\s*//g;
    # forced space
    $molecule =~ s/_/ /g;
    $molecule =~ s/-/&minus;/g;
    $formula .= $molecule.'&nbsp;';
       }
       # get rid of trailing space
       $formula =~ s/(\&nbsp\;| )$//;
       return &xmlparse($formula);
 }  }
   
 sub prettyprint {  sub prettyprint {
   my ($value,$fmt)=@_;      my ($value,$fmt,$target)=@_;
   my $result;      my $result;
   my $dollarmode;      if (!$target) { $target = $external::target; }
   if ($fmt =~ /^\$(.*)/) { $fmt=$1; $dollarmode=1; }       if ($fmt =~ /chem/i) { return(&chemparse($value)); }
   if ($fmt) { $value=sprintf('%.'.$fmt,$value); }      my ($dollarmode,$commamode,$alwaysperiod,$options);
   if ($value =~ /([0-9\.\-\+]+)E([0-9\-\+]+)/ ) {      if ($fmt =~ /^([^\d]*)(.*)/) { $options=$1; $fmt=$2; } 
     my $frac=$1;      if ($options =~ /\$/) { $dollarmode=1; }
     if ($dollarmode) { $frac=&dollarformat($frac); }      if ($options =~ /,/)  { $commamode=1; }
     my $exponent=$2;      if ($options =~ /\./) { $alwaysperiod=1; }
     $exponent=~s/^\+0*//;      if ($fmt=~/s$/i) {
     $exponent=~s/^-0*/-/;   $value=&format_significant_figures($value,$fmt);
     if ($exponent) {      } elsif ($fmt) {
       if ($external::target eq 'web') {   $value=sprintf('%.'.$fmt,$value);
  $result=$frac.'&#215;10<sup>'.$exponent.'</sup>';      }
       } elsif ($external::target eq 'tex') {      if ($alwaysperiod && $fmt eq '0f') {
  $result='\ensuremath{'.$frac.'\times 10^{'.$exponent.'}}';   if ($target eq 'tex') {
       } else {      $value .='\\ensuremath{.}';
    } else {
       $value .='.';
    }
       }
       if ($value =~ /([0-9\.\-\+]+)E([0-9\-\+]+)/i ) {
    my $frac=$1;
    if ($dollarmode) { $frac=&dollarformat($frac); }
    if ($commamode) { $frac=&commaformat($frac); }
    my $exponent=$2;
    $exponent=~s/^\+0*//;
    $exponent=~s/^-0*/-/;
    $exponent=~s/^-0*/-/;
    if ($exponent eq '-') { undef($exponent); }
    if ($exponent) {
       if ($target eq 'web') {
    $result=$frac.'&#215;10<sup>'.$exponent.'</sup>';
       } elsif ($target eq 'tex') {
    $result='\ensuremath{'.$frac.'\times 10^{'.$exponent.'}}';
       } else {
    $result=$value;
       }
    } else {
       $result=$frac;
    }
       } else {
  $result=$value;   $result=$value;
       }   if    ($dollarmode) { $result=&dollarformat($result,$target); }
    elsif ($commamode)  { $result=&commaformat($result,$target); }
       }
       return $result;
   }
   
   sub commaformat {
       my ($number,$target) = @_;
       if ($number =~ /\./) {
    while ($number =~ /([^0-9]*)([0-9]+)([^\.,][^\.,][^\.,])([,0-9]*\.[0-9]*)$/) {
       $number = $1.$2.','.$3.$4;
    }
     } else {      } else {
       $result=$frac;   while ($number =~ /^([^0-9]*)([0-9]+)([^,][^,][^,])([,0-9]*)$/) {
       $number = $1.$2.','.$3.$4;
    }
     }      }
   } else {      return $number;
     $result=$value;  
     if ($dollarmode) { $result=&dollarformat($result); }  
   }  
   return $result;  
 }  }
   
 sub dollarformat {  sub dollarformat {
   my ($number) = @_;      my ($number,$target) = @_;
   if ($number =~ /\./) {      if (!$target) { $target = $external::target; }
     while ($number =~ /([^\.,]+)([^\.,][^\.,][^\.,])([,0-9]*\.[0-9]*$)/) {      $number=&commaformat($number,$target);
       $number = $1.','.$2.$3;      if ($target eq 'tex') {
     }   $number='\$'.$number; #' stupid emacs
   } else {      } else {
     while ($number =~ /([^,]+)([^,][^,][^,])([,0-9]*)$/) {   $number='$'.$number; #' stupid emacs
       $number = $1.','.$2.$3;      }
     }      return $number; 
   }  }
   if ($external::target eq 'tex') {  
     $number='\$'.$number; #' stupid emacs  # format of form ns or nS where n is an integer
   } else {  sub format_significant_figures {
     $number='$'.$number; #' stupid emacs      my ($number,$format) = @_; 
   }      return '0' if ($number == 0);
   return $number;       # extract number of significant figures needed
       my ($sig) = ($format =~ /(\d+)s/i);
       # arbitrary choice - suggestions ?? or throw error message?
       $sig = 3 if ($sig eq '');
       # save the minus sign
       my $sign = ($number < 0) ? '-' : '';
       $number = abs($number);
       # needed to correct for a number greater than 1 (or
       my $power = ($number < 1) ? 0 : 1;
       # could round up. Take the integer part of log10.
       my $x10 = int(log($number)/log(10));
       # find number with values left of decimal pt = # of sign figs.
       my $xsig = $number*10**($sig-$x10-$power);
       # get just digits left of decimal pt - also rounds off correctly
       my $xint  = sprintf('%.0f',$xsig);
       # save any trailing zero's
       my ($zeros) = ($xint =~ /(0+)$/);
       # return number to original magnitude
       my $numSig = $xint*10**($x10-$sig+$power);
       # insert trailing zero's if have decimal point
       $numSig =~ s/^(\d+)\.(\d+)(\e?(.*)?)$/$1\.$2$zeros$3/;
       # put a decimal pt for number ending with 0 and length = # of sig fig
       $numSig.='.' if (length($numSig) == $sig && $numSig =~ /0$/);
       if (length($numSig) < $sig) {
    $numSig.='.'.substr($zeros,0,($sig-length($numSig)));
       }
       # return number with sign
       return $sign.$numSig;
   
 }  }
   
 sub map {  sub map {
Line 638  sub capa_id { return } Line 1101  sub capa_id { return }
 sub problem { return }  sub problem { return }
   
 sub name{  sub name{
   my $fullname = &EXT('environment.lastname').', '.&EXT('environment.firstname').' '.&EXT('environment.middlename');      my $fullname = &EXT('environment.lastname').', '.&EXT('environment.firstname').' '.&EXT('environment.middlename');
   $fullname = "" if $fullname eq ",  ";      $fullname = "" if $fullname eq ",  ";
   $fullname =~ s/\%2d/-/g;      $fullname =~ s/\%2d/-/g;
   return $fullname;      return $fullname;
 }  }
   
 sub student_number {   sub student_number { 
   my $id = &EXT('environment.id');      my $id = &EXT('environment.id');
   $id = '' if $id eq "";      $id = '' if $id eq "";
   return $id;      return $id;
 }  }
   
 sub class {  sub class {
   my $course = &EXT('course.description');      my $course = &EXT('course.description');
   $course = '' if $course eq "";      $course = '' if $course eq "";
   return $course;      return $course;
   }
   
   sub firstname {
       my $firstname = &EXT('environment.firstname');
       $firstname = '' if $firstname eq "";
       return $firstname;
   }
                                                                                   
   sub lastname {
       my $lastname = &EXT('environment.lastname');
       $lastname = '' if $lastname eq "";
       return $lastname;
 }  }
   
 sub sec {   sub sec { 
   my $sec = &EXT('request.course.sec');      my $sec = &EXT('request.course.sec');
   $sec = '' if $sec eq "";      $sec = '' if $sec eq "";
   return $sec;      return $sec;
   }
   
   sub submission {
      my ($partid,$responseid,$subnumber)=@_;
      my $sub='';
      if ($subnumber) { $sub=$subnumber.':'; }
      return &EXT('user.resource.'.$sub.'resource.'.$partid.'.'.$responseid.'.submission');
   }
   
   sub currentpart {
      return $external::part;
   }
   
   sub eval_time {
      my ($timestamp)=@_;
      unless ($timestamp) { return ''; }
      return &locallocaltime($timestamp);
 }  }
   
 sub open_date {   sub open_date { 
   my @dc = split(/\s+/,localtime(&EXT('resource.0.opendate')));      my ($partid)=@_;
   return '' if ($dc[0] eq "Wed" and $dc[2] == 31 and $dc[4] == 1969);      unless ($partid) { $partid=0; }
   my @hm = split(/:/,$dc[3]);      return &eval_time(&EXT('resource.'.$partid.'.opendate'));
   my $ampm = " am";  }
   if ($hm[0] > 12) {  
     $hm[0]-=12;  sub due_date {
     $ampm = " pm";      my ($partid)=@_;
   }      unless ($partid) { $partid=0; } 
   return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$hm[0].':'.$hm[1].$ampm;      return &eval_time(&EXT('resource.'.$partid.'.duedate'));
 }  
   
 sub due_date {   
   my @dc = split(/\s+/,localtime(&EXT('resource.0.duedate')));  
   return '' if ($dc[0] eq "Wed" and $dc[2] == 31 and $dc[4] == 1969);  
   my @hm = split(/:/,$dc[3]);  
   my $ampm = " am";  
   if ($hm[0] > 12) {  
     $hm[0]-=12;  
     $ampm = " pm";  
   }  
   return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$hm[0].':'.$hm[1].$ampm;  
 #  return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$dc[3];  
 }  }
   
 sub answer_date {   sub answer_date { 
   my @dc = split(/\s+/,localtime(&EXT('resource.0.answerdate')));      my ($partid)=@_;
   return '' if ($dc[0] eq "Wed" and $dc[2] == 31 and $dc[4] == 1969);      unless ($partid) { $partid=0; }
   my @hm = split(/:/,$dc[3]);      return &eval_time(&EXT('resource.'.$partid.'.answerdate'));
   my $ampm = " am";  }
   if ($hm[0] > 12) {  
     $hm[0]-=12;  sub open_date_epoch {
     $ampm = " pm";      my ($partid)=@_;
   }      unless ($partid) { $partid=0; }
   return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$hm[0].':'.$hm[1].$ampm;      return &EXT('resource.'.$partid.'.opendate');
 #  return $dc[0].', '.$dc[1].' '.$dc[2].', '.$dc[4].' at '.$dc[3];  }
   
   sub due_date_epoch {
       my ($partid)=@_;
       unless ($partid) { $partid=0; }
       return &EXT('resource.'.$partid.'.duedate');
   }
   
   sub answer_date_epoch {
       my ($partid)=@_;
       unless ($partid) { $partid=0; }
       return &EXT('resource.'.$partid.'.answerdate');
 }  }
   
 sub array_moments {  sub array_moments {
   my @input=@_;      my @input=@_;
   my (@output,$N);      my (@output,$N);
   $N=scalar (@input);      $N=scalar (@input);
   $output[0]=$N;      $output[0]=$N;
   if ($N <= 1) {      if ($N <= 1) {
     $output[1]=$input[0];   $output[1]=$input[0];
     $output[1]="Input array not defined" if ($N == 0);   $output[1]="Input array not defined" if ($N == 0);
     $output[2]="variance undefined for N<=1";   $output[2]="variance undefined for N<=1";
     $output[3]="skewness undefined for N<=1";   $output[3]="skewness undefined for N<=1";
     $output[4]="kurtosis undefined for N<=1";   $output[4]="kurtosis undefined for N<=1";
    return @output;
       }
       my $sum=0;
       foreach my $line (@input) {
    $sum+=$line;
       }
       $output[1] = $sum/$N;
       my ($x,$sdev,$var,$skew,$kurt) = 0;
       foreach my $line (@input) {
    $x=$line-$output[1];
    $var+=$x**2;
    $skew+=$x**3;
    $kurt+=$x**4;
       }
       $output[2]=$var/($N-1);
       $sdev=CORE::sqrt($output[2]);
       if ($sdev == 0) {
    $output[3]="inf-variance=0";
    $output[4]="inf-variance=0";
    return @output;
       }
       $output[3]=$skew/($sdev**3*$N);
       $output[4]=$kurt/($sdev**4*$N)-3;
     return @output;      return @output;
   }  
   my $sum=0;  
   foreach my $line (@input) {  
     $sum+=$line;  
   }  
   $output[1] = $sum/$N;  
   my ($x,$sdev,$var,$skew,$kurt) = 0;  
   foreach my $line (@input) {  
     $x=$line-$output[1];  
     $var+=$x**2;  
     $skew+=$x**3;  
     $kurt+=$x**4;  
   }  
   $output[2]=$var/($N-1);  
   $sdev=CORE::sqrt($output[2]);  
   if ($sdev == 0) {  
      $output[3]="inf-variance=0";  
      $output[4]="inf-variance=0";  
      return @output;  
   }  
   $output[3]=$skew/($sdev**3*$N);  
   $output[4]=$kurt/($sdev**4*$N)-3;  
   return @output;  
 }  }
   
 sub choose {  sub choose {
   my $num = $_[0];      my $num = $_[0];
   return $_[$num];      return $_[$num];
 }  }
   
   #&sum1(1,$x,sub { &sum1($_[0],2*$_[0], sub { fact($_[0])**2 })});
   #sub sum1 {
   #    my ($start,$end,$sub)=@_;
   #    my $sum=0;
   #    for (my $i=$start;$i<=$end;$i++) {
   #        $sum+=&$sub($i);
   #    }
   #    return $sum
   #}
   
   #&sum2('a',1,$x,'&sum2(\'b\',$a,2*$a, \'&factorial($b)**2\')');
   #sub sum2 {
   #    my ($varname,$start,$end,$line)=@_;
   #    my $sum=0;
   #    for (my $i=$start;$i<=$end;$i++) {
   # my $func=sub {
   #    eval("\$".$varname."=$i");
   #    eval($line);
   # };
   #        $sum+=&$func($i);
   #    }
   #    return $sum
   #}
   
 # expiremental idea  # expiremental idea
 sub proper_path {  sub proper_path {
   my ($path)=@_;      my ($path)=@_;
   if ( $external::target eq "tex" ) {      if ( $external::target eq "tex" ) {
     return '/home/httpd/html'.$path;   return '/home/httpd/html'.$path;
   } else {      } else {
     return $path;   return $path;
   }      }
 }  }
   

Removed from v.1.64  
changed lines
  Added in v.1.150


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.