--- loncom/homework/response.pm 2007/06/20 22:36:52 1.172 +++ loncom/homework/response.pm 2014/08/28 14:41:18 1.236 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # various response type definitons response definition # -# $Id: response.pm,v 1.172 2007/06/20 22:36:52 foxr Exp $ +# $Id: response.pm,v 1.236 2014/08/28 14:41:18 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,11 +26,36 @@ # http://www.lon-capa.org/ # +=pod + +=head1 NAME + +Apache::response.pm + +=head1 SYNOPSIS + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + + +=head1 NOTABLE SUBROUTINES + +=over + +=item + +=back + +=cut + + package Apache::response; use strict; use Apache::lonlocal; use Apache::lonnet; +use Apache::inputtags(); use Apache::lonmaxima(); +use Apache::lonr(); BEGIN { &Apache::lonxml::register('Apache::response',('responseparam','parameter','dataresponse','customresponse','mathresponse')); @@ -112,9 +137,10 @@ sub poprandomnumber { } sub setrandomnumber { - my ($ignore_id2) = @_; - my $rndseed; - $rndseed=&Apache::structuretags::setup_rndseed(); + my ($ignore_id2,$target,$rndseed) = @_; + if (!defined($rndseed)) { + $rndseed=&Apache::structuretags::setup_rndseed(undef,$target); + } if (!defined($rndseed)) { $rndseed=&Apache::lonnet::rndseed(); } &Apache::lonxml::debug("randseed $rndseed"); # $rndseed=unpack("%32i",$rndseed); @@ -154,7 +180,7 @@ sub setrandomnumber { } else { ($rndmod,$rndmod2)=&Apache::lonnet::digest("$id1,$id2"); } - + $Apache::lonhomework::results{'resource.'.$id1.'.rawrndseed'}=$rndseed; if ($rndseed =~/([,:])/) { my $char=$1; use integer; @@ -171,6 +197,7 @@ sub setrandomnumber { } } &Apache::lonxml::debug("randseed $rndmod $rndseed"); + $Apache::lonhomework::results{'resource.'.$id1.'.rndseed'}=$rndseed; &Apache::lonnet::setup_random_from_rndseed($rndseed); return ''; } @@ -216,35 +243,26 @@ sub meta_stores_write { ">\n"; } +=pod + +=item mandatory_part_meta() + +Autogenerate metadata for mandatory +input (from RAT or lonparmset) and +output (to lonspreadsheet) +of each part + +Note: responseid-specific data 'submission' and 'awarddetail' +not available to spreadsheet -> skip here + +=cut + + sub mandatory_part_meta { -# -# Autogenerate metadata for mandatory -# input (from RAT or lonparmset) and -# output (to lonspreadsheet) -# of each part -# - return -# &meta_parameter_write('opendate','date_start','', -# 'Opening Date'). -# &meta_parameter_write('duedate','date_end','', -# 'Due Date'). -# &meta_parameter_write('answerdate','date_start','', -# 'Show Answer Date'). -# &meta_parameter_write('weight','int_zeropos','', -# 'Available Points'). -# &meta_parameter_write('maxtries','int_pos','', -# 'Maximum Number of Tries'). - &meta_package_write('part'). - &meta_stores_write('solved','string', - 'Problem Status'). - &meta_stores_write('tries','int_zeropos', - 'Number of Attempts'). - &meta_stores_write('awarded','float', - 'Partial Credit Factor'); -# -# Note: responseid-specific data 'submission' and 'awarddetail' -# not available to spreadsheet -> skip here -# + return &meta_package_write('part'). + &meta_stores_write('solved','string','Problem Status'). + &meta_stores_write('tries','int_zeropos','Number of Attempts'). + &meta_stores_write('awarded','float','Partial Credit Factor'); } sub meta_part_order { @@ -265,31 +283,51 @@ sub meta_response_order { } sub check_for_previous { - my ($curresponse,$partid,$id,$last) = @_; + my ($curresponse,$partid,$id,$last,$type) = @_; my %previous; $previous{'used'} = 0; + my $questiontype = $Apache::lonhomework::type; + my $curr_rndseed = $env{'form.'.$partid.'.rndseed'}; foreach my $key (sort(keys(%Apache::lonhomework::history))) { - if ($key =~ /resource\.$partid\.$id\.submission$/) { + if ($key =~ /resource\.\Q$partid\E\.\Q$id\E\.submission$/) { if ( $last && $key =~ /^(\d+):/ ) { next if ($1 >= $last); } &Apache::lonxml::debug("Trying $key"); my $pastresponse=$Apache::lonhomework::history{$key}; if ($pastresponse eq $curresponse) { - $previous{'used'} = 1; my $history; if ( $key =~ /^(\d+):/ ) { - $history=$1; + $history=$1; + next if ((($questiontype eq 'randomizetry') || + ($Apache::lonhomework::history{"$history:resource.$partid.type"} eq 'randomizetry')) && + ($curr_rndseed ne $Apache::lonhomework::history{"$history:resource.$partid.rndseed"})); $previous{'award'} = $Apache::lonhomework::history{"$history:resource.$partid.$id.awarddetail"}; $previous{'last'}='0'; push(@{ $previous{'version'} },$history); } else { + next if ((($questiontype eq 'randomizetry') || + ($Apache::lonhomework::history{"resource.$partid.type"} eq 'randomizetry')) && + ($curr_rndseed ne $Apache::lonhomework::history{"resource.$partid.rndseed"})); $previous{'award'} = $Apache::lonhomework::history{"resource.$partid.$id.awarddetail"}; $previous{'last'}='1'; } + $previous{'used'} = 1; if (! $previous{'award'} ) { $previous{'award'} = 'UNKNOWN'; } + if ($previous{'award'} eq 'INTERNAL_ERROR') { $previous{'used'}=0; } &Apache::lonxml::debug("got a match :$previous{'award'}:$previous{'used'}:"); - } + } elsif ($type eq 'ci') { + if (lc($pastresponse) eq lc($curresponse)) { + if ($key =~ /^(\d+):/) { + my $history = $1; + next if (($questiontype eq 'randomizetry') && + ($curr_rndseed ne $Apache::lonhomework::history{"$history:resource.$partid.rndseed"})); + push (@{$previous{'versionci'}},$history); + $previous{'awardci'} = $Apache::lonhomework::history{"$history:resource.$partid.$id.awarddetail"}; + $previous{'usedci'} = 1; + } + } + } } } &Apache::lonhomework::showhash(%previous); @@ -302,7 +340,10 @@ sub handle_previous { if ($$previous{'last'}) { push(@Apache::inputtags::previous,'PREVIOUSLY_LAST'); push(@Apache::inputtags::previous_version,$$previous{'version'}); - } elsif ($Apache::lonhomework::type ne 'survey') { + } elsif (($Apache::lonhomework::type ne 'survey') && + ($Apache::lonhomework::type ne 'surveycred') && + ($Apache::lonhomework::type ne 'anonsurvey') && + ($Apache::lonhomework::type ne 'anonsurveycred')) { push(@Apache::inputtags::previous,'PREVIOUSLY_USED'); push(@Apache::inputtags::previous_version,$$previous{'version'}); } @@ -358,7 +399,7 @@ sub end_dataresponse { $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}='SUBMITTED'; } } else { - $result='Not Permitted to change values.' + $result=&mt('Not Permitted to change values'); } } } @@ -383,7 +424,7 @@ sub start_customresponse { } elsif ($target eq 'edit') { $result.=&Apache::edit::tag_start($target,$token); $result.=&Apache::edit::text_arg('String to display for answer:', - 'answerdisplay',$token); + 'answerdisplay',$token,'50'); $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row(); } elsif ($target eq 'modified') { my $constructtag; @@ -423,14 +464,29 @@ sub end_customresponse { ${$safeeval->varglob('LONCAPA::customresponse_submission')}= $response; - my $award = &Apache::run::run('{ my $submission=$LONCAPA::customresponse_submission;'.$Apache::response::custom_answer[-1].'}',$safeeval); + my ($award,$score) = &Apache::run::run('{ my $submission=$LONCAPA::customresponse_submission;'.$Apache::response::custom_answer[-1].'}',$safeeval); if (!&Apache::inputtags::valid_award($award)) { $error = $award; $award = 'ERROR'; } + if (($award eq 'INCORRECT' || $award eq 'APPROX_ANS' || + $award eq 'EXACT_ANS')) { + if ($Apache::lonhomework::type eq 'survey') { + $award='SUBMITTED'; + } elsif ($Apache::lonhomework::type eq 'surveycred') { + $award='SUBMITTED_CREDIT'; + } elsif ($Apache::lonhomework::type eq 'anonsurvey') { + $award='ANONYMOUS'; + } elsif ($Apache::lonhomework::type eq 'anonsurveycred') { + $award='ANONYMOUS_CREDIT'; + } + } &Apache::response::handle_previous(\%previous,$award); $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= $award; + if ($award eq 'ASSIGNED_SCORE') { + $Apache::lonhomework::results{"resource.$part.$id.awarded"}=1.0*$score; + } if ($error) { $Apache::lonhomework::results{"resource.$part.$id.awardmsg"}= $error; @@ -447,11 +503,16 @@ sub end_customresponse { $result .= &Apache::response::answer_footer('customresponse'); } if ($target eq 'web') { - &setup_prior_tries_hash(\&format_prior_response_math); + &setup_prior_tries_hash(\&format_prior_response_custom); } if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || $target eq 'tex' || $target eq 'analyze') { - &Apache::lonxml::increment_counter(&Apache::response::repetition()); + my $repetition = &repetition(); + &Apache::lonxml::increment_counter($repetition,"$part.$id"); + if ($target eq 'analyze') { + $Apache::lonhomework::analyze{"$part.$id.type"} = 'customresponse'; + &Apache::lonhomework::set_bubble_lines(); + } } pop(@Apache::lonxml::namespace); pop(@Apache::response::custom_answer); @@ -463,6 +524,9 @@ sub end_customresponse { sub format_prior_response_custom { my ($mode,$answer) =@_; + if (ref($answer) eq 'ARRAY') { + $answer = '('.join(', ', @{ $answer }).')'; + } return ''. &HTML::Entities::encode($answer,'"<>&').''; } @@ -481,21 +545,26 @@ sub start_mathresponse { $safeeval); $Apache::inputtags::answertxt{$id}=[$answer]; } + } elsif ($target eq 'edit') { $result.=&Apache::edit::tag_start($target,$token); $result.=&Apache::edit::text_arg('String to display for answer:', - 'answerdisplay',$token); + 'answerdisplay',$token,'50'); $result.=&Apache::edit::select_arg('Algebra System:', 'cas', - ['maxima'], + ['maxima','R'], $token); $result.=&Apache::edit::text_arg('Argument Array:', - 'args',$token); + 'args',$token). + &Apache::loncommon::help_open_topic('Maxima_Argument_Array'); + $result.=&Apache::edit::text_arg('Libraries:', + 'libraries',$token). + &Apache::loncommon::help_open_topic('Maxima_Libraries'); $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,'answerdisplay','cas','args'); + $safeeval,'answerdisplay','cas','args','libraries'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); } @@ -507,6 +576,23 @@ sub start_mathresponse { return $result; } +sub edit_mathresponse_button { + my ($id,$field)=@_; + my $button=&mt('Edit Answer'); +# my $helplink=&Apache::loncommon::help_open_topic('Formula_Editor'); + my $iconpath=$Apache::lonnet::perlvar{'lonIconsURL'}; + return(< +function edit_${id}_${field} (textarea) { + thenumber = textarea; + thedata = document.forms['lonhomework'].elements[textarea].value; + newwin = window.open("/adm/dragmath/MaximaPopup.html","","width=565,height=400,resizable"); +} + +$button +ENDFORMULABUTTON +} + sub end_mathresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; @@ -527,12 +613,31 @@ sub end_mathresponse { my $cas = &Apache::lonxml::get_param('cas',$parstack,$safeeval); if ($cas eq 'maxima') { my $args = [&Apache::lonxml::get_param_var('args',$parstack,$safeeval)]; - $award=&Apache::lonmaxima::maxima_run($Apache::response::custom_answer[-1],$response,$args); + $award=&Apache::lonmaxima::maxima_run($Apache::response::custom_answer[-1],$response,$args, + &Apache::lonxml::get_param('libraries',$parstack,$safeeval)); } + if ($cas eq 'R') { + my $args = [&Apache::lonxml::get_param_var('args',$parstack,$safeeval)]; + $award=&Apache::lonr::r_run($Apache::response::custom_answer[-1],$response,$args, + &Apache::lonxml::get_param('libraries',$parstack,$safeeval)); + } + if (!&Apache::inputtags::valid_award($award)) { $error = $award; $award = 'ERROR'; } + if (($award eq 'INCORRECT' || $award eq 'APPROX_ANS' || + $award eq 'EXACT_ANS')) { + if ($Apache::lonhomework::type eq 'survey') { + $award='SUBMITTED'; + } elsif ($Apache::lonhomework::type eq 'surveycred') { + $award='SUBMITTED_CREDIT'; + } elsif ($Apache::lonhomework::type eq 'anonsurvey') { + $award='ANONYMOUS'; + } elsif ($Apache::lonhomework::type eq 'anonsurveycred') { + $award='ANONYMOUS_CREDIT'; + } + } &Apache::response::handle_previous(\%previous,$award); $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= $award; @@ -544,6 +649,12 @@ sub end_mathresponse { } if ($target eq 'web') { &setup_prior_tries_hash(\&format_prior_response_math); + my $partid = $Apache::inputtags::part; + my $id = $Apache::inputtags::response[-1]; + if (($Apache::inputtags::status['-1'] eq 'CAN_ANSWER') + && (&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffeditor') ne 'yes')) { + $result.=&edit_mathresponse_button($id,"HWVAL_$id"); + } } pop(@Apache::lonxml::namespace); @@ -569,15 +680,15 @@ sub implicit_multiplication { $expression=~s/(\d+)(?:x|\*)10(?:\^|\*\*)([\+\-]*\d+)/$1\&\($2\)/gsi; # Fill in multiplication signs # a b -> a*b;3 b -> 3*b;3 4 -> 3*4 - $expression=~s/(\w)\s+(\w)/$1\*$2/gs; + $expression=~s/([A-Za-z0-9])\s+(?=[A-Za-z0-9])/$1\*/gs; # )( -> )*(; ) ( -> )*( $expression=~s/\)\s*\(/\)\*\(/gs; # 3a -> 3*a; 3( -> 3*(; 3 ( -> 3*(; 3A -> 3*A $expression=~s/(\d)\s*([a-zA-Z\(])/$1\*$2/gs; # a ( -> a*( - $expression=~s/(\w)\s+\(/$1\*\(/gs; + $expression=~s/([A-Za-z0-9])\s+\(/$1\*\(/gs; # )a -> )*a; )3 -> )*3; ) 3 -> )*3 - $expression=~s/\)\s*(\w)/\)\*$1/gs; + $expression=~s/\)\s*([A-Za-z0-9])/\)\*$1/gs; # 3&8 -> 3e8; 3&-4 -> 3e-4 $expression=~s/(\d+)\&\(([\+\-]*\d+)\)/$1e$2/gs; return $expression; @@ -646,7 +757,7 @@ sub start_responseparam { } } if (defined($optionlist)) { - $result.='Use template:
'; } @@ -671,6 +782,7 @@ sub start_responseparam { $Apache::lonnet::packagetab{"$tag&$name&display"}; $token->[2]->{'default'}= $Apache::lonnet::packagetab{"$tag&$name&default"}; + $token->[3] = ['name','type','description','default']; $constructtag=1; } if ($constructtag) { @@ -751,8 +863,8 @@ sub answer_header { if ($Apache::lonhomework::type eq 'exam') { $bit = ($Apache::lonxml::counter+$increment).') '; } else { - $bit .= ' Answer for Part: \verb|'. - $Apache::inputtags::part.'| '; + $bit .= ' '.&mt('Answer for Part: [_1]', + '\verb|'.$Apache::inputtags::part.'|').' '; } push(@answer_bits,$bit); } else { @@ -795,9 +907,13 @@ sub answer_part { last; } } - if ($answer ne '') { - $answer = '\verb'.$to_use.$answer.$to_use; - } + my $fullanswer=$answer; + $answer=''; + foreach my $element (split(/[\;]/,$fullanswer)) { + if ($element ne '') { + $answer.= '\verb'.$to_use.$element.$to_use.' \newline'; + } + } } if ($answer ne '') { push(@answer_bits,$answer); @@ -816,12 +932,17 @@ sub answer_footer { my ($type) = @_; my $result; if ($env{'form.answer_output_mode'} eq 'tex') { - my $columns = scalar(@answer_bits); - $result = ' \vskip 0 mm \noindent \begin{tabular}{|'.'c|'x$columns.'}\hline '; - $result .= join(' & ',@answer_bits); - $result .= ' \\\\ \\hline \end{tabular} \vskip 0 mm '; + $result = ' \vskip 0 mm \noindent \begin{tabular}{|p{1.5cm}|p{6.8cm}|}\hline '; + $result .= $answer_bits[0].'&\vspace*{-4mm}\begin{itemize}'; + for (my $i=1;$i<=$#answer_bits;$i++) { + $result.='\item '.$answer_bits[$i].'\vspace*{-7mm}'; + } + $result .= ' \end{itemize} \\\\ \hline \end{tabular} \vskip 0 mm '; } else { - $result = ''; + if (!$need_row_start) { + $result .= ''; + } + $result .= ''; } return $result; } @@ -838,12 +959,16 @@ sub showallfoils { } } if ($Apache::lonhomework::type eq 'survey') { return 1; } + if ($Apache::lonhomework::type eq 'surveycred') { return 1; } + if ($Apache::lonhomework::type eq 'anonsurvey') { return 1; } + if ($Apache::lonhomework::type eq 'anonsurveycred') { return 1; } + return 0; } =pod -=item &getresponse($offset,$resulttype); +=item &getresponse(); Retreives the current submitted response, helps out in the case of scantron mode. @@ -865,6 +990,7 @@ Optional Arguments: $lines lines of bubbles. $bubbles_per_line - Must be provided if lines is defined.. number of bubbles on a line. + =cut sub getresponse { @@ -879,7 +1005,6 @@ sub getresponse { if (!defined($lines)) { $lines = 1; } - my %let_to_num=('A'=>0,'B'=>1,'C'=>2,'D'=>3,'E'=>4,'F'=>5,'G'=>6,'H'=>7, 'I'=>8,'J'=>9,'K'=>10,'L'=>11,'M'=>12,'N'=>13,'O'=>14, 'P'=>15,'Q'=>16,'R'=>17,'S'=>18,'T'=>19,'U'=>20,'V'=>21, @@ -889,32 +1014,38 @@ sub getresponse { my $id = $Apache::inputtags::response[-1]; my $line; + my $startline = $env{'form.scantron_questnum_start.'.$part.'.'.$id}; + if (!$startline) { + $startline = $Apache::lonxml::counter; + } for ($line = 0; $line < $lines; $line++) { - $response = $env{'scantron.'. - ($Apache::lonxml::counter+$offset-1+$line). - '.answer'}; - if ($response ne "") { + my $theline = $startline+$offset-1+$line; + $response = $env{"scantron.$theline.answer"}; + if ((defined($response)) && ($response ne "") && ($response ne " ")) { last; } - + } + + # save bubbled letter for later + $Apache::lonhomework::results{"resource.$part.$id.scantron"}.= + $response; if ($resulttype ne 'letter') { - if ($resulttype eq 'A is 1') { - $response = $let_to_num{$response}+1; - } else { - $response = $let_to_num{$response}; + $response = $let_to_num{$response}; + if ($resulttype eq 'A is 1') { + if ($response ne "") { + $response = $response+1; + } } if ($response ne "") { $response += $line * $bubbles_per_line; } } else { if ($response ne "") { + my $raw = $response; $response = chr(ord($response) + $line * $bubbles_per_line); } } - # save submitted response for later - $Apache::lonhomework::results{"resource.$part.$id.scantron"}.= - $response; } else { $response = $env{$formparm}; @@ -931,8 +1062,17 @@ sub getresponse { =item &repetition(); -Returns the number of lines that are required to encode the weight. -(Currently expects that there are 10 bubbles per line) +In scalar context: + +returns: the number of lines that are required to encode the weight. +(Default is for 10 bubbles per bubblesheet item; other (integer) +values can be specified by using a custom Bubblesheet format file +with an eighteenth entry (BubblesPerRow) set to the integer +appropriate for the bubblesheets which will be used to assign weights. + +In array context: + +returns: number of lines required to encode weight, and bubbles/line. =cut @@ -940,14 +1080,30 @@ sub repetition { my $id = $Apache::inputtags::part; my $weight = &Apache::lonnet::EXT("resource.$id.weight"); if (!defined($weight) || ($weight eq '')) { $weight=1; } - my $repetition = int($weight/10); - if ($weight % 10 != 0) { $repetition++; } + my $bubbles_per_row; + if (($env{'form.bubbles_per_row'} =~ /^\d+$/) && + ($env{'form.bubbles_per_row'} > 0)) { + $bubbles_per_row = $env{'form.bubbles_per_row'}; + } else { + $bubbles_per_row = 10; + } + my $denominator = $bubbles_per_row; + if (($env{'form.scantron_lastbubblepoints'} == 0) && + ($bubbles_per_row > 1)) { + $denominator = $bubbles_per_row - 1; + } + my $repetition = int($weight/$denominator); + if ($weight % $denominator != 0) { $repetition++; } + if (wantarray) { + return ($repetition,$bubbles_per_row); + } return $repetition; + } =pod -=item &scored_response($part_id,$response_id); +=item &scored_response(); Sets the results hash elements @@ -972,11 +1128,24 @@ Arguments sub scored_response { my ($part,$id)=@_; my $repetition=&repetition(); + my $bubbles_per_row; + if (($env{'form.bubbles_per_row'} =~ /^\d+$/) && + ($env{'form.bubbles_per_row'} > 0)) { + $bubbles_per_row = $env{'form.bubbles_per_row'}; + } else { + $bubbles_per_row = 10; + } my $score=0; for (my $i=0;$i<$repetition;$i++) { - # A is 1, B is 2, etc. (get response return 0-9 and then we add 1) + # A is 1, B is 2, etc. my $increase=&Apache::response::getresponse($i+1); - if ($increase ne '') { $score+=$increase+1; } + unless (($increase == $bubbles_per_row-1) && + ($env{'form.scantron_lastbubblepoints'} == 0)) { + # (get response return 0-9 and then we add 1) + if ($increase ne '') { + $score+=$increase+1; + } + } } my $weight = &Apache::lonnet::EXT("resource.$part.weight"); if (!defined($weight) || $weight eq '' || $weight eq 0) { $weight = 1; } @@ -988,10 +1157,13 @@ sub scored_response { } sub whichorder { - my ($max,$randomize,$showall,$hash)=@_; + my ($max,$randomize,$showall,$hash,$rndseed)=@_; #&Apache::lonxml::debug("man $max randomize $randomize"); - if (!defined(@{ $$hash{'names'} })) { return; } - my @names = @{ $$hash{'names'} }; + my @names; + if (ref($hash->{'names'}) eq 'ARRAY') { + @names = @{$hash->{'names'}}; + } + return if (!@names); my @whichopt =(); my (%top,@toplist,%bottom,@bottomlist); if (!($showall || ($randomize eq 'no'))) { @@ -1042,9 +1214,15 @@ sub show_answer { my $part = $Apache::inputtags::part; my $award = $Apache::lonhomework::history{"resource.$part.solved"}; my $status = $Apache::inputtags::status[-1]; - return ( ($award =~ /^correct/ - && lc($Apache::lonhomework::problemstatus) ne 'no') - || $status eq "SHOW_ANSWER"); + my $canshow = 0; + if ($award =~ /^correct/) { + if (($Apache::lonhomework::history{"resource.$part.awarded"} >= 1) || + (&Apache::lonnet::EXT("resource.$part.retrypartial") !~/^1|on|yes$/)) { + $canshow = 1; + } + } + return (($canshow && &Apache::lonhomework::show_problem_status()) + || $status eq "SHOW_ANSWER"); } sub analyze_store_foilgroup { @@ -1072,8 +1250,11 @@ sub check_if_computed { sub pick_foil_for_concept { my ($target,$attrs,$hinthash,$parstack,$safeeval)=@_; - if (not defined(@{ $Apache::response::conceptgroup{'names'} })) { return; } - my @names = @{ $Apache::response::conceptgroup{'names'} }; + my @names; + if (ref($Apache::response::conceptgroup{'names'}) eq 'ARRAY') { + @names = @{ $Apache::response::conceptgroup{'names'} }; + } + return if (!@names); my $pick=int(&Math::Random::random_uniform() * ($#names+1)); my $name=$names[$pick]; push @{ $Apache::response::foilgroup{'names'} }, $name; @@ -1104,17 +1285,20 @@ sub pick_foil_for_concept { $Apache::response::conceptgroup{'names'}; } -#------------------------------------------------------------ -# -# Get a parameter associated with a problem. -# Parameters: -# $id - the id of the paramater, either a part id, -# or a partid and responspe id joined by _ -# $name - Name of the parameter to fetch -# $default - Default value for the paramter. -# -# -# + +=pod + +=item get_response_param() + +Get a parameter associated with a problem. +Parameters: + $id - the id of the paramater, either a part id, + or a partid and responspe id joined by _ + $name - Name of the parameter to fetch + $default - Default value for the paramter. + +=cut + sub get_response_param { my ($id,$name,$default)=@_; my $parameter; @@ -1148,7 +1332,7 @@ sub submitted { } # Submit All button on a .page was pressed if (defined($env{'form.all_submit'})) { return 1; } - # otherwise no submission occured + # otherwise no submission occurred return 0; } @@ -1175,20 +1359,27 @@ sub add_to_gradingqueue { } } -# 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 +=pod + +=item check_status() + +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 + +=cut + sub check_status { my ($id)=@_; if (!defined($id)) { $id=$Apache::inputtags::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 $duedate=&Apache::lonhomework::due_date($id); my $answerdate=&Apache::lonnet::EXT("resource.$id.answerdate"); if ( $opendate && $curtime > $opendate && $duedate && $curtime > $duedate && @@ -1205,23 +1396,53 @@ sub check_status { return 2; } +=pod + +=item setup_prior_tries_hash() + + Foreach each past .submission $func is called with 3 arguments + - the mode to set things up for (currently always 'grade') + - the stored .submission string + - The expansion of $data + + $data is an array ref containing elements that are either + - scalars that are other elements of the history hash to pass to $func + - ref to data to be passed untouched to $func + + $questiontype is the questiontype (currently only passed in if + randomizebytry. + +=cut + sub setup_prior_tries_hash { - my ($func,$data) = @_; + my ($func,$data,$questiontype) = @_; my $part = $Apache::inputtags::part; - my $id = $Apache::inputtags::response[-1]; + my $id = $Apache::inputtags::response[-1]; foreach my $i (1..$Apache::lonhomework::history{'version'}) { - my $sub_key = "$i:resource.$part.$id.submission"; + my $partprefix = "$i:resource.$part"; + my $sub_key = "$partprefix.$id.submission"; next if (!exists($Apache::lonhomework::history{$sub_key})); + my $type_key = "$partprefix.type"; + my $type = $Apache::lonhomework::history{$type_key}; my @other_data; - foreach my $datum (@{ $data }) { - if (ref($datum)) { - push(@other_data,$datum); - } else { - my $info_key = "$i:resource.$part.$id.$datum"; - push(@other_data,$Apache::lonhomework::history{$info_key}); + if (ref($data) eq 'ARRAY') { + foreach my $datum (@{ $data }) { + if (ref($datum)) { + push(@other_data,$datum); + } else { + my $info_key = "$i:resource.$part.$id.$datum"; + push(@other_data,$Apache::lonhomework::history{$info_key}); + } } - } - + } + if ($questiontype eq 'randomizetry') { + my $order_key = "$partprefix.$id.foilorder"; + my @whichopts = &Apache::lonnet::str2array($Apache::lonhomework::history{$order_key}); + if (@whichopts > 0) { + shift(@other_data); + unshift(@other_data,\@whichopts); + } + } my $output = &$func('grade', $Apache::lonhomework::history{$sub_key}, @@ -1235,3 +1456,6 @@ sub setup_prior_tries_hash { 1; __END__ +=pod + +=cut