File:  [LON-CAPA] / loncom / homework / caparesponse / caparesponse.pm
Revision 1.232: download - view: text, annotated - select for diffs
Fri Sep 12 09:56:10 2008 UTC (15 years, 7 months ago) by raeburn
Branches: MAIN
CVS tags: HEAD
- Bug 5531 (although should really be a separate bug).
RegExp used to separate units from numerical part of an answer can truncate responses to stringresponse items for which the type has not been explicitly set (as ci, cs, mc or re).

- Include the tagname of the response item in calls to caparesponse_check_list(), so that if the type attribute is unspecified, stringresponse submissions are not subjected to the unit extractor.

Perhaps there is a reason why this ambiguity has not been eliminated previously by passing the tagname to caparesponse_check_list() - run in the safe space?
Testing needed.

# The LearningOnline Network with CAPA
# caparesponse definition
#
# $Id: caparesponse.pm,v 1.232 2008/09/12 09:56:10 raeburn 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);

BEGIN {
    &Apache::lonxml::register('Apache::caparesponse',('numericalresponse','stringresponse','formularesponse'));
}

my %answer;
my @answers;
sub get_answer { return %answer; };
sub push_answer{ push(@answers,dclone(\%answer)); undef(%answer) }
sub pop_answer { %answer = %{pop(@answers)}; };

my $cur_name;
my $tag_internal_answer_name = 'INTERNAL';

sub start_answer {
    my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
    my $result;
    $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 '
        <answer>
            <value></value>
        </answer>';
}

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 '
    <answergroup>
        <answer>
            <value></value>
        </answer>
    </answergroup>';
}

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 '
            <value></value>';
}

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 '
            <value></value>';
}

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)=@_;
    &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 (($token->[1] eq 'formularesponse') && 
            ($Apache::inputtags::status['-1'] eq 'CAN_ANSWER')) {
        }
	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)
    }
	
    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) = @_;   

    if (ref($response)) {
	$$args_ref{'response'}=dclone($response);
    } else {
	$$args_ref{'response'}=dclone([$response]);
    }
}

sub check_submission {
    my ($response,$partid,$id,$tag,$parstack,$safeeval,$ignore_sig)=@_;
    my @args = ('type','tol','sig','format','unit','calc','samples');
    my $args_ref = &setup_capa_args($safeeval,$parstack,\@args,$response);

    my $hideunit=
	&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit');
        #no way to enter units, with radio buttons
    if ($Apache::lonhomework::type eq 'exam' ||
	lc($hideunit) eq "yes") {
	delete($$args_ref{'unit'});
    }
    #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';
    }
    
    &add_in_tag_answer($parstack,$safeeval);

    if (!%answer) {
	&Apache::lonxml::error("No answers are defined");
    }

    my (@final_awards,@final_msgs,@names);
    foreach my $name (keys(%answer)) {
	&Apache::lonxml::debug(" doing $name with ".join(':',@{ $answer{$name}{'answers'} }));
	
	${$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=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($tag)",$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 && $answer[0] =~ /\S/) {
	$answer{$tag_internal_answer_name}= {'type' => 'ordered',
					     'answers' => [\@answer] };
    }
}

sub capa_formula_fix {
   my ($expression)=@_;
   return &Apache::response::implicit_multiplication($expression);
}

sub end_numericalresponse {
    my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;

    &Apache::lonxml::deregister('Apache::caparesponse',
			      ('answer','answergroup','value','array','unit',
			       'vector'));
    pop(@Apache::lonxml::namespace);

    my $increment=1;
    my $result = '';
    if (!$Apache::lonxml::default_homework_loaded) {
	&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 {
	    my $response = &Apache::response::getresponse();
	    if ( $response =~ /[^\s]/) {
		my %previous = &Apache::response::check_for_previous($response,$partid,$id);
		&Apache::lonxml::debug("submitted a $response<br>\n");
		&Apache::lonxml::debug($$parstack[-1] . "\n<br>");
		
		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<br>result:$result:$Apache::lonxml::curdepth<br>\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.')<br /><br />';}
		    $result.= '<table border="1"><tr>';
		    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.='<td><input type="radio" name="HWVAL_'.$id.
			    '" value="'.$bubble_values->[$ind].'" '.$checked
			    .' /><b>'.$alphabet[$ind].'</b>: '.
			    $bubble_display->[$ind].'</td>';
		    }
		    $result.='</tr></table>';
		}
	    } 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();
		}
	    }
	}
        if (($target eq 'web') && ($tag eq 'formularesponse')
            && ($Apache::lonhomework::type ne 'exam') && ($Apache::inputtags::status['-1'] eq 'CAN_ANSWER')
	    && (&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoneditor') ne 'no')){	   
           $result.=&Apache::response::edit_mathresponse_button($id,"HWVAL_$id");
#hier
        }
            
	&Apache::response::setup_prior_tries_hash(\&format_prior_response_numerical);
    } elsif ($target eq 'edit') {
	$result.='</td></tr>'.&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);
	    }
	}
	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 <i>$siglow - $sighigh</i>";
				$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: <b>$unit</b>");
		    }
		} 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') {
        if (($tag eq 'formularesponse') && ($target eq 'analyze')) {
            my $type = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.type');
            if ($type eq 'exam') {
                $increment = &Apache::response::repetition();
            }
        }
	&Apache::lonxml::increment_counter($increment,"$partid.$id");
	if ($target eq 'analyze') {
	    &Apache::lonhomework::set_bubble_lines();
	}
    }
    &Apache::response::end_response();
    return $result;
}

sub format_prior_response_numerical {
    my ($mode,$answer) = @_;
    if (ref($answer)) {
	my $result = '<table class="LC_prior_numerical"><tr>';
	foreach my $element (@{ $answer }) {
	    $result.= '<td><span class="LC_prior_numerical">'.
		&HTML::Entities::encode($element,'"<>&').'</span></td>';
	}
	$result.='</tr></table>';
	return $result;
    }
    return '<span class="LC_prior_numerical">'.
	    &HTML::Entities::encode($answer,'"<>&').'</span>';

}

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.",
		'<tt>'.join(', ',@{$counts{$count}}).'</tt>',
		$count);
	} (sort(keys(%counts))));
	&Apache::lonxml::error(&mt("All answers must have the same number of components. Varying numbers of answers were seen. ").$counts);
    }
    my $expected_number_of_inputs = (keys(%counts))[0];
    if ( $expected_number_of_inputs > 0 
	 && $expected_number_of_inputs != scalar(@Apache::inputtags::inputlist)) {
	&Apache::lonxml::error(&mt("Expected [_1] input fields, but there were only [_2] seen.", 
				   $expected_number_of_inputs,
				   scalar(@Apache::inputtags::inputlist)));
    }
}

sub get_table_sizes {
    my ($number_of_bubbles,$rbubble_values)=@_;
    my $scale=2; #mm for one digit
    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 {
	    $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;
    }
    if ($bubbles_per_line < 1) {
	$bubbles_per_line=1;
    }
    my $number_of_tables = int($number_of_bubbles/$bubbles_per_line);
    my @table_range = ();
    for (my $i=0;$i<$number_of_tables;$i++) {push @table_range,$bubbles_per_line;}
    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) =@_;

    if (!%answer) {
	&Apache::lonxml::error(&mt("No answers defined for response [_1] in part [_2] to make bubbles for.",$id,$part));
	return ([],[],undef);
    }
    
    my $number_of_bubbles = 
	&Apache::response::get_response_param($part.'_'.$id,'numbubbles',8);

    my ($format)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval);
    my $name = (exists($answer{$tag_internal_answer_name}) 
		? $tag_internal_answer_name
		: (sort(keys(%answer)))[0]);

    if ( scalar(@{$answer{$name}{'answers'}}) > 1) {
	&Apache::lonxml::error("Only answers with 1 component are supported in exam mode");
    }
    if (scalar(@{$answer{$name}{'answers'}[0]}) > 1) {
	&Apache::lonxml::error("Vector answers are unsupported in exam mode.");
    }

    my $answer = $answer{$name}{'answers'}[0][0];
    my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,
						   $safeeval);
    if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); }
    
    my @bubble_values=();
    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;
    my $answerfactor=$answer;
    if ($answer==0) { 
       $answerfactor=&Math::Random::random_uniform_integer(1,1,100)/
                     &Math::Random::random_uniform_integer(1,1,10);
    }
    for ($ind=0;$ind<$number_of_bubbles;$ind++) {
	$bubble_values[$ind] = $answerfactor*($factor**($power-$powers[$#powers-$ind]));
	$bubble_display[$ind] = &format_number($bubble_values[$ind],
					       $format,$target,$safeeval);
    }
    my $correct = $alphabet[$number_of_bubbles-$power];
    if ($answer==0) {
       $correct='A';
       $bubble_values[0]=0;
       $bubble_display[0] = &format_number($bubble_values[0],
                                           $format,$target,$safeeval);
    }
    &Math::Random::random_set_seed(@oldseed);
    return (\@bubble_values,\@bubble_display,$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 ($env{'request.state'} ne 'construct'
	&& 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
	}
	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 format_prior_response_string {
    my ($mode,$answer) =@_;
    return '<span class="LC_prior_string">'.
	    &HTML::Entities::encode($answer,'"<>&').'</span>';
}

sub start_stringresponse {
    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 {
    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<br>\n");
		&Apache::lonxml::debug($$parstack[-1] . "\n<br>");
		$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($$tagstack[-1])",$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<br>result:$result:$Apache::lonxml::curdepth<br>\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',
							"<b>$string</b>");
	    }
	} 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.='</td></tr>'.&Apache::edit::end_table;
    } elsif ($target eq 'web' || $target eq 'tex') {
	&Apache::response::setup_prior_tries_hash(\&format_prior_response_string);
    }
    if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' || 
	$target eq 'tex' || $target eq 'analyze') {
	&Apache::lonxml::increment_counter(&Apache::response::repetition(),
					   "$part.$id");
	if ($target eq 'analyze') {
	    &Apache::lonhomework::set_bubble_lines();
	}
    }
    &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__


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>