--- loncom/homework/caparesponse/caparesponse.pm 2001/09/18 02:21:13 1.43 +++ loncom/homework/caparesponse/caparesponse.pm 2007/03/01 02:31:29 1.209 @@ -1,204 +1,1232 @@ # The LearningOnline Network with CAPA # caparesponse definition +# +# $Id: caparesponse.pm,v 1.209 2007/03/01 02:31:29 albertel Exp $ +# +# Copyright Michigan State University Board of Trustees +# +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# http://www.lon-capa.org/ +# 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); -sub BEGIN { - &Apache::lonxml::register('Apache::caparesponse',('caparesponse','numericalresponse','stringresponse')); +BEGIN { + &Apache::lonxml::register('Apache::caparesponse',('numericalresponse','stringresponse','formularesponse')); } -sub start_caparesponse { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - my $id = &Apache::response::start_response($parstack,$safeeval); - return ''; -} - -sub end_caparesponse { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; - my $result = ''; - if ( $target eq 'grade' ) { - if ( defined $ENV{'form.submitted'}) { - $safeeval->share_from('capa',['&caparesponse_capa_check_answer']); - my $response = $ENV{'form.HWVAL'.$Apache::inputtags::response['-1']}; - if ( $response =~ /[^\s]/) { - my $id = $Apache::inputtags::response['-1']; - my $previous= &Apache::response::check_for_previous($response,$id,$response); - if ( $previous ) { - $result = 'PREVIOUSLY_USED'; - } else { - $Apache::lonhomework::results{"resource.$Apache::inputtags::part.$id.submission"}=$response; - &Apache::lonxml::debug("submitted a $response
\n"); - &Apache::lonxml::debug($$parstack[$#$parstack] . "\n
"); - my $expression="&caparesponse_check('".$response."','". - $$parstack[$#$parstack]. - ';my $tol="'.$Apache::inputtags::params{'tol'}.'"'. - ';my $sig="'.$Apache::inputtags::params{'sig'}.'"'. - "');"; - $result = &Apache::run::run($expression,$safeeval); - my ($ad) = split /:/ , $result; - $Apache::lonhomework::results{"resource.$Apache::inputtags::part.$id.awarddetail"}=$ad; - &Apache::lonxml::debug("$expression"); - &Apache::lonxml::debug("\n
result:$result:$Apache::lonxml::curdepth
\n"); - } - } - } - } elsif ($target eq 'web') { - #$result .= "The correct answer is ".&Apache::run::run("{$$parstack['-1'];".'return $answer}',$safeeval)."\n"; - } - #Apache::lonxml::debug("\n
\nreal end caparesponse
\n"); - &Apache::response::end_response; - return ''; +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; + $cur_name = &Apache::lonxml::get_param('name',$parstack,$safeeval); + if ($cur_name =~ /^\s*$/) { $cur_name = $Apache::lonxml::curdepth; } + my $type = &Apache::lonxml::get_param('type',$parstack,$safeeval); + if (!defined($type) && $tagstack->[-2] eq 'answergroup') { + $type = &Apache::lonxml::get_param('type',$parstack,$safeeval,-2); + } + 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; + 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,$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,$style); + $bodytext = &Apache::run::evaluate($bodytext,$safeeval, + $$parstack[-1]); + + 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; +} + +sub end_value { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + if ($target eq 'edit') { + $result = &Apache::edit::end_table(); + } + return $result; +} + +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("/array",$parser,$style); + my @values = &Apache::run::evaluate($bodytext,$safeeval, + $$parstack[-1]); + push(@{ $answer{$cur_name}{'answers'} },@values); + } + return $result; +} + +sub end_array { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + +sub start_unit { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; +} + +sub end_unit { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + my $result; + return $result; } sub start_numericalresponse { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; - my $id = &Apache::response::start_response($parstack,$safeeval); - my $result; - if ($target eq 'edit') { - $result.=&Apache::edit::tag_start($target,$token,&Apache::lonxml::description($token)); - $result.=&Apache::edit::text_arg('Answer:','answer',$token); - if ($token->[1] eq 'numericalresponse') { - $result.=&Apache::edit::text_arg('Unit:','unit',$token,5); - $result.=&Apache::edit::text_arg('Format:','format',$token,4); - } else { - $result.=&Apache::edit::select_arg('Type:','type', - ['cs','ci','mc'],$token) + my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; + &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); + undef(%{$safeeval->varglob('LONCAPA::CAPAresponse_args')}); + if ($target eq 'edit') { + $result.=&Apache::edit::tag_start($target,$token); + $result.=&Apache::edit::text_arg('Answer:','answer',$token); + if ($token->[1] eq 'numericalresponse') { + $result.=&Apache::edit::text_arg('Incorrect Answers:','incorrect', + $token). + &Apache::loncommon::help_open_topic('numerical_wrong_answers'); + $result.=&Apache::edit::text_arg('Unit:','unit',$token,5). + &Apache::loncommon::help_open_topic('Physical_Units'); + $result.=&Apache::edit::text_arg('Format:','format',$token,4). + &Apache::loncommon::help_open_topic('Numerical_Response_Format'); + } elsif ($token->[1] eq 'formularesponse') { + $result.=&Apache::edit::text_arg('Sample Points:','samples', + $token,40). + &Apache::loncommon::help_open_topic('Formula_Response_Sampling'); + } + $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); + } elsif ($target eq 'modified') { + my $constructtag; + if ($token->[1] eq 'numericalresponse') { + $constructtag=&Apache::edit::get_new_args($token,$parstack, + $safeeval,'answer', + 'incorrect','unit', + 'format'); + } elsif ($token->[1] eq 'formularesponse') { + $constructtag=&Apache::edit::get_new_args($token,$parstack, + $safeeval,'answer', + 'samples'); + } + if ($constructtag) { + $result = &Apache::edit::rebuild_tag($token); + $result.=&Apache::edit::handle_insert(); + } + } elsif ($target eq 'meta') { + $result=&Apache::response::meta_package_write('numericalresponse'); + } elsif ($target eq 'answer' || $target eq 'grade') { + &Apache::response::reset_params(); + } elsif ($target eq 'web') { + my $partid = $Apache::inputtags::part; + my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit'); + &Apache::lonxml::debug("Got unit $hideunit for $partid $id"); + #no way to enter units, with radio buttons + if (lc($hideunit) eq "yes") { + my $unit=&Apache::lonxml::get_param_var('unit',$parstack, + $safeeval); + if ($unit =~ /\S/) { $result.=" (in $unit) "; } + } + if ( &Apache::response::show_answer() ) { + &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]; + } else { + $format=$formats[0]; + } + if ($unit=~/\$/) { $format="\$".$format; $unit=~s/\$//g; } + if ($unit=~/\,/) { $format="\,".$format; $unit=~s/\,//g; } + my $formatted=&format_number($element,$format,$target, + $safeeval); + $answertxt.=' '.$formatted.','; + } + + } + chop($answertxt); + if ($target eq 'web') { + $answertxt.=" $unit "; + } + + push(@answertxt,$answertxt) } - $result.=''; - } elsif ($target eq 'modified') { - my $constructtag; - if ($token->[1] eq 'numericalresponse') { - $constructtag=&Apache::edit::get_new_args($token,$parstack,$safeeval, - 'answer','unit','format'); + + my $id = $Apache::inputtags::response[-1]; + $Apache::inputtags::answertxt{$id}=\@answertxt; +} + +sub setup_capa_args { + my ($safeeval,$parstack,$args,$response) = @_; + my $args_ref= \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')}; + 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}; + } + &setup_capa_response($args_ref,$response); + return $args_ref; +} + +sub setup_capa_response { + my ($args_ref,$response) = @_; + + use Data::Dumper; + &Apache::lonxml::debug("response dump is ".&Dumper($response)); + + if (ref($response)) { + $$args_ref{'response'}=dclone($response); } else { - $constructtag=&Apache::edit::get_new_args($token,$parstack,$safeeval, - 'answer','type'); + $$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'}); + } + #sig fig don't make much sense either + if (($Apache::lonhomework::type eq 'exam' || + &Apache::response::submitted('scantron') || + $ignore_sig) && + $tag eq 'numericalresponse') { + delete($$args_ref{'sig'}); + } + + if ($tag eq 'formularesponse') { + if ($$args_ref{'samples'}) { + $$args_ref{'type'}='fml'; + } else { + $$args_ref{'type'}='math'; + } + } elsif ($tag eq 'numericalresponse') { + $$args_ref{'type'}='float'; } - if ($constructtag) { - $result = &Apache::edit::rebuild_tag($token); - $result.=&Apache::edit::handle_insert(); - } - } elsif ($target eq 'meta') { - $result=&Apache::response::meta_package_write('numericalresponse'); - } - return $result; + + &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}); + &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); + push(@final_awards,$ad); + push(@final_msgs,$msg); + push(@names,$name); + } + my ($ad, $msg, $name) = &Apache::inputtags::finalizeawards(\@final_awards, + \@final_msgs, + \@names,1); + &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 && defined($answer[0])) { + $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)=@_; - my $result = ''; - if ( $target eq 'grade' ) { - if ( defined $ENV{'form.submitted'}) { - &Apache::response::setup_params('numericalresponse'); - $safeeval->share_from('capa',['&caparesponse_capa_check_answer']); - my $partid = $Apache::inputtags::part; - my $id = $Apache::inputtags::response['-1']; - my $response = $ENV{'form.HWVAL'.$id}; - if ( $response =~ /[^\s]/) { - my %previous = &Apache::response::check_for_previous($response,$partid,$id); - $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; - &Apache::lonxml::debug("submitted a $response
\n"); - &Apache::lonxml::debug($$parstack[$#$parstack] . "\n
"); - $response =~ s/\\/\\\\/g; - $response =~ s/\'/\\\'/g; - &Apache::lonxml::debug("current $response"); - my $expression="&caparesponse_check_list('".$response."','". - $$parstack[$#$parstack]; - foreach my $key (keys(%Apache::inputtags::params)) { - $expression.= ';my $'. #' - $key.'="'.$Apache::inputtags::params{$key}.'"'; - } - $expression.="');"; - $result = &Apache::run::run($expression,$safeeval); - my ($awards) = split /:/ , $result; - my ($ad) = &Apache::inputtags::finalizeawards(split /,/ , $awards); - if ( $previous{'used'} && ($previous{'award'} eq $ad) ) { - if ($previous{'last'}) { - push(@Apache::inputtags::previous,'PREVIOUSLY_LAST'); - } else { - push(@Apache::inputtags::previous,'PREVIOUSLY_USED'); - } - } - $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad; - &Apache::lonxml::debug("$expression"); - &Apache::lonxml::debug("\n
result:$result:$Apache::lonxml::curdepth
\n"); - $result=''; - } - } - } elsif ($target eq 'web') { - my $award = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.solved"}; - my $status = $Apache::inputtags::status['-1']; - if ($award =~ /^correct/ || $status eq "SHOW_ANSWER" ) { - my $answervar=&Apache::lonxml::get_param('answer',$parstack,$safeeval); - my (@answers)=&Apache::run::run("return $answervar",$safeeval,1); - if (!defined($answers[0])) { $answers[0]=$answervar; } else { - &Apache::lonxml::debug("answers is $#answers :$answers[0]:"); - } - my $formatvar=&Apache::lonxml::get_param('format',$parstack,$safeeval); - my (@formats)=&Apache::run::run("return $formatvar",$safeeval,1); - if (!defined($formats[0])) { $formats[0]=$formatvar; } - - my $unit=&Apache::lonxml::get_param('unit',$parstack,$safeeval); - - $result="

The computer got "; - - for (my $i=0; $i <= $#answers; $i++) { - my $answer=$answers[$i]; - my $format; - if ($#formats > 0) { - $format=$formats[$i]; + 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) { + &Apache::lonxml::default_homework_load($safeeval); + } + 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 'mathresponse'))) { + $increment=&Apache::response::scored_response($partid,$id); } else { - $format=$formats[0]; + my $response = &Apache::response::getresponse(); + if ( $response =~ /[^\s]/) { + my %previous = &Apache::response::check_for_previous($response,$partid,$id); + &Apache::lonxml::debug("submitted a $response
\n"); + &Apache::lonxml::debug($$parstack[-1] . "\n
"); + + if ( &Apache::response::submitted('scantron')) { + &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,$name)=&check_submission($response,$partid,$id, + $tag,$parstack, + $safeeval); + + &Apache::lonxml::debug('ad is'.$ad); + if ($ad eq 'SIG_FAIL') { + my ($sig_u,$sig_l)= + &get_sigrange($Apache::inputtags::params{'sig'}); + $msg=join(':',$msg,$sig_l,$sig_u); + &Apache::lonxml::debug("sigs bad $sig_u $sig_l ". + $Apache::inputtags::params{'sig'}); + } + &Apache::lonxml::debug("\n
result:$result:$Apache::lonxml::curdepth
\n"); + if ($Apache::lonhomework::type eq 'survey' && + ($ad eq 'INCORRECT' || $ad eq 'APPROX_ANS' || + $ad eq 'EXACT_ANS')) { + $ad='SUBMITTED'; + } + &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') { + &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') { + # 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 @alphabet=('A'..'Z'); + if ($target eq 'web') { + if ($tag eq 'numericalresponse') { + if ($unit=~/\S/) {$result.=' (in '.$unit.')

';} + $result.= ''; + my $previous=$Apache::lonhomework::history{"resource.$Apache::inputtags::part.$id.submission"}; + for (my $ind=0;$ind<$number_of_bubbles;$ind++) { + my $checked=''; + if ($previous eq $bubble_values->[$ind]) { + $checked=" checked='on' "; + } + $result.=''; + } + $result.='
'.$alphabet[$ind].': '. + $bubble_display->[$ind].'
'; + } + } elsif ($target eq 'tex') { + if ((defined $unit) and ($unit=~/\S/) and ($Apache::lonhomework::type eq 'exam')) { + $result.=' \textit{(in} \verb|'.$unit.'|\textit{)} '; + } + if ($tag eq 'numericalresponse') { + my ($celllength,$number_of_tables,@table_range)= + &get_table_sizes($number_of_bubbles,$bubble_display); + my $j=0; + my $cou=0; + $result.='\vskip -1 mm \noindent \begin{enumerate}\item[\textbf{'.$Apache::lonxml::counter.'}.]'; + for (my $i=0;$i<$number_of_tables;$i++) { + $result.='\vskip -1 mm \noindent \setlength{\tabcolsep}{2 mm}\begin{tabular}{'; + for (my $ind=0;$ind<$table_range[$j];$ind++) { + $result.='p{3 mm}p{'.$celllength.' mm}'; + } + $result.='}'; + for (my $ind=$cou;$ind<$cou+$table_range[$j];$ind++) { + $result.='\hskip -4 mm {\small \textbf{'.$alphabet[$ind].'}}$\bigcirc$ & \hskip -3 mm {\small '.$bubble_display->[$ind].'} '; + if ($ind != $cou+$table_range[$j]-1) {$result.=' & ';} + } + $cou += $table_range[$j]; + $j++; + $result.='\\\\\end{tabular}\vskip 0 mm '; + } + $result.='\end{enumerate}'; + } else { + $increment = &Apache::response::repetition(); + } + } + } + &setup_prior_tries_hash(); + } elsif ($target eq 'edit') { + $result.=''.&Apache::edit::end_table; + } elsif ($target eq 'answer' || $target eq 'analyze') { + my $part_id="$partid.$id"; + if ($target eq 'analyze') { + push (@{ $Apache::lonhomework::analyze{"parts"} },$part_id); + $Apache::lonhomework::analyze{"$part_id.type"} = $tag; + my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval); + if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); } + push (@{ $Apache::lonhomework::analyze{"$part_id.incorrect"} }, @incorrect); + &Apache::response::check_if_computed($token,$parstack, + $safeeval,'answer'); + } + if (scalar(@$tagstack)) { + &Apache::response::setup_params($tag,$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); + + if ($target eq 'answer') { + $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); + } } - if ((defined($format)) && ($format ne '')) { - &Apache::lonxml::debug("formatting with :$format: answer :$answer:"); - $result.=sprintf('%.'.$format,$answer).','; + 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}=[]; + } + } + 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); + } + } + } + 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];} + 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') { + 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"); + } + } 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); + } + $result.=&Apache::response::next_answer($tag,$name); + } + if ($target eq 'answer') { + $result.=&Apache::response::answer_footer($tag); + } + } + if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || + $target eq 'tex' || $target eq 'analyze') { + &Apache::lonxml::increment_counter($increment); + } + &Apache::response::end_response(); + return $result; +} + +sub setup_prior_tries_hash { + #FIXME support multi answer numericals/formula + my $part=$Apache::inputtags::part; + my $id=$Apache::inputtags::response[-1]; + foreach my $i (1..$Apache::lonhomework::history{'version'}) { + my $key = "$i:resource.$part.$id.submission"; + next if (!exists($Apache::lonhomework::history{"$key"})); + $Apache::inputtags::submission_display{$key} = + '
'.&HTML::Entities::encode($Apache::lonhomework::history{$key},
+					  '"<>&').'
'; + } +} + +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); + } + use Data::Dumper; + &Apache::lonxml::debug("count dump is ".&Dumper(\%counts)); + my $expected_number_of_inputs = (keys(%counts))[0]; + if ( $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 + my $cell_width=0; + foreach my $member (@$rbubble_values) { + my $cell_width_real=0; + if ($member=~/(\+|-)?(\d*)\.?(\d*)\s*\$?\\times\s*10\^{(\+|-)?(\d+)}\$?/) { + $cell_width_real=(length($2)+length($3)+length($5)+7)*$scale; + } elsif ($member=~/(\d*)\.?(\d*)(E|e)(\+|-)?(\d*)/) { + $cell_width_real=(length($1)+length($2)+length($5)+9)*$scale; + } elsif ($member=~/(\d*)\.(\d*)/) { + $cell_width_real=(length($1)+length($2)+3)*$scale; } else { - &Apache::lonxml::debug("no format answer :$answer:"); - $result.="$answer,"; + $cell_width_real=(length($member)+1)*$scale*0.9; + } + if ($cell_width_real>$cell_width) {$cell_width=$cell_width_real;} + } + $cell_width+=8; + my $textwidth; + if ($env{'form.textwidth'} ne '') { + $env{'form.textwidth'}=~/(\d*)\.?(\d*)/; + $textwidth=$1.'.'.$2; + } else { + $env{'form.textwidth'}=~/(\d+)\.?(\d*)/; + $textwidth=$1.'.'.$2; + } + 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;} + 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;} + if ($number_of_bubbles % $bubbles_per_line) { + $number_of_tables++; + push @table_range,($number_of_bubbles % $bubbles_per_line); + } + $cell_width-=8; + $cell_width=$cell_width*3/4; + return ($cell_width,$number_of_tables,@table_range); +} + +sub format_number { + my ($number,$format,$target,$safeeval)=@_; + my $ans; + if ($format eq '') { + #What is the number? (integer,decimal,floating point) + if ($number=~/^(\d*\.?\d*)(E|e)[+\-]?(\d*)$/) { + $format = '3e'; + } elsif ($number=~/^(\d*)\.(\d*)$/) { + $format = '4f'; + } elsif ($number=~/^(\d*)$/) { + $format = 'd'; + } + } + if (!$Apache::lonxml::default_homework_loaded) { + &Apache::lonxml::default_homework_load($safeeval); + } + $ans=&Apache::run::run("&prettyprint(q\0$number\0,q\0$format\0,q\0$target\0)",$safeeval); + return $ans; +} + +sub make_numerical_bubbles { + my ($part,$id,$target,$parstack,$safeeval) =@_; + + 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=(); + my @alphabet=('A'..'Z'); + + &Apache::lonxml::debug("answer is $answer incorrect is @incorrect"); + my @oldseed=&Math::Random::random_get_seed(); + 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); + @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.": 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,$correct); + } else { + 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).")."); + } + } + my @factors = (1.13,1.17,1.25,1.33,1.45); #default values of factors + my @powers = (1..$number_of_bubbles); + &Apache::response::setrandomnumber(); + my $ind=&Math::Random::random_uniform_integer(1,0,$#powers); + my $power = $powers[$ind]; + $ind=&Math::Random::random_uniform_integer(1,0,$#factors); + my $factor = $factors[$ind]; + my @bubble_display; + for ($ind=0;$ind<$number_of_bubbles;$ind++) { + $bubble_values[$ind] = $answer*($factor**($power-$powers[$#powers-$ind])); + $bubble_display[$ind] = &format_number($bubble_values[$ind], + $format,$target,$safeeval); + + } + my $correct = $alphabet[$number_of_bubbles-$power]; + &Math::Random::random_set_seed(@oldseed); + return (\@bubble_values,\@bubble_display,$correct); +} + +sub get_tolrange { + my ($ans,$tol)=@_; + my ($high,$low); + if ($tol =~ /%$/) { + chop($tol); + my $change=$ans*($tol/100.0); + $high=$ans+$change; + $low=$ans-$change; + } else { + $high=$ans+$tol; + $low=$ans-$tol; + } + return ($high,$low); +} + +sub get_sigrange { + my ($sig)=@_; + #&Apache::lonxml::debug("Got a sig of :$sig:"); + my $courseid=$env{'request.course.id'}; + if (lc($env{"course.$courseid.disablesigfigs"}) eq 'yes') { + return (15,0); + } + my $sig_lbound; + my $sig_ubound; + if ($sig eq '') { + $sig_lbound = 0; #SIG_LB_DEFAULT + $sig_ubound =15; #SIG_UB_DEFAULT + } else { + ($sig_lbound,$sig_ubound) = split(/,/,$sig); + if (!defined($sig_lbound)) { + $sig_lbound = 0; #SIG_LB_DEFAULT + $sig_ubound =15; #SIG_UB_DEFAULT } - } - chop $result; - $result.=" $unit.

"; - } - } elsif ($target eq 'edit') { - $result.=''.&Apache::edit::end_table; - } elsif ($target eq 'answer') { - my $answer= &Apache::run::run('eval \''.$$parstack[-1].';return $answer\'', - $safeeval); - my (@answers) = &Apache::run::run("eval ".$answer,$safeeval); - # if the eval fails just use what is in the answer exactly - if (!defined(@answers) || !defined($answers[0])) { - $result.="list zero is undefined
"; - $answers[0]=$answer; - } - $result.="
An answers: $answer"; - foreach my $ans (@answers) { - $result.="
An answer: $ans"; - } - $result .= "
".&Apache::run::run('return $result',$safeeval); - } - &Apache::response::end_response; - return $result; + if (!defined($sig_ubound)) { $sig_ubound=$sig_lbound; } + } + if (($sig_ubound<$sig_lbound) || + ($sig_lbound > 15) || + ($sig =~/(\+|-)/ ) ) { + my $errormsg=&mt("Invalid Significant figures detected")." ($sig)"; + if ($env{'request.state'} eq 'construct') { + $errormsg.= + &Apache::loncommon::help_open_topic('Significant_Figures'); + } + &Apache::lonxml::error($errormsg); + } + return ($sig_ubound,$sig_lbound); } sub start_stringresponse { - my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; - my $result; - if ($target eq 'meta') { - $result=&Apache::response::meta_package_write('stringresponse'); - } else { - $result.=&start_numericalresponse(@_); - } - return $result; + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result; + my $id = &Apache::response::start_response($parstack,$safeeval); + if ($target eq 'meta') { + $result=&Apache::response::meta_package_write('stringresponse'); + } elsif ($target eq 'edit') { + $result.=&Apache::edit::tag_start($target,$token); + $result.=&Apache::edit::text_arg('Answer:','answer',$token); + $result.=&Apache::edit::select_arg('Type:','type', + [['cs','Case Sensitive'],['ci','Case Insensitive'], + ['mc','Case Insensitive, Any Order'], + ['re','Regular Expression']],$token); + $result.=&Apache::edit::text_arg('String to display for answer:', + 'answerdisplay',$token); + $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); + } elsif ($target eq 'modified') { + my $constructtag; + $constructtag=&Apache::edit::get_new_args($token,$parstack, + $safeeval,'answer', + 'type','answerdisplay'); + if ($constructtag) { + $result = &Apache::edit::rebuild_tag($token); + $result.=&Apache::edit::handle_insert(); + } + } elsif ($target eq 'web') { + if ( &Apache::response::show_answer() ) { + my $answer= + &Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval); + if (!defined $answer || $answer eq '') { + $answer= + &Apache::lonxml::get_param('answer',$parstack,$safeeval); + } + $Apache::inputtags::answertxt{$id}=[$answer]; + } + } elsif ($target eq 'answer' || $target eq 'grade') { + &Apache::response::reset_params(); + } + return $result; } sub end_stringresponse { - return end_numericalresponse(@_); + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + + my $result = ''; + my $part=$Apache::inputtags::part; + my $id=$Apache::inputtags::response[-1]; + my $answer=&Apache::lonxml::get_param('answer',$parstack,$safeeval); + my $type=&Apache::lonxml::get_param('type',$parstack,$safeeval); + my $answerdisplay=&Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval); + &Apache::lonxml::debug("current $answer ".$token->[2]); + if (!$Apache::lonxml::default_homework_loaded) { + &Apache::lonxml::default_homework_load($safeeval); + } + if ( $target eq 'grade' && &Apache::response::submitted() ) { + &Apache::response::setup_params('stringresponse',$safeeval); + $safeeval->share_from('capa',['&caparesponse_capa_check_answer']); + if ($Apache::lonhomework::type eq 'exam' || + &Apache::response::submitted('scantron')) { + &Apache::response::scored_response($part,$id); + + } else { + my $response = &Apache::response::getresponse(); + if ( $response =~ /[^\s]/) { + my %previous = &Apache::response::check_for_previous($response, + $part,$id); + &Apache::lonxml::debug("submitted a $response
\n"); + &Apache::lonxml::debug($$parstack[-1] . "\n
"); + $Apache::lonhomework::results{"resource.$part.$id.submission"}= + $response; + my ($ad,$msg); + if ($type eq 're' ) { + # if the RE wasn't in a var it likely got munged, + # thus grab it from the var directly +# my $testans=$token->[2]->{'answer'}; +# if ($testans !~ m/^\s*\$/) { +# $answer=$token->[2]->{'answer'}; +# } + ${$safeeval->varglob('LONCAPA::response')}=$response; + $result = &Apache::run::run('if ($LONCAPA::response=~m'.$answer.') { return 1; } else { return 0; }',$safeeval); + &Apache::lonxml::debug("current $response"); + &Apache::lonxml::debug("current $answer"); + $ad = ($result) ? 'APPROX_ANS' : 'INCORRECT'; + } else { + my @args = ('type'); + my $args_ref = &setup_capa_args($safeeval,$parstack, + \@args,$response); + + &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"); + } + 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' || + $ad eq 'EXACT_ANS')) { + $ad='SUBMITTED'; + } + &Apache::response::handle_previous(\%previous,$ad); + $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}=$ad; + $Apache::lonhomework::results{"resource.$part.$id.awardmsg"}=$msg; + } + } + } 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'; + &Apache::response::check_if_computed($token,$parstack,$safeeval, + 'answer'); + } + &Apache::response::setup_params('stringresponse',$safeeval); + if ($target eq 'answer') { + $result.=&Apache::response::answer_header('stringresponse'); + } + 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); + } + } + } + my $string='Case Insensitive'; + if ($type eq 'mc') { + $string='Multiple Choice'; + } elsif ($type eq 'cs') { + $string='Case Sensitive'; + } elsif ($type eq 'ci') { + $string='Case Insensitive'; + } elsif ($type eq 're') { + $string='Regular Expression'; + } + if ($target eq 'answer') { + if ($env{'form.answer_output_mode'} eq 'tex') { + $result.=&Apache::response::answer_part('stringresponse', + "$string"); + } else { + $result.=&Apache::response::answer_part('stringresponse', + "$string"); + } + } elsif ($target eq 'analyze') { + push (@{$Apache::lonhomework::analyze{"$part.$id.str_type"}}, + $type); + } + if ($target eq 'answer') { + $result.=&Apache::response::answer_footer('stringresponse'); + } + } elsif ($target eq 'edit') { + $result.=''.&Apache::edit::end_table; + } + if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || + $target eq 'tex' || $target eq 'analyze') { + &Apache::lonxml::increment_counter(&Apache::response::repetition()); + } + &Apache::response::end_response; + return $result; +} + +sub start_formularesponse { + my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; + my $result; + if ($target eq 'meta') { + &Apache::response::start_response($parstack,$safeeval); + $result=&Apache::response::meta_package_write('formularesponse'); + &Apache::response::end_response(); + } else { + $result.=&start_numericalresponse(@_); + } + return $result; +} + +sub end_formularesponse { + return end_numericalresponse(@_); } 1; __END__ - + 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.