--- loncom/homework/caparesponse/caparesponse.pm 2005/11/16 22:52:31 1.181 +++ loncom/homework/caparesponse/caparesponse.pm 2008/09/23 19:22:58 1.227.2.4 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # caparesponse definition # -# $Id: caparesponse.pm,v 1.181 2005/11/16 22:52:31 albertel Exp $ +# $Id: caparesponse.pm,v 1.227.2.4 2008/09/23 19:22:58 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -29,15 +29,26 @@ package Apache::caparesponse; use strict; use capa; +use Safe::Hole; +use Apache::lonmaxima(); use Apache::lonlocal; use Apache::lonnet; +use Apache::response(); +use Storable qw(dclone); BEGIN { - &Apache::lonxml::register('Apache::caparesponse',('caparesponse','numericalresponse','stringresponse','formularesponse')); + &Apache::lonxml::register('Apache::caparesponse',('numericalresponse','stringresponse','formularesponse')); } my %answer; +my @answers; +sub get_answer { return %answer; }; +sub push_answer{ push(@answers,dclone(\%answer)); undef(%answer) } +sub pop_answer { %answer = %{pop(@answers)}; }; + my $cur_name; +my $tag_internal_answer_name = 'INTERNAL'; + sub start_answer { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; @@ -50,41 +61,111 @@ sub start_answer { if (!defined($type)) { $type = 'ordered' }; $answer{$cur_name}= { 'type' => $type, 'answers' => [] }; + if ($target eq 'edit') { + $result.=&Apache::edit::tag_start($target,$token); + $result.=&Apache::edit::text_arg('Name:','name',$token); + $result.=&Apache::edit::select_arg('Type:','type', + [['ordered', 'Ordered' ], + ['unordered','Unordered'],], + $token); + $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); + } elsif ($target eq 'modified') { + my $constructtag = &Apache::edit::get_new_args($token,$parstack, + $safeeval,'name', + 'type'); + if ($constructtag) { + $result = &Apache::edit::rebuild_tag($token); + $result.= &Apache::edit::handle_insert(); + } + } return $result; } sub end_answer { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; + if ($target eq 'edit') { + $result .= &Apache::edit::tag_end(); + } + undef($cur_name); return $result; } +sub insert_answer { + return ' + + + '; +} + sub start_answergroup { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; - my $id = $Apache::inputtags::response[-1]; - my $dis = &Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval); - if (defined($dis)) { $Apache::inputtags::answertxt{$id}=$dis; } + if ($target eq 'edit') { + $result.=&Apache::edit::tag_start($target,$token); + $result.=&Apache::edit::select_arg('Type:','type', + [['ordered', 'Ordered' ], + ['unordered','Unordered'],], + $token); + $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); + } elsif ($target eq 'modified') { + my $constructtag = &Apache::edit::get_new_args($token,$parstack, + $safeeval,'name', + 'type'); + if ($constructtag) { + $result = &Apache::edit::rebuild_tag($token); + $result.= &Apache::edit::handle_insert(); + } + } return $result; } sub end_answergroup { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; + if ($target eq 'web') { + if ( &Apache::response::show_answer() ) { + my $partid = $Apache::inputtags::part; + my $id = $Apache::inputtags::response[-1]; + &set_answertext($Apache::lonhomework::history{"resource.$partid.$id.answername"}, + $target,$token,$tagstack,$parstack,$parser, + $safeeval,-2); + } + } elsif ($target eq 'edit') { + $result .= &Apache::edit::tag_end(); + } return $result; } +sub insert_answergroup { + return ' + + + + + '; +} + sub start_value { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; if ( $target eq 'web' || $target eq 'tex' || $target eq 'grade' || $target eq 'webgrade' || $target eq 'answer' || $target eq 'analyze' ) { - my $bodytext = &Apache::lonxml::get_all_text("/value",$parser); + my $bodytext = &Apache::lonxml::get_all_text("/value",$parser,$style); $bodytext = &Apache::run::evaluate($bodytext,$safeeval, $$parstack[-1]); - push(@{ $answer{$cur_name}{'answers'} },$bodytext); + + push(@{ $answer{$cur_name}{'answers'} },[$bodytext]); + + } elsif ($target eq 'edit') { + $result.=&Apache::edit::tag_start($target,$token); + my $bodytext = &Apache::lonxml::get_all_text("/value",$parser,$style); + $result.=&Apache::edit::editline($token->[1],$bodytext,undef,40). + &Apache::edit::end_row(); + } elsif ($target eq 'modified') { + $result=$token->[4].&Apache::edit::modifiedfield('/value',$parser); } return $result; } @@ -92,16 +173,61 @@ sub start_value { sub end_value { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; + if ($target eq 'edit') { + $result = &Apache::edit::end_table(); + } return $result; } -sub start_array { +sub insert_value { + return ' + '; +} + +sub start_vector { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result; + if ( $target eq 'web' || $target eq 'tex' || + $target eq 'grade' || $target eq 'webgrade' || + $target eq 'answer' || $target eq 'analyze' ) { + my $bodytext = &Apache::lonxml::get_all_text("/vector",$parser,$style); + my @values = &Apache::run::run($bodytext,$safeeval,$$parstack[-1]); + if (@values == 1) { + @values = split(',',$values[0]); + } + push(@{ $answer{$cur_name}{'answers'} },\@values); + } elsif ($target eq 'edit') { + $result.=&Apache::edit::tag_start($target,$token); + my $bodytext = &Apache::lonxml::get_all_text("/vector",$parser,$style); + $result.=&Apache::edit::editline($token->[1],$bodytext,undef,40). + &Apache::edit::end_row(); + } elsif ($target eq 'modified') { + $result=$token->[4].&Apache::edit::modifiedfield('/vector',$parser); + } + return $result; +} + +sub end_vector { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; + if ($target eq 'edit') { + $result = &Apache::edit::end_table(); + } + return $result; +} + +sub insert_vector { + return ' + '; +} + +sub start_array { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result; if ( $target eq 'web' || $target eq 'tex' || $target eq 'grade' || $target eq 'webgrade' || $target eq 'answer' || $target eq 'analyze' ) { - my $bodytext = &Apache::lonxml::get_all_text("/value",$parser); + my $bodytext = &Apache::lonxml::get_all_text("/array",$parser,$style); my @values = &Apache::run::evaluate($bodytext,$safeeval, $$parstack[-1]); push(@{ $answer{$cur_name}{'answers'} },@values); @@ -129,7 +255,10 @@ sub end_unit { sub start_numericalresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - &Apache::lonxml::register('Apache::caparesponse',('answer','answergroup','value','array','unit')); + &Apache::lonxml::register('Apache::caparesponse', + ('answer','answergroup','value','array','unit', + 'vector')); + push(@Apache::lonxml::namespace,'caparesponse'); my $id = &Apache::response::start_response($parstack,$safeeval); my $result; undef(%answer); @@ -182,15 +311,42 @@ sub start_numericalresponse { if ($unit =~ /\S/) { $result.=" (in $unit) "; } } if ( &Apache::response::show_answer() ) { - my $answertxt; - my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack, - $safeeval); - my (@formats)=&Apache::lonxml::get_param_var('format',$parstack, - $safeeval); - my $unit=&Apache::lonxml::get_param_var('unit',$parstack, - $safeeval); - for (my $i=0; $i <= $#answers; $i++) { - my $answer=$answers[$i]; + &set_answertext($tag_internal_answer_name,$target,$token,$tagstack, + $parstack,$parser,$safeeval,-1); + } + } + return $result; +} + +sub set_answertext { + my ($name,$target,$token,$tagstack,$parstack,$parser,$safeeval, + $response_level) = @_; + &add_in_tag_answer($parstack,$safeeval,$response_level); + + if ($name eq '' || !ref($answer{$name})) { + if (ref($answer{$tag_internal_answer_name})) { + $name = $tag_internal_answer_name; + } else { + $name = (sort(keys(%answer)))[0]; + } + } + return if ($name eq '' || !ref($answer{$name})); + + my (@formats)=&Apache::lonxml::get_param_var('format',$parstack, + $safeeval,$response_level); + my $unit=&Apache::lonxml::get_param_var('unit',$parstack,$safeeval, + $response_level); + + &Apache::lonxml::debug("answer looks to be $name"); + my @answertxt; + for (my $i=0; $i < scalar(@{$answer{$name}{'answers'}}); $i++) { + my $answertxt; + my $answer=$answer{$name}{'answers'}[$i]; + foreach my $element (@$answer) { + if ( scalar(@$tagstack) + && $tagstack->[$response_level] ne 'numericalresponse') { + $answertxt.=$element.','; + } else { my $format; if ($#formats > 0) { $format=$formats[$i]; @@ -199,36 +355,58 @@ sub start_numericalresponse { } if ($unit=~/\$/) { $format="\$".$format; $unit=~s/\$//g; } if ($unit=~/\,/) { $format="\,".$format; $unit=~s/\,//g; } - my $formatted=&format_number($answer,$format,$target, + my $formatted=&format_number($element,$format,$target, $safeeval); - $answertxt.=$formatted.','; - } - chop $answertxt; - if ($target eq 'web') { - $answertxt.=" $unit "; + $answertxt.=' '.$formatted.','; } - $Apache::inputtags::answertxt{$id}=$answertxt; + + } + chop($answertxt); + if ($target eq 'web') { + $answertxt.=" $unit "; } + + push(@answertxt,$answertxt) } - return $result; + + my $id = $Apache::inputtags::response[-1]; + $Apache::inputtags::answertxt{$id}=\@answertxt; } -sub check_submission { - my ($response,$partid,$id,$tag,$parstack,$safeeval,$ignore_sig)=@_; +sub setup_capa_args { + my ($safeeval,$parstack,$args,$response) = @_; my $args_ref= \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')}; - $$args_ref{'response'}=$response; - my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit'); - - foreach my $arg ('type','tol','sig','format','unit','calc', - 'samples') { + undef(%{ $args_ref }); + + foreach my $arg (@{$args}) { $$args_ref{$arg}= &Apache::lonxml::get_param($arg,$parstack,$safeeval); } foreach my $key (keys(%Apache::inputtags::params)) { $$args_ref{$key}=$Apache::inputtags::params{$key}; } - - #no way to enter units, with radio buttons + &setup_capa_response($args_ref,$response); + return $args_ref; +} + +sub setup_capa_response { + my ($args_ref,$response) = @_; + + if (ref($response)) { + $$args_ref{'response'}=dclone($response); + } else { + $$args_ref{'response'}=dclone([$response]); + } +} + +sub check_submission { + my ($response,$partid,$id,$tag,$parstack,$safeeval,$ignore_sig)=@_; + my @args = ('type','tol','sig','format','unit','calc','samples'); + my $args_ref = &setup_capa_args($safeeval,$parstack,\@args,$response); + + my $hideunit= + &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit'); + #no way to enter units, with radio buttons if ($Apache::lonhomework::type eq 'exam' || lc($hideunit) eq "yes") { delete($$args_ref{'unit'}); @@ -242,29 +420,40 @@ sub check_submission { } if ($tag eq 'formularesponse') { - $$args_ref{'type'}='fml'; + if ($$args_ref{'samples'}) { + $$args_ref{'type'}='fml'; + } else { + $$args_ref{'type'}='math'; + } } elsif ($tag eq 'numericalresponse') { $$args_ref{'type'}='float'; + } elsif ($tag eq 'stringresponse') { + if ($$args_ref{'type'} eq '') { + $$args_ref{'type'} = 'ci'; + } } - my @answer=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval); - &Apache::lonxml::debug('answer is'.join(':',@answer)); - if (@answer && defined($answer[0])) { - $answer{'INTERNAL'}= {'type' => 'ordered', - 'answers' => \@answer }; - } - #FIXME would be nice if we could save name so we know who graded him - #correct - my (%results,@final_awards,@final_msgs,@names); + + &add_in_tag_answer($parstack,$safeeval); + + if (!%answer) { + &Apache::lonxml::error("No answers are defined"); + } + + my (@final_awards,@final_msgs,@names); foreach my $name (keys(%answer)) { &Apache::lonxml::debug(" doing $name with ".join(':',@{ $answer{$name}{'answers'} })); - @{$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=@{ $answer{$name}{'answers'} }; + + ${$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=dclone($answer{$name}); + &setup_capa_response($args_ref,$response); + use Time::HiRes; + my $t0 = [Time::HiRes::gettimeofday()]; my ($result,@msgs) = &Apache::run::run("&caparesponse_check_list()",$safeeval); + &Apache::lonxml::debug("checking $name $result with $response took ".&Time::HiRes::tv_interval($t0)); &Apache::lonxml::debug('msgs are '.join(':',@msgs)); my ($awards)=split(/:/,$result); my @awards= split(/,/,$awards); my ($ad, $msg) = &Apache::inputtags::finalizeawards(\@awards,\@msgs); - $results{$name}= [$ad,$msg]; push(@final_awards,$ad); push(@final_msgs,$msg); push(@names,$name); @@ -272,11 +461,34 @@ sub check_submission { my ($ad, $msg, $name) = &Apache::inputtags::finalizeawards(\@final_awards, \@final_msgs, \@names,1); - return($ad,$msg); + &Apache::lonxml::debug(" name of picked award is $name from ".join(', ',@names)); + return($ad,$msg, $name); +} + +sub add_in_tag_answer { + my ($parstack,$safeeval,$response_level) = @_; + my @answer=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval, + $response_level); + &Apache::lonxml::debug('answer is'.join(':',@answer)); + if (@answer && $answer[0] =~ /\S/) { + $answer{$tag_internal_answer_name}= {'type' => 'ordered', + 'answers' => [\@answer] }; + } +} + +sub capa_formula_fix { + my ($expression)=@_; + return &Apache::response::implicit_multiplication($expression); } sub end_numericalresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + &Apache::lonxml::deregister('Apache::caparesponse', + ('answer','answergroup','value','array','unit', + 'vector')); + pop(@Apache::lonxml::namespace); + my $increment=1; my $result = ''; if (!$Apache::lonxml::default_homework_loaded) { @@ -285,12 +497,14 @@ sub end_numericalresponse { my $partid = $Apache::inputtags::part; my $id = $Apache::inputtags::response[-1]; my $tag; + my $safehole = new Safe::Hole; $safeeval->share_from('capa',['&caparesponse_capa_check_answer']); + if (scalar(@$tagstack)) { $tag=$$tagstack[-1]; } if ( $target eq 'grade' && &Apache::response::submitted() ) { &Apache::response::setup_params($tag,$safeeval); if ($Apache::lonhomework::type eq 'exam' && - $tag eq 'formularesponse') { + (($tag eq 'formularesponse') || ($tag eq 'mathresponse'))) { $increment=&Apache::response::scored_response($partid,$id); } else { my $response = &Apache::response::getresponse(); @@ -300,18 +514,15 @@ sub end_numericalresponse { &Apache::lonxml::debug($$parstack[-1] . "\n
"); if ( &Apache::response::submitted('scantron')) { - my $number_of_bubbles = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.numbubbles'); - if (!$number_of_bubbles) { $number_of_bubbles=8; } - my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval); - my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval); - my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval); - if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); } - my ($values,$display)=&make_numerical_bubbles($number_of_bubbles,$target,$answers[0],$formats[0],\@incorrect,$safeeval); + &add_in_tag_answer($parstack,$safeeval); + my ($values,$display)=&make_numerical_bubbles($partid,$id, + $target,$parstack,$safeeval); $response=$values->[$response]; } $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; - my ($ad,$msg)=&check_submission($response,$partid,$id, - $tag,$parstack,$safeeval); + my ($ad,$msg,$name)=&check_submission($response,$partid,$id, + $tag,$parstack, + $safeeval); &Apache::lonxml::debug('ad is'.$ad); if ($ad eq 'SIG_FAIL') { @@ -330,31 +541,23 @@ sub end_numericalresponse { &Apache::response::handle_previous(\%previous,$ad); $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad; $Apache::lonhomework::results{"resource.$partid.$id.awardmsg"}=$msg; + $Apache::lonhomework::results{"resource.$partid.$id.answername"}=$name; $result=''; } } } elsif ($target eq 'web' || $target eq 'tex') { - my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack, - $safeeval); + &check_for_answer_errors($parstack,$safeeval); my $award = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.solved"}; my $status = $Apache::inputtags::status['-1']; if ($Apache::lonhomework::type eq 'exam') { - my $number_of_bubbles = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.numbubbles'); - if ($Apache::inputtags::params{'numbubbles'}) { - $number_of_bubbles = $Apache::inputtags::params{'numbubbles'}; - } - if (!$number_of_bubbles) { $number_of_bubbles=8; } - - my (@formats)=&Apache::lonxml::get_param_var('format',$parstack, - $safeeval); + # FIXME support multi dimensional numerical problems + # in exam bubbles + my ($bubble_values,$bubble_display)= + &make_numerical_bubbles($partid,$id,$target,$parstack, + $safeeval); + my $number_of_bubbles = scalar(@{ $bubble_values }); my $unit=&Apache::lonxml::get_param_var('unit',$parstack, $safeeval); - my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval); - if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); } - my ($bubble_values,$bubble_display)= - &make_numerical_bubbles($number_of_bubbles, - $target,$answers[0], - $formats[0],\@incorrect,$safeeval); my @alphabet=('A'..'Z'); if ($target eq 'web') { if ($tag eq 'numericalresponse') { @@ -372,10 +575,6 @@ sub end_numericalresponse { $bubble_display->[$ind].''; } $result.=''; - } elsif ($tag eq 'formularesponse') { - $result.= '

-

'; } } elsif ($target eq 'tex') { if ((defined $unit) and ($unit=~/\S/) and ($Apache::lonhomework::type eq 'exam')) { @@ -403,17 +602,17 @@ sub end_numericalresponse { } $result.='\end{enumerate}'; } else { - $result.='\fbox{\fbox{\parbox{\textwidth-5mm}{\strut\\\\\strut\\\\\strut\\\\\strut\\\\}}}'; - my $repetition = &Apache::response::repetition(); - $result.='\begin{enumerate}'; - for (my $i=0;$i<$repetition;$i++) { - $result.='\item[\textbf{'.($Apache::lonxml::counter+$i).'}.]\textit{Leave blank on scoring form}\vskip 0 mm'; - } - $increment=$repetition; - $result.= '\end{enumerate}'; + $increment = &Apache::response::repetition(); } } } + if (($target eq 'web') && ($tag eq 'formularesponse') + && ($Apache::lonhomework::type ne 'exam') && ($Apache::inputtags::status['-1'] eq 'CAN_ANSWER') + && (&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffeditor') ne 'yes')) { + $result.=&Apache::response::edit_mathresponse_button($id,"HWVAL_$id"); + } + + &Apache::response::setup_prior_tries_hash(\&format_prior_response_numerical); } elsif ($target eq 'edit') { $result.=''.&Apache::edit::end_table; } elsif ($target eq 'answer' || $target eq 'analyze') { @@ -430,129 +629,167 @@ sub end_numericalresponse { if (scalar(@$tagstack)) { &Apache::response::setup_params($tag,$safeeval); } - my (@answers)=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval); + &add_in_tag_answer($parstack,$safeeval); my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval); + my $unit=&Apache::lonxml::get_param_var('unit',$parstack,$safeeval); - my $type=&Apache::lonxml::get_param('type',$parstack,$safeeval); if ($target eq 'answer') { - $result.=&Apache::response::answer_header($tag); + $result.=&Apache::response::answer_header($tag,undef, + scalar(keys(%answer))); + if ($tag eq 'numericalresponse' + && $Apache::lonhomework::type eq 'exam') { + my ($bubble_values,undef,$correct) = &make_numerical_bubbles($partid, + $id,$target,$parstack,$safeeval); + $result.=&Apache::response::answer_part($tag,$correct); + } } - my ($sigline,$tolline); - for(my $i=0;$i<=$#answers;$i++) { - my $ans=$answers[$i]; - my $fmt=$formats[0]; - if (@formats && $#formats) {$fmt=$formats[$i];} - my ($high,$low); - if ($Apache::inputtags::params{'tol'}) { - ($high,$low)=&get_tolrange($ans,$Apache::inputtags::params{'tol'}); - } - my ($sighigh,$siglow); - if ($Apache::inputtags::params{'sig'}) { - ($sighigh,$siglow)=&get_sigrange($Apache::inputtags::params{'sig'}); - } - if ($fmt && $tag eq 'numericalresponse') { - $fmt=~s/e/E/g; - if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; } - if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; } - $ans = &format_number($ans,$fmt,$target,$safeeval); - #if ($high) { - # $high=&format_number($high,$fmt,$target,$safeeval); - # $low =&format_number($low,$fmt,$target,$safeeval); - #} - } - if ($target eq 'answer') { - if ($high && $tag eq 'numericalresponse') { - $ans.=' ['.$low.','.$high.']'; - $tolline .= "[$low, $high]"; + foreach my $name (sort(keys(%answer))) { + my @answers = @{ $answer{$name}{'answers'} }; + if ($target eq 'analyze') { + foreach my $info ('answer','ans_high','ans_low','format') { + $Apache::lonhomework::analyze{"$part_id.$info"}{$name}=[]; } - if (defined($sighigh) && $tag eq 'numericalresponse') { - if ($env{'form.answer_output_mode'} eq 'tex') { - $ans.= " Sig $siglow - $sighigh"; - } else { - $ans.= " Sig $siglow - $sighigh"; - $sigline .= "[$siglow, $sighigh]"; + } + my ($sigline,$tolline); + if ($name ne $tag_internal_answer_name + || scalar(keys(%answer)) > 1) { + $result.=&Apache::response::answer_part($tag,$name); + } + for(my $i=0;$i<=$#answers;$i++) { + my $ans=$answers[$i]; + my $fmt=$formats[0]; + if (@formats && $#formats) {$fmt=$formats[$i];} + my ($sighigh,$siglow); + if ($Apache::inputtags::params{'sig'}) { + ($sighigh,$siglow)=&get_sigrange($Apache::inputtags::params{'sig'}); + } + my @vector; + if (ref($ans)) { + @vector = @{ $ans }; + } else { + @vector = ($ans); + } + my @all_answer_info; + foreach my $element (@vector) { + my ($high,$low); + if ($Apache::inputtags::params{'tol'}) { + ($high,$low)=&get_tolrange($element,$Apache::inputtags::params{'tol'}); + } + if ($target eq 'answer') { + if ($fmt && $tag eq 'numericalresponse') { + $fmt=~s/e/E/g; + if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; } + if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; } + $element = &format_number($element,$fmt,$target,$safeeval); + #if ($high) { + # $high=&format_number($high,$fmt,$target,$safeeval); + # $low =&format_number($low,$fmt,$target,$safeeval); + #} + } + if ($high && $tag eq 'numericalresponse') { + $element.='; ['.$low.'; '.$high.']'; + $tolline .= "[$low, $high]"; + } + if (defined($sighigh) && $tag eq 'numericalresponse') { + if ($env{'form.answer_output_mode'} eq 'tex') { + $element.= "; Sig $siglow - $sighigh"; + } else { + $element.= " Sig $siglow - $sighigh"; + $sigline .= "[$siglow, $sighigh]"; + } + } + push(@all_answer_info,$element); + + } elsif ($target eq 'analyze') { + push (@{ $Apache::lonhomework::analyze{"$part_id.answer"}{$name}[$i] }, $element); + if ($high) { + push (@{ $Apache::lonhomework::analyze{"$part_id.ans_high"}{$name}[$i] }, $high); + push (@{ $Apache::lonhomework::analyze{"$part_id.ans_low"}{$name}[$i] }, $low); + } + if ($fmt) { + push (@{ $Apache::lonhomework::analyze{"$part_id.format"}{$name}[$i] }, $fmt); + } } } - $result.=&Apache::response::answer_part($tag,$ans); - } elsif ($target eq 'analyze') { - push (@{ $Apache::lonhomework::analyze{"$part_id.answer"} }, $ans); - if ($high) { - push (@{ $Apache::lonhomework::analyze{"$part_id.ans_high"} }, $high); - push (@{ $Apache::lonhomework::analyze{"$part_id.ans_low"} }, $low); - } - if ($fmt) { - push (@{ $Apache::lonhomework::analyze{"$part_id.format"} }, $fmt); + if ($target eq 'answer') { + $result.= &Apache::response::answer_part($tag,join('; ',@all_answer_info)); } } - } - my @fmt_ans; - for(my $i=0;$i<=$#answers;$i++) { - my $ans=$answers[$i]; - my $fmt=$formats[0]; - if (@formats && $#formats) {$fmt=$formats[$i];} - if ($fmt && $tag eq 'numericalresponse') { - $fmt=~s/e/E/g; - if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; } - if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; } - $ans = &format_number($ans,$fmt,$target,$safeeval); - if ($fmt=~/\$/ && $unit!~/\$/) { $ans=~s/\$//; } - } - push(@fmt_ans,$ans); - } - my $response=join(', ',@fmt_ans); - my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'. - $id.'.turnoffunit'); - if ($unit ne '' && - ! ($Apache::lonhomework::type eq 'exam' || - lc($hideunit) eq "yes") ) { - my $cleanunit=$unit; - $cleanunit=~s/\$\,//g; - $response.=" $cleanunit"; - } - - my ($ad,$msg)=&check_submission($response,$partid,$id,$tag, - $parstack,$safeeval); - if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') { - my $error; - if ($tag eq 'formularesponse') { - $error=&mt('Computer\'s answer is incorrect ("[_1]").'); - } else { - # answer failed check if it is sig figs that is failing - my ($ad,$msg)=&check_submission($response,$partid,$id, - $tag,$parstack, - $safeeval,1); - if ($sigline ne '') { - $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] or significant figures [_3] need to be adjusted.',$response,$tolline,$sigline); - } else { - $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] needs to be adjusted.',$response,$tolline); + my @fmt_ans; + for(my $i=0;$i<=$#answers;$i++) { + my $ans=$answers[$i]; + my $fmt=$formats[0]; + if (@formats && $#formats) {$fmt=$formats[$i];} + foreach my $element (@$ans) { + if ($fmt && $tag eq 'numericalresponse') { + $fmt=~s/e/E/g; + if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; } + if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; } + $element = &format_number($element,$fmt,$target, + $safeeval); + if ($fmt=~/\$/ && $unit!~/\$/) { $element=~s/\$//; } + } + } + push(@fmt_ans,join(',',@$ans)); + } + my $response=\@fmt_ans; + + my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'. + $id.'.turnoffunit'); + if ($unit ne '' && + ! ($Apache::lonhomework::type eq 'exam' || + lc($hideunit) eq "yes") ) { + my $cleanunit=$unit; + $cleanunit=~s/\$\,//g; + foreach my $ans (@fmt_ans) { + $ans.=" $cleanunit"; } } + my ($ad,$msg)=&check_submission($response,$partid,$id,$tag, + $parstack,$safeeval); if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') { - &Apache::lonxml::error($error); - } else { - &Apache::lonxml::warning($error); + my $error; + if ($tag eq 'formularesponse') { + $error=&mt('Computer\'s answer is incorrect ("[_1]").',join(', ',@$response)); + } else { + # answer failed check if it is sig figs that is failing + my ($ad,$msg)=&check_submission($response,$partid,$id, + $tag,$parstack, + $safeeval,1); + if ($sigline ne '') { + $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] or significant figures [_3] need to be adjusted.',join(', ',@$response),$tolline,$sigline); + } else { + $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] needs to be adjusted.',join(', ',@$response),$tolline); + } + } + if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') { + &Apache::lonxml::error($error); + } else { + &Apache::lonxml::warning($error); + } } - } - if (defined($unit) and ($unit ne '') and - $tag eq 'numericalresponse') { - if ($target eq 'answer') { - if ($env{'form.answer_output_mode'} eq 'tex') { - $result.=&Apache::response::answer_part($tag, - " Unit: $unit "); - } else { - $result.=&Apache::response::answer_part($tag, - "Unit: $unit"); + if (defined($unit) and ($unit ne '') and + $tag eq 'numericalresponse') { + if ($target eq 'answer') { + if ($env{'form.answer_output_mode'} eq 'tex') { + $result.=&Apache::response::answer_part($tag, + " Unit: $unit "); + } else { + $result.=&Apache::response::answer_part($tag, + "Unit: $unit"); + } + } elsif ($target eq 'analyze') { + push (@{ $Apache::lonhomework::analyze{"$part_id.unit"} }, $unit); } - } elsif ($target eq 'analyze') { - push (@{ $Apache::lonhomework::analyze{"$part_id.unit"} }, $unit); } - } - if ($tag eq 'formularesponse' && $target eq 'answer') { - my $samples=&Apache::lonxml::get_param('samples',$parstack,$safeeval); - $result.=&Apache::response::answer_part($tag,$samples); + if ($tag eq 'formularesponse' && $target eq 'answer') { + my $samples=&Apache::lonxml::get_param('samples',$parstack,$safeeval); + $result.=&Apache::response::answer_part($tag,$samples); + } + $result.=&Apache::response::next_answer($tag,$name); } if ($target eq 'answer') { $result.=&Apache::response::answer_footer($tag); @@ -560,12 +797,62 @@ sub end_numericalresponse { } if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || $target eq 'tex' || $target eq 'analyze') { - &Apache::lonxml::increment_counter($increment); + if (($tag eq 'formularesponse') && ($target eq 'analyze')) { + my $type = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.type'); + if ($type eq 'exam') { + $increment = &Apache::response::repetition(); + } + } + &Apache::lonxml::increment_counter($increment,"$partid.$id"); + if ($target eq 'analyze') { + &Apache::lonhomework::set_bubble_lines(); + } } - &Apache::response::end_response; + &Apache::response::end_response(); return $result; } +sub format_prior_response_numerical { + my ($mode,$answer) = @_; + if (ref($answer)) { + my $result = ''; + foreach my $element (@{ $answer }) { + $result.= ''; + } + $result.='
'. + &HTML::Entities::encode($element,'"<>&').'
'; + return $result; + } + return ''. + &HTML::Entities::encode($answer,'"<>&').''; + +} + +sub check_for_answer_errors { + my ($parstack,$safeeval) = @_; + &add_in_tag_answer($parstack,$safeeval); + my %counts; + foreach my $name (keys(%answer)) { + push(@{$counts{scalar(@{$answer{$name}{'answers'}})}},$name); + } + if (scalar(keys(%counts)) > 1) { + my $counts = join(' ',map { + my $count = $_; + &mt("Answers [_1] had [_2] components.", + ''.join(', ',@{$counts{$count}}).'', + $count); + } (sort(keys(%counts)))); + &Apache::lonxml::error(&mt("All answers must have the same number of components. Varying numbers of answers were seen. ").$counts); + } + my $expected_number_of_inputs = (keys(%counts))[0]; + if ( $expected_number_of_inputs > 0 + && $expected_number_of_inputs != scalar(@Apache::inputtags::inputlist)) { + &Apache::lonxml::error(&mt("Expected [_1] input fields, but there were only [_2] seen.", + $expected_number_of_inputs, + scalar(@Apache::inputtags::inputlist))); + } +} + sub get_table_sizes { my ($number_of_bubbles,$rbubble_values)=@_; my $scale=2; #mm for one digit @@ -595,7 +882,13 @@ sub get_table_sizes { my $bubbles_per_line=int($textwidth/$cell_width); if ($bubbles_per_line > $number_of_bubbles) { $bubbles_per_line=$number_of_bubbles; - }elsif (($bubbles_per_line > $number_of_bubbles/2) && ($number_of_bubbles % 2==0)) {$bubbles_per_line=$number_of_bubbles/2;} + } elsif (($bubbles_per_line > $number_of_bubbles/2) + && ($number_of_bubbles % 2==0)) { + $bubbles_per_line=$number_of_bubbles/2; + } + if ($bubbles_per_line < 1) { + $bubbles_per_line=1; + } my $number_of_tables = int($number_of_bubbles/$bubbles_per_line); my @table_range = (); for (my $i=0;$i<$number_of_tables;$i++) {push @table_range,$bubbles_per_line;} @@ -613,7 +906,7 @@ sub format_number { my $ans; if ($format eq '') { #What is the number? (integer,decimal,floating point) - if ($number=~/^(\d*\.?\d*)(E|e)(\d*)$/) { + if ($number=~/^(\d*\.?\d*)(E|e)[+\-]?(\d*)$/) { $format = '3e'; } elsif ($number=~/^(\d*)\.(\d*)$/) { $format = '4f'; @@ -629,35 +922,72 @@ sub format_number { } sub make_numerical_bubbles { - my ($number_of_bubbles,$target,$answer,$format,$incorrect,$safeeval) =@_; + my ($part,$id,$target,$parstack,$safeeval) =@_; + + if (!%answer) { + &Apache::lonxml::error(&mt("No answers defined for response [_1] in part [_2] to make bubbles for.",$id,$part)); + return ([],[],undef); + } + + my $number_of_bubbles = + &Apache::response::get_response_param($part.'_'.$id,'numbubbles',8); + + my ($format)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval); + my $name = (exists($answer{$tag_internal_answer_name}) + ? $tag_internal_answer_name + : (sort(keys(%answer)))[0]); + + if ( scalar(@{$answer{$name}{'answers'}}) > 1) { + &Apache::lonxml::error("Only answers with 1 component are supported in exam mode"); + } + if (scalar(@{$answer{$name}{'answers'}[0]}) > 1) { + &Apache::lonxml::error("Vector answers are unsupported in exam mode."); + } + + my $answer = $answer{$name}{'answers'}[0][0]; + my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack, + $safeeval); + if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); } + my @bubble_values=(); - &Apache::lonxml::debug("answer is $answer incorrect is $incorrect"); + my @alphabet=('A'..'Z'); + + &Apache::lonxml::debug("answer is $answer incorrect is @incorrect"); my @oldseed=&Math::Random::random_get_seed(); - if (defined($incorrect) && ref($incorrect)) { - &Apache::lonxml::debug("inside ".(scalar(@$incorrect)+1 gt $number_of_bubbles)); - if (defined($$incorrect[0]) && - scalar(@$incorrect)+1 >= $number_of_bubbles) { - &Apache::lonxml::debug("inside ".(scalar(@$incorrect)+1).":$number_of_bubbles"); + if (@incorrect) { + &Apache::lonxml::debug("inside ".(scalar(@incorrect)+1 gt $number_of_bubbles)); + if (defined($incorrect[0]) && + scalar(@incorrect)+1 >= $number_of_bubbles) { + &Apache::lonxml::debug("inside ".(scalar(@incorrect)+1).":$number_of_bubbles"); &Apache::response::setrandomnumber(); - my @rand_inc=&Math::Random::random_permutation(@$incorrect); + my @rand_inc=&Math::Random::random_permutation(@incorrect); @bubble_values=@rand_inc[0..($number_of_bubbles-2)]; @bubble_values=sort {$a <=> $b} (@bubble_values,$answer); - &Apache::lonxml::debug("Answer was :$answer: returning :".$#bubble_values.": whih are :".join(':',@bubble_values)); + &Apache::lonxml::debug("Answer was :$answer: returning :".$#bubble_values.": which are :".join(':',@bubble_values)); &Math::Random::random_set_seed(@oldseed); + + my $correct; + for(my $i=0; $i<=$#bubble_values;$i++) { + if ($bubble_values[$i] eq $answer) { + $correct = $alphabet[$i]; + last; + } + } + if (defined($format) && $format ne '') { my @bubble_display; foreach my $value (@bubble_values) { push(@bubble_display, &format_number($value,$format,$target,$safeeval)); } - return (\@bubble_values,\@bubble_display); + return (\@bubble_values,\@bubble_display,$correct); } else { - return (\@bubble_values,\@bubble_values); + return (\@bubble_values,\@bubble_values,$correct); } } - if (defined($$incorrect[0]) && - scalar(@$incorrect)+1 < $number_of_bubbles) { - &Apache::lonxml::warning("Not enough incorrect answers were specified in the incorrect array, ignoring the specified incorrect answers and instead generating them (".join(',',@$incorrect).")."); + if (defined($incorrect[0]) && + scalar(@incorrect)+1 < $number_of_bubbles) { + &Apache::lonxml::warning("Not enough incorrect answers were specified in the incorrect array, ignoring the specified incorrect answers and instead generating them (".join(',',@incorrect).")."); } } my @factors = (1.13,1.17,1.25,1.33,1.45); #default values of factors @@ -668,14 +998,25 @@ sub make_numerical_bubbles { $ind=&Math::Random::random_uniform_integer(1,0,$#factors); my $factor = $factors[$ind]; my @bubble_display; + my $answerfactor=$answer; + if ($answer==0) { + $answerfactor=&Math::Random::random_uniform_integer(1,1,100)/ + &Math::Random::random_uniform_integer(1,1,10); + } for ($ind=0;$ind<$number_of_bubbles;$ind++) { - $bubble_values[$ind] = $answer*($factor**($power-$powers[$#powers-$ind])); + $bubble_values[$ind] = $answerfactor*($factor**($power-$powers[$#powers-$ind])); $bubble_display[$ind] = &format_number($bubble_values[$ind], $format,$target,$safeeval); - + } + my $correct = $alphabet[$number_of_bubbles-$power]; + if ($answer==0) { + $correct='A'; + $bubble_values[0]=0; + $bubble_display[0] = &format_number($bubble_values[0], + $format,$target,$safeeval); } &Math::Random::random_set_seed(@oldseed); - return (\@bubble_values,\@bubble_display); + return (\@bubble_values,\@bubble_display,$correct); } sub get_tolrange { @@ -695,9 +1036,10 @@ sub get_tolrange { sub get_sigrange { my ($sig)=@_; - &Apache::lonxml::debug("Got a sig of :$sig:"); + #&Apache::lonxml::debug("Got a sig of :$sig:"); my $courseid=$env{'request.course.id'}; - if (lc($env{"course.$courseid.disablesigfigs"}) eq 'yes') { + if ($env{'request.state'} ne 'construct' + && lc($env{"course.$courseid.disablesigfigs"}) eq 'yes') { return (15,0); } my $sig_lbound; @@ -726,6 +1068,12 @@ sub get_sigrange { return ($sig_ubound,$sig_lbound); } +sub format_prior_response_string { + my ($mode,$answer) =@_; + return ''. + &HTML::Entities::encode($answer,'"<>&').''; +} + sub start_stringresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $result; @@ -759,7 +1107,7 @@ sub start_stringresponse { $answer= &Apache::lonxml::get_param('answer',$parstack,$safeeval); } - $Apache::inputtags::answertxt{$id}=$answer; + $Apache::inputtags::answertxt{$id}=[$answer]; } } elsif ($target eq 'answer' || $target eq 'grade') { &Apache::response::reset_params(); @@ -769,7 +1117,7 @@ sub start_stringresponse { sub end_stringresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; - my $increment=1; + my $result = ''; my $part=$Apache::inputtags::part; my $id=$Apache::inputtags::response[-1]; @@ -785,7 +1133,8 @@ sub end_stringresponse { $safeeval->share_from('capa',['&caparesponse_capa_check_answer']); if ($Apache::lonhomework::type eq 'exam' || &Apache::response::submitted('scantron')) { - $increment=&Apache::response::scored_response($part,$id); + &Apache::response::scored_response($part,$id); + } else { my $response = &Apache::response::getresponse(); if ( $response =~ /[^\s]/) { @@ -809,24 +1158,32 @@ sub end_stringresponse { &Apache::lonxml::debug("current $answer"); $ad = ($result) ? 'APPROX_ANS' : 'INCORRECT'; } else { - my $args_ref= - \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')}; - - $$args_ref{'response'}=$response; - &Apache::lonxml::debug("current $response"); - $$args_ref{'type'}= - &Apache::lonxml::get_param('type',$parstack,$safeeval); - foreach my $key (keys(%Apache::inputtags::params)) { - $$args_ref{$key}=$Apache::inputtags::params{$key}; + my @args = ('type'); + my $args_ref = &setup_capa_args($safeeval,$parstack, + \@args,$response); + if ($$args_ref{'type'} eq '') { + $$args_ref{'type'} = 'ci'; + } + &add_in_tag_answer($parstack,$safeeval); + my (@final_awards,@final_msgs,@names); + foreach my $name (keys(%answer)) { + &Apache::lonxml::debug(" doing $name with ".join(':',@{ $answer{$name}{'answers'} })); + ${$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=dclone($answer{$name}); + my ($result, @msgs)=&Apache::run::run("&caparesponse_check_list()",$safeeval); + &Apache::lonxml::debug('msgs are'.join(':',@msgs)); + my ($awards)=split(/:/,$result); + my (@awards) = split(/,/,$awards); + ($ad,$msg) = + &Apache::inputtags::finalizeawards(\@awards,\@msgs); + push(@final_awards,$ad); + push(@final_msgs,$msg); + push(@names,$name); + &Apache::lonxml::debug("\n
result:$result:$Apache::lonxml::curdepth
\n"); } - &Apache::lonxml::debug('answer is'.join(':',$answer)); - @{$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=($answer); - ($result, my @msgs)=&Apache::run::run("&caparesponse_check_list()",$safeeval); - &Apache::lonxml::debug('msgs are'.join(':',@msgs)); - my ($awards)=split(/:/,$result); - my (@awards) = split(/,/,$awards); - ($ad,$msg) = &Apache::inputtags::finalizeawards(\@awards,\@msgs); - &Apache::lonxml::debug("\n
result:$result:$Apache::lonxml::curdepth
\n"); + my ($ad, $msg, $name) = + &Apache::inputtags::finalizeawards(\@final_awards, + \@final_msgs, + \@names,1); } if ($Apache::lonhomework::type eq 'survey' && ($ad eq 'INCORRECT' || $ad eq 'APPROX_ANS' || @@ -838,20 +1195,8 @@ sub end_stringresponse { $Apache::lonhomework::results{"resource.$part.$id.awardmsg"}=$msg; } } - } elsif ($target eq 'web' || $target eq 'tex') { - my $award = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.solved"}; - my $status = $Apache::inputtags::status['-1']; - if ($Apache::lonhomework::type eq 'exam' && $target eq 'tex') { - $result.='\fbox{\fbox{\parbox{\textwidth-5mm}{\strut\\\\\strut\\\\\strut\\\\\strut\\\\}}}'; - $increment = &Apache::response::repetition(); - $result.='\begin{enumerate}'; - for (my $i=0;$i<$increment;$i++) { - $result.='\item[\textbf{'.($Apache::lonxml::counter+$i). - '}.]\textit{Leave blank on scoring form}\vskip 0 mm'; - } - $result.= '\end{enumerate}'; - } } elsif ($target eq 'answer' || $target eq 'analyze') { + &add_in_tag_answer($parstack,$safeeval); if ($target eq 'analyze') { push (@{ $Apache::lonhomework::analyze{"parts"} },"$part.$id"); $Apache::lonhomework::analyze{"$part.$id.type"} = 'stringresponse'; @@ -862,18 +1207,25 @@ sub end_stringresponse { if ($target eq 'answer') { $result.=&Apache::response::answer_header('stringresponse'); } -# foreach my $ans (@answers) { - if ($target eq 'answer') { - $result.=&Apache::response::answer_part('stringresponse',$answer); - if ($type eq 're') { + foreach my $name (keys(%answer)) { + my @answers = @{ $answer{$name}{'answers'} }; + for (my $i=0;$i<=$#answers;$i++) { + my $answer_part = $answers[$i]; + foreach my $element (@{$answer_part}) { + if ($target eq 'answer') { + $result.=&Apache::response::answer_part('stringresponse', + $element); + } elsif ($target eq 'analyze') { + push (@{ $Apache::lonhomework::analyze{"$part.$id.answer"}{$name}[$i] }, + $element); + } + } + if ($target eq 'answer' && $type eq 're') { $result.=&Apache::response::answer_part('stringresponse', $answerdisplay); } - } elsif ($target eq 'analyze') { - push (@{ $Apache::lonhomework::analyze{"$part.$id.answer"} }, - $answer); } -# } + } my $string='Case Insensitive'; if ($type eq 'mc') { $string='Multiple Choice'; @@ -901,10 +1253,16 @@ sub end_stringresponse { } } elsif ($target eq 'edit') { $result.=''.&Apache::edit::end_table; + } elsif ($target eq 'web' || $target eq 'tex') { + &Apache::response::setup_prior_tries_hash(\&format_prior_response_string); } if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || $target eq 'tex' || $target eq 'analyze') { - &Apache::lonxml::increment_counter($increment); + &Apache::lonxml::increment_counter(&Apache::response::repetition(), + "$part.$id"); + if ($target eq 'analyze') { + &Apache::lonhomework::set_bubble_lines(); + } } &Apache::response::end_response; return $result; 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.