# The LearningOnline Network with CAPA # various response type definitons response definition # # $Id: response.pm,v 1.129 2005/11/15 15:57:45 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::response; use strict; use Apache::lonlocal; use Apache::lonnet; BEGIN { &Apache::lonxml::register('Apache::response',('responseparam','parameter','dataresponse','customresponse')); } sub start_response { my ($parstack,$safeeval)=@_; my $id= &Apache::lonxml::get_param('id',$parstack,$safeeval); if ($id eq '') { $id = $Apache::lonxml::curdepth; } if ($#Apache::inputtags::import > -1) { &Apache::lonxml::debug("Turning :$id: into"); $id = join('_',@Apache::inputtags::import).'_'.$id; &Apache::lonxml::debug("New :$id:"); } 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; } sub end_response { #pop @Apache::inputtags::response; @Apache::inputtags::inputlist=(); return ''; } sub start_hintresponse { my ($parstack,$safeeval)=@_; my $id= &Apache::lonxml::get_param('id',$parstack,$safeeval); if ($id eq '') { $id = $Apache::lonxml::curdepth; } push (@Apache::inputtags::hint,$id); push (@Apache::inputtags::hintlist,$id); push (@Apache::inputtags::paramstack,[%Apache::inputtags::params]); return $id; } sub end_hintresponse { pop @Apache::inputtags::hint; if (defined($Apache::inputtags::paramstack[-1])) { %Apache::inputtags::params= @{ pop(@Apache::inputtags::paramstack) }; } return ''; } 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 { 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 ($ignore_id2) = @_; my $rndseed; $rndseed=&Apache::structuretags::setup_rndseed(); if (!defined($rndseed)) { $rndseed=&Apache::lonnet::rndseed(); } &Apache::lonxml::debug("randseed $rndseed"); # $rndseed=unpack("%32i",$rndseed); my $rand_alg=&Apache::lonnet::get_rand_alg(); my ($rndmod,$rndmod2); my ($id1,$id2,$shift_amt); if ($Apache::lonhomework::parsing_a_problem) { $id1=$Apache::inputtags::part; if (defined($Apache::inputtags::response[-1])) { $id2=$Apache::inputtags::response[-1]; } $shift_amt=scalar(@Apache::inputtags::responselist); } elsif ($Apache::lonhomework::parsing_a_task) { $id1=$Apache::bridgetask::dimension; if (!$ignore_id2 && defined($Apache::bridgetask::instance[-1])) { $id2=$Apache::bridgetask::instance[-1]; } $shift_amt=scalar(@Apache::bridgetask::instance); } &Apache::lonxml::debug("id1: $id1, id2: $id2, shift_amt: $shift_amt"); if (!$rand_alg || $rand_alg eq '32bit' || $rand_alg eq '64bit' || $rand_alg eq '64bit2') { $rndmod=(&Apache::lonnet::numval($id1) << 10); if (defined($id2)) { $rndmod+=&Apache::lonnet::numval($id2); } } elsif ($rand_alg eq '64bit3') { $rndmod=(&Apache::lonnet::numval2($id1) << 10); if (defined($id2)) { $rndmod+=&Apache::lonnet::numval2($id2); } } elsif ($rand_alg eq '64bit4') { my $shift=(4*$shift_amt)%30; $rndmod=(&Apache::lonnet::numval3($id1) << (($shift+15)%30)); if (defined($id2)) { $rndmod+=(&Apache::lonnet::numval3($id2) << $shift ); } } else { ($rndmod,$rndmod2)=&Apache::lonnet::digest("$id1,$id2"); } if ($rndseed =~/([,:])/) { my $char=$1; use integer; my ($num1,$num2)=split(/\Q$char\E/,$rndseed); $num1+=$rndmod; $num2+= ((defined($rndmod2)) ? $rndmod2 : $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); return ''; } sub meta_parameter_write { my ($name,$type,$default,$display)=@_; my $partref=$Apache::inputtags::part; my $result='' ."\n"; return $result; } sub meta_package_write { my $name=shift; my $result = ''."\n"; return $result; } sub meta_stores_write { my ($name,$type,$display)=@_; my $partref=$Apache::inputtags::part; my $result = '\n"; } 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 # } sub meta_part_order { if (@Apache::inputtags::partlist) { my @parts=@Apache::inputtags::partlist; shift(@parts); return ''.join(',',@parts).''."\n"; } else { return '0'."\n"; } } sub meta_response_order { if (@Apache::inputtags::responselist) { return ''.join(',',@Apache::inputtags::responselist). ''."\n"; } } sub check_for_previous { my ($curresponse,$partid,$id) = @_; my %previous; $previous{'used'} = 0; foreach my $key (sort(keys(%Apache::lonhomework::history))) { if ($key =~ /resource\.$partid\.$id\.submission$/) { &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; $previous{'award'} = $Apache::lonhomework::history{"$history:resource.$partid.$id.awarddetail"}; $previous{'last'}='0'; push(@{ $previous{'version'} },$history); } else { $previous{'award'} = $Apache::lonhomework::history{"resource.$partid.$id.awarddetail"}; $previous{'last'}='1'; } if (! $previous{'award'} ) { $previous{'award'} = 'UNKNOWN'; } &Apache::lonxml::debug("got a match :$previous{'award'}:$previous{'used'}:"); } } } &Apache::lonhomework::showhash(%previous); return %previous; } sub handle_previous { my ($previous,$ad)=@_; if ($$previous{'used'} && ($$previous{'award'} eq $ad) ) { if ($$previous{'last'}) { push(@Apache::inputtags::previous,'PREVIOUSLY_LAST'); 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'}); } } } sub view_or_modify { my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); my $myself=0; if ( ($name eq $env{'user.name'}) && ($domain eq $env{'user.domain'}) ) { $myself=1; } my $vgr=&Apache::lonnet::allowed('vgr',$courseid); my $mgr=&Apache::lonnet::allowed('vgr',$courseid); if ($mgr) { return "M"; } if ($vgr) { return "V"; } if ($myself) { return "V"; } return ''; } sub start_dataresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $id = &Apache::response::start_response($parstack,$safeeval); my $result; if ($target eq 'web') { $result = $token->[2]->{'display'}.':'; } elsif ($target eq 'meta') { $result = &Apache::response::meta_stores_write($token->[2]->{'name'}, $token->[2]->{'type'}, $token->[2]->{'display'}); $result .= &Apache::response::meta_package_write('dataresponse'); } return $result; } sub end_dataresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; if ( $target eq 'web' ) { } elsif ($target eq 'grade' ) { if ( defined $env{'form.submitted'}) { my ($symb,$courseid,$domain,$name)=&Apache::lonxml::whichuser(); my $allowed=&Apache::lonnet::allowed('mgr',$courseid); if ($allowed) { &Apache::response::setup_params('dataresponse',$safeeval); my $partid = $Apache::inputtags::part; my $id = $Apache::inputtags::response['-1']; my $response = $env{'form.HWVAL_'.$id}; my $name = &Apache::lonxml::get_param('name',$parstack,$safeeval); if ( $response =~ /[^\s]/) { $Apache::lonhomework::results{"resource.$partid.$id.$name"}=$response; $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response; $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}='SUBMITTED'; } } else { $result='Not Permitted to change values.' } } } &Apache::response::end_response; return $result; } sub start_customresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $id = &Apache::response::start_response($parstack,$safeeval); push(@Apache::lonxml::namespace,'customresponse'); my $result; undef($Apache::response::custom_answer); &Apache::lonxml::register('Apache::response',('answer')); if ($target eq 'web') { if ( &Apache::response::show_answer() ) { my $answer = &Apache::lonxml::get_param('answerdisplay',$parstack, $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); $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'); if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); $result.=&Apache::edit::handle_insert(); } } elsif ($target eq 'answer' || $target eq 'grade') { &Apache::response::reset_params(); } elsif ($target eq 'meta') { $result .= &Apache::response::meta_package_write('customresponse'); } return $result; } sub end_customresponse { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; my $part=$Apache::inputtags::part; my $id=$Apache::inputtags::response[-1]; if ( $target eq 'grade' && &Apache::response::submitted() ) { my $response = &Apache::response::getresponse(); if ( $response =~ /[^\s]/ && $Apache::response::custom_answer_type eq 'loncapa/perl') { if (!$Apache::lonxml::default_homework_loaded) { &Apache::lonxml::default_homework_load($safeeval); } my %previous = &Apache::response::check_for_previous($response, $part,$id); $Apache::lonhomework::results{"resource.$part.$id.submission"}= $response; my $error; ${$safeeval->varglob('LONCAPA::customresponse_submission')}= $response; my $award = &Apache::run::run('{ my $submission=$LONCAPA::customresponse_submission;'.$Apache::response::custom_answer.'}',$safeeval); if (!&Apache::inputtags::valid_award($award)) { $error = $award; $award = 'ERROR'; } &Apache::response::handle_previous(\%previous,$award); $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= $award; if ($error) { $Apache::lonhomework::results{"resource.$part.$id.awardmsg"}= $error; } } } pop(@Apache::lonxml::namespace); &Apache::lonxml::deregister('Apache::response',('answer')); &Apache::response::end_response(); return $result; } sub start_answer { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result; $Apache::response::custom_answer= &Apache::lonxml::get_all_text_unbalanced("/answer",$parser); $Apache::response::custom_answer_type= lc(&Apache::lonxml::get_param('type',$parstack,$safeeval)); $Apache::response::custom_answer_type =~ s/\s+//g; if ($target eq "edit" ) { $result=&Apache::edit::tag_start($target,$token,'Answer algorithm'); $result.=&Apache::edit::editfield($token->[1], $Apache::response::custom_answer, '',80,4); } elsif ( $target eq "modified" ) { $result=$token->[4].&Apache::edit::modifiedfield('/answer',$parser); } return $result; } sub end_answer { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; if ($target eq 'edit' ) { return &Apache::edit::end_table(); } } sub decide_package { my ($tagstack)=@_; my $package; if ($$tagstack[-1] eq 'parameter') { $package='part'; } else { my $i=-1; while (defined($$tagstack[$i])) { if ($$tagstack[$i] =~ /(response|hint)$/) { $package=$$tagstack[$i]; last; } $i--; } } return $package; } sub start_responseparam { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; my $result=''; if ($target eq 'meta') { $result = &meta_parameter_write($token->[2]->{'name'}, $token->[2]->{'type'}, $token->[2]->{'default'}, $token->[2]->{'description'}); } elsif ($target eq 'edit') { $result.=&Apache::edit::tag_start($target,$token); my $optionlist; my $package=&decide_package($tagstack); foreach my $key (sort(keys(%Apache::lonnet::packagetab))) { if ($key =~ /^\Q$package\E&(.*)&display$/) { $optionlist.=''; } } if (defined($optionlist)) { $result.='Use template:
'; } $result.=&Apache::edit::text_arg('Name:','name',$token). &Apache::edit::text_arg('Type:','type',$token). &Apache::edit::text_arg('Description:','description',$token). &Apache::edit::text_arg('Default:','default',$token). ""; $result.=&Apache::edit::end_table; } elsif ($target eq 'modified') { my $constructtag=&Apache::edit::get_new_args($token,$parstack, $safeeval,'name','type', 'description','default'); my $element=&Apache::edit::html_element_name('parameter_package'); if (defined($env{"form.$element"}) && $env{"form.$element"} ne '') { my $name=$env{"form.$element"}; my $tag=&decide_package($tagstack); $token->[2]->{'name'}=$name; $token->[2]->{'type'}= $Apache::lonnet::packagetab{"$tag&$name&type"}; $token->[2]->{'description'}= $Apache::lonnet::packagetab{"$tag&$name&display"}; $token->[2]->{'default'}= $Apache::lonnet::packagetab{"$tag&$name&default"}; $constructtag=1; } if ($constructtag) { $result = &Apache::edit::rebuild_tag($token); $result.=&Apache::edit::handle_insert(); } } elsif ($target eq 'grade' || $target eq 'answer' || $target eq 'web' || $target eq 'tex' || $target eq 'analyze' ) { if ($env{'request.state'} eq 'construct') { my $name =&Apache::lonxml::get_param('name',$parstack,$safeeval); my $default=&Apache::lonxml::get_param('default',$parstack, $safeeval); if ($name) {$Apache::inputtags::params{$name}=$default;} } } return $result; } sub end_responseparam { my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_; if ($target eq 'edit') { return ('','no'); } return ''; } sub start_parameter { return &start_responseparam(@_); } sub end_parameter { return &end_responseparam(@_); } sub reset_params { %Apache::inputtags::params=(); } sub setup_params { my ($tag,$safeeval) = @_; if ($env{'request.state'} eq 'construct') { return; } my %paramlist=(); foreach my $key (keys(%Apache::lonnet::packagetab)) { if ($key =~ /^$tag/) { my ($package,$name) = split(/&/,$key); $paramlist{$name}=1; } } foreach my $key (keys(%paramlist)) { my $entry= 'resource.'.$Apache::inputtags::part; if (defined($Apache::inputtags::response[-1])) { $entry.='_'.$Apache::inputtags::response[-1]; } $entry.='.'.$key; &Apache::lonxml::debug("looking for $entry"); my $value = &Apache::lonnet::EXT("$entry"); &Apache::lonxml::debug("$key has value :$value:"); if ($value eq 'con_lost' || $value =~ /^error:/) { &Apache::lonxml::debug("using nothing"); $Apache::inputtags::params{$key}=''; } else { 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; } } } sub answer_header { my ($type) = @_; my $result; if ($env{'form.answer_output_mode'} eq 'tex') { $result = ' \vskip 0 mm \begin{tabular}{|c|}\hline Answer for Part: \verb|'. $Apache::inputtags::part.'| \\\\ \hline '; } else { $result = ''."\n"; } return $result; } sub answer_part { my ($type,$answer) = @_; my $result; if ($env{'form.answer_output_mode'} eq 'tex') { my $to_use='|'; foreach my $value (32..126) { my $char=pack('c',$value); if ($answer !~ /\Q$char\E/) { $to_use=$char; last; } } $result = '\verb'.$to_use.$answer.$to_use.'\\\\ \hline '; } else { $result = ''; } return $result; } sub answer_footer { my ($type) = @_; my $result; if ($env{'form.answer_output_mode'} eq 'tex') { $result = ' \end{tabular} \vskip 0 mm '; } else { $result = '
Answer for Part:'. $Apache::inputtags::part. ''.$answer.'
'; } return $result; } sub showallfoils { 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; } } if ($Apache::lonhomework::type eq 'survey') { return 1; } return 0; } sub getresponse { my ($temp,$resulttype)=@_; my $formparm='form.HWVAL_'.$Apache::inputtags::response['-1']; my $response; if (!defined($temp)) { $temp=1; } else { $formparm.=":$temp"; } 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, 'W'=>22,'X'=>23,'Y'=>24,'Z'=>25); if ($env{'form.submitted'} eq 'scantron') { my $part = $Apache::inputtags::part; my $id = $Apache::inputtags::response[-1]; $response = $env{'scantron.'.($Apache::lonxml::counter+$temp-1). '.answer'}; # 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}; } } } else { $response = $env{$formparm}; } return $response; } 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++; } return $repetition; } sub scored_response { my ($part,$id)=@_; my $repetition=&repetition(); 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) my $increase=&Apache::response::getresponse($i+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; } my $pcr=$score/$weight; $Apache::lonhomework::results{"resource.$part.$id.awarded"}=$pcr; $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}= 'ASSIGNED_SCORE'; return $repetition; } sub whichorder { my ($max,$randomize,$showall,$hash)=@_; #&Apache::lonxml::debug("man $max randomize $randomize"); if (!defined(@{ $$hash{'names'} })) { return; } my @names = @{ $$hash{'names'} }; my @whichopt =(); my (%top,@toplist,%bottom,@bottomlist); if (!($showall || ($randomize eq 'no'))) { my $current=0; foreach my $name (@names) { $current++; if ($$hash{"$name.location"} eq 'top') { $top{$name}=$current; } elsif ($$hash{"$name.location"} eq 'bottom') { $bottom{$name}=$current; } } } my $topcount=0; my $bottomcount=0; while (((scalar(@whichopt)+$topcount+$bottomcount) < $max || $showall) && ($#names > -1)) { #&Apache::lonxml::debug("Have $#whichopt max is $max"); my $aopt; if ($showall || ($randomize eq 'no')) { $aopt=0; } else { $aopt=int(&Math::Random::random_uniform() * ($#names+1)); } #&Apache::lonxml::debug("From $#whichopt $max $#names elms, picking $aopt"); $aopt=splice(@names,$aopt,1); #&Apache::lonxml::debug("Picked $aopt"); if ($top{$aopt}) { $toplist[$top{$aopt}]=$aopt; $topcount++; } elsif ($bottom{$aopt}) { $bottomlist[$bottom{$aopt}]=$aopt; $bottomcount++; } else { push (@whichopt,$aopt); } } for (my $i=0;$i<=$#toplist;$i++) { if ($toplist[$i]) { unshift(@whichopt,$toplist[$i]) } } for (my $i=0;$i<=$#bottomlist;$i++) { if ($bottomlist[$i]) { push(@whichopt,$bottomlist[$i]) } } return @whichopt; } 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"); } sub analyze_store_foilgroup { my ($shown,$attrs)=@_; my $part_id="$Apache::inputtags::part.$Apache::inputtags::response[-1]"; foreach my $name (@{ $Apache::response::foilgroup{'names'} }) { if (defined($Apache::lonhomework::analyze{"$part_id.foil.value.$name"})) { next; } push (@{ $Apache::lonhomework::analyze{"$part_id.foils"} },$name); foreach my $attr (@$attrs) { $Apache::lonhomework::analyze{"$part_id.foil.".$attr.".$name"} = $Apache::response::foilgroup{"$name.".$attr}; } } 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; } my @names = @{ $Apache::response::conceptgroup{'names'} }; my $pick=int(&Math::Random::random_uniform() * ($#names+1)); my $name=$names[$pick]; push @{ $Apache::response::foilgroup{'names'} }, $name; foreach my $attr (@$attrs) { $Apache::response::foilgroup{"$name.".$attr} = $Apache::response::conceptgroup{"$name.".$attr}; } my $concept = &Apache::lonxml::get_param('concept',$parstack,$safeeval); $Apache::response::foilgroup{"$name.concept"} = $concept; &Apache::lonxml::debug("Selecting $name in $concept"); my $part_id="$Apache::inputtags::part.$Apache::inputtags::response[-1]"; if ($target eq 'analyze') { push (@{ $Apache::lonhomework::analyze{"$part_id.concepts"} }, $concept); $Apache::lonhomework::analyze{"$part_id.concept.$concept"}= $Apache::response::conceptgroup{'names'}; foreach my $name (@{ $Apache::response::conceptgroup{'names'} }) { push (@{ $Apache::lonhomework::analyze{"$part_id.foils"} }, $name); foreach my $attr (@$attrs) { $Apache::lonhomework::analyze{"$part_id.foil.$attr.$name"}= $Apache::response::conceptgroup{"$name.$attr"}; } } } push(@{ $hinthash->{"$part_id.concepts"} },$concept); $hinthash->{"$part_id.concept.$concept"}= $Apache::response::conceptgroup{'names'}; } 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; } # Submit All button on a .page was pressed if (defined($env{'form.all_submit'})) { 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__