--- loncom/homework/response.pm 2003/10/27 19:27:09 1.87 +++ loncom/homework/response.pm 2005/04/04 10:04:09 1.118 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # various response type definitons response definition # -# $Id: response.pm,v 1.87 2003/10/27 19:27:09 albertel Exp $ +# $Id: response.pm,v 1.118 2005/04/04 10:04:09 foxr Exp $ # # Copyright Michigan State University Board of Trustees # @@ -28,6 +28,7 @@ package Apache::response; use strict; +use Apache::lonlocal; BEGIN { &Apache::lonxml::register('Apache::response',('responseparam','parameter','dataresponse')); @@ -45,6 +46,17 @@ sub start_response { push (@Apache::inputtags::response,$id); push (@Apache::inputtags::responselist,$id); @Apache::inputtags::inputlist=(); + if ($Apache::inputtags::part eq '' && + !$Apache::lonhomework::ignore_response_errors) { + &Apache::lonxml::error(&HTML::Entities::encode(&mt("Found a <*response> outside of a in a ed problem"),'<>&"')); + } + if ($Apache::inputtags::response_with_no_part && + $Apache::inputtags::part ne '0') { + &Apache::lonxml::error(&HTML::Entities::encode(&mt("<*response>s are both inside of and outside of , this is not a valid problem, errors in grading may occur."),'<>&"').'
'); + } + if ($Apache::inputtags::part eq '0') { + $Apache::inputtags::response_with_no_part=1; + } return $id; } @@ -73,35 +85,75 @@ sub end_hintresponse { return ''; } -# used by response to set the non-safe space random number generator to something -# that is stable and unique based on the part number and response number -sub setrandomnumber { - my $rndseed; - if ($ENV{'request.state'} eq "construct") { - $rndseed=$ENV{'form.rndseed'}; - if (!$rndseed) { $rndseed=time; } +my @randomseeds; +sub pushrandomnumber { + my $rand_alg=&Apache::lonnet::get_rand_alg(); + if (!$rand_alg || $rand_alg eq '32bit' || $rand_alg eq '64bit' || + $rand_alg eq '64bit2') { + # do nothing } else { - $rndseed=&Apache::lonnet::rndseed(); + my @seed=&Math::Random::random_get_seed(); + push (@randomseeds,\@seed); } + &Apache::response::setrandomnumber(); +} +sub poprandomnumber { + my $rand_alg=&Apache::lonnet::get_rand_alg(); + if (!$rand_alg || $rand_alg eq '32bit' || $rand_alg eq '64bit' || + $rand_alg eq '64bit2') { + return; + } + my $seed=pop(@randomseeds); + if ($seed) { + &Math::Random::random_set_seed(@$seed); + } else { + &Apache::lonxml::error("Unable to restore random algorithm."); + } +} + +sub setrandomnumber { + my $rndseed; + $rndseed=&Apache::structuretags::setup_rndseed(); + if (!defined($rndseed)) { $rndseed=&Apache::lonnet::rndseed(); } &Apache::lonxml::debug("randseed $rndseed"); # $rndseed=unpack("%32i",$rndseed); - my $rndmod=(&Apache::lonnet::numval($Apache::inputtags::part) << 10); - if (defined($Apache::inputtags::response['-1'])) { - $rndmod+=&Apache::lonnet::numval($Apache::inputtags::response[-1]); - } - if ($rndseed =~/,/) { - { - use integer; - my ($num1,$num2)=split(/,/,$rndseed); - $num1+=$rndmod; - $num2+=$rndmod; - $rndseed="$num1,$num2"; + my $rand_alg=&Apache::lonnet::get_rand_alg(); + my $rndmod; + if (!$rand_alg || $rand_alg eq '32bit' || $rand_alg eq '64bit' || + $rand_alg eq '64bit2') { + $rndmod=(&Apache::lonnet::numval($Apache::inputtags::part) << 10); + if (defined($Apache::inputtags::response[-1])) { + $rndmod+=&Apache::lonnet::numval($Apache::inputtags::response[-1]); + } + } elsif ($rand_alg eq '64bit3') { + $rndmod=(&Apache::lonnet::numval2($Apache::inputtags::part) << 10); + if (defined($Apache::inputtags::response[-1])) { + $rndmod+=&Apache::lonnet::numval2($Apache::inputtags::response[-1]); } } else { + my $shift=(4*scalar(@Apache::inputtags::responselist))%30; + $rndmod=(&Apache::lonnet::numval3($Apache::inputtags::part) << (($shift+15)%30)); + if (defined($Apache::inputtags::response[-1])) { + $rndmod+=(&Apache::lonnet::numval3($Apache::inputtags::response[-1]) << $shift ); + } + } + if ($rndseed =~/([,:])/) { + my $char=$1; + use integer; + my ($num1,$num2)=split(/\Q$char\E/,$rndseed); + $num1+=$rndmod; + $num2+=$rndmod; + if($Apache::lonnet::_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); } + $rndseed=$num1.$char.$num2; + } else { $rndseed+=$rndmod; + if($Apache::lonnet::_64bit) { + use integer; + $rndseed=(($rndseed<<32)>>32); + } } + &Apache::lonxml::debug("randseed $rndmod $rndseed"); &Apache::lonnet::setup_random_from_rndseed($rndseed); - &Apache::lonxml::debug("randseed $rndseed"); return ''; } @@ -115,8 +167,8 @@ sub meta_parameter_write { } $result.= ' name="'.$name.'"'. ' type="'.$type.'"'. -($default?' default="'.$default.'"':''). -($display?' display="'.$display.' [Part: '.$partref.']"':'') +(defined($default)?' default="'.$default.'"':''). +(defined($display)?' display="'.$display.' [Part: '.$partref.']"':'') .'>' ."\n"; return $result; @@ -181,9 +233,16 @@ sub meta_part_order { if (@Apache::inputtags::partlist) { my @parts=@Apache::inputtags::partlist; shift(@parts); - return ''.join(',',@parts).''; + return ''.join(',',@parts).''."\n"; } else { - return '0'; + return '0'."\n"; + } +} + +sub meta_response_order { + if (@Apache::inputtags::responselist) { + return ''.join(',',@Apache::inputtags::responselist). + ''."\n"; } } @@ -192,7 +251,7 @@ sub check_for_previous { my %previous; $previous{'used'} = 0; foreach my $key (sort(keys(%Apache::lonhomework::history))) { - if ($key =~ /resource\.$partid\.$id\.submission/) { + if ($key =~ /resource\.$partid\.$id\.submission$/) { &Apache::lonxml::debug("Trying $key"); my $pastresponse=$Apache::lonhomework::history{$key}; if ($pastresponse eq $curresponse) { @@ -221,10 +280,11 @@ sub handle_previous { if ($$previous{'used'} && ($$previous{'award'} eq $ad) ) { if ($$previous{'last'}) { push(@Apache::inputtags::previous,'PREVIOUSLY_LAST'); - } else { + push(@Apache::inputtags::previous_version,$$previous{'version'}); + } elsif ($Apache::lonhomework::type ne 'survey') { push(@Apache::inputtags::previous,'PREVIOUSLY_USED'); + push(@Apache::inputtags::previous_version,$$previous{'version'}); } - push(@Apache::inputtags::previous_version,$$previous{'version'}); } } @@ -266,7 +326,7 @@ sub end_dataresponse { my ($symb,$courseid,$domain,$name)=&Apache::lonxml::whichuser(); my $allowed=&Apache::lonnet::allowed('mgr',$courseid); if ($allowed) { - &Apache::response::setup_params('dataresponse'); + &Apache::response::setup_params('dataresponse',$safeeval); my $partid = $Apache::inputtags::part; my $id = $Apache::inputtags::response['-1']; my $response = $ENV{'form.HWVAL_'.$id}; @@ -372,13 +432,11 @@ sub end_responseparam { } sub start_parameter { - my $result = &start_responseparam(@_); - return $result; + return &start_responseparam(@_); } sub end_parameter { - my $result = &end_responseparam(@_); - return $result; + return &end_responseparam(@_); } sub reset_params { @@ -386,7 +444,7 @@ sub reset_params { } sub setup_params { - my ($tag) = @_; + my ($tag,$safeeval) = @_; if ($ENV{'request.state'} eq 'construct') { return; } my %paramlist=(); @@ -409,7 +467,9 @@ sub setup_params { &Apache::lonxml::debug("using nothing"); $Apache::inputtags::params{$key}=''; } else { - &Apache::lonxml::debug("using value"); + my $string="{return qq\0".$value."\0}"; + my $newvalue=&Apache::run::run($string,$safeeval,1); + if (defined($newvalue)) { $value=$newvalue; } $Apache::inputtags::params{$key}=$value; } } @@ -451,16 +511,20 @@ sub answer_footer { } sub showallfoils { - my $return=0; - if (defined($ENV{'form.showallfoils'}) && - $ENV{'request.state'} eq 'construct') { - $return=1; + if (defined($ENV{'form.showallfoils'})) { + my ($symb)=&Apache::lonxml::whichuser(); + if (($ENV{'request.state'} eq 'construct') || + ($ENV{'user.adv'} && $symb eq '') || + ($Apache::lonhomework::viewgrades) ) { + return 1; + } } - return $return; + if ($Apache::lonhomework::type eq 'survey') { return 1; } + return 0; } sub getresponse { - my ($temp)=@_; + my ($temp,$resulttype)=@_; my $formparm='form.HWVAL_'.$Apache::inputtags::response['-1']; my $response; if (!defined($temp)) { @@ -480,7 +544,13 @@ sub getresponse { # save bubbled letter for later $Apache::lonhomework::results{"resource.$part.$id.scantron"}.= $response; - $response = $let_to_num{$response}; + if ($resulttype ne 'letter') { + if ($resulttype eq 'A is 1') { + $response = $let_to_num{$response}+1; + } else { + $response = $let_to_num{$response}; + } + } } else { $response = $ENV{$formparm}; } @@ -504,6 +574,7 @@ sub scored_response { if ($increase ne '') { $score+=$increase+1; } } my $weight = &Apache::lonnet::EXT("resource.$part.weight"); + if (!defined($weight) || $weight eq '' || $weight eq 0) { $weight = 1; } my $pcr=$score/$weight; $Apache::lonhomework::results{"resource.$part.$id.awarded"}=$pcr; $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= @@ -559,7 +630,6 @@ sub whichorder { for (my $i=0;$i<=$#bottomlist;$i++) { if ($bottomlist[$i]) { push(@whichopt,$bottomlist[$i]) } } - return @whichopt; } @@ -586,6 +656,15 @@ sub analyze_store_foilgroup { push (@{ $Apache::lonhomework::analyze{"$part_id.shown"} }, @{ $shown }); } +sub check_if_computed { + my ($token,$parstack,$safeeval,$name)=@_; + my $value = &Apache::lonxml::get_param($name,$parstack,$safeeval); + if (ref($token->[2]) eq 'HASH' && $value ne $token->[2]{$name}) { + my $part_id="$Apache::inputtags::part.$Apache::inputtags::response[-1]"; + $Apache::lonhomework::analyze{"$part_id.answercomputed"} = 1; + } +} + sub pick_foil_for_concept { my ($target,$attrs,$hinthash,$parstack,$safeeval)=@_; if (not defined(@{ $Apache::response::conceptgroup{'names'} })) { return; } @@ -621,6 +700,64 @@ sub pick_foil_for_concept { } +sub get_response_param { + my ($id,$name,$default)=@_; + my $parameter; + if ($ENV{'request.state'} eq 'construct' && + defined($Apache::inputtags::params{$name})) { + $parameter=$Apache::inputtags::params{$name}; + } else { + $parameter=&Apache::lonnet::EXT("resource.$id.$name"); + } + if (!defined($parameter) || $parameter eq '') { + $parameter = $default; + } + return $parameter; +} + +sub submitted { + my ($who)=@_; + + # when scatron grading any submission is a submission + if ($ENV{'form.submitted'} eq 'scantron') { return 1; } + # if the caller only cared if this was a scantron submission + if ($who eq 'scantron') { return 0; } + # if the Submit Answer button for this particular part was pressed + my $partid=$Apache::inputtags::part; + if (defined($ENV{'form.submit_'.$partid})) { return 1; } + # otherwise no submission occured + return 0; +} + +# basically undef and 0 (both false) mean that they still have work to do +# and all true values mean that they can't do any more work +# +# a return of undef means it is unattempted +# a return of 0 means it is attmpted and wrong but still has tries +# a return of 1 means it is marked correct +# a return of 2 means they have exceed maximum number of tries +# a return of 3 means it after the answer date +sub check_status { + my ($id)=@_; + if (!$id) { $id=$Apache::linputtags::part; } + my $curtime=&Apache::lonnet::EXT('system.time'); + my $opendate=&Apache::lonnet::EXT("resource.$id.opendate"); + my $duedate=&Apache::lonnet::EXT("resource.$id.duedate"); + my $answerdate=&Apache::lonnet::EXT("resource.$id.answerdate"); + if ( $opendate && $curtime > $opendate && + $duedate && $curtime > $duedate && + $answerdate && $curtime > $answerdate) { + return 3; + } + my $status=&Apache::lonnet::EXT("user.resource.resource.$id.solved"); + if ($status =~ /^correct/) { return 1; } + if (!$status) { return undef; } + my $maxtries=&Apache::lonnet::EXT("resource.$id.maxtries"); + if ($maxtries eq '') { $maxtries=2; } + my $curtries=&Apache::lonnet::EXT("user.resource.resource.$id.tries"); + if ($curtries < $maxtries) { return 0; } + return 2; +} 1; __END__