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, 9 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.
1: # The LearningOnline Network with CAPA
2: # caparesponse definition
3: #
4: # $Id: caparesponse.pm,v 1.232 2008/09/12 09:56:10 raeburn Exp $
5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: #
10: # LON-CAPA is free software; you can redistribute it and/or modify
11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
14: #
15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
27: #
28:
29: package Apache::caparesponse;
30: use strict;
31: use capa;
32: use Safe::Hole;
33: use Apache::lonmaxima();
34: use Apache::lonlocal;
35: use Apache::lonnet;
36: use Apache::response();
37: use Storable qw(dclone);
38:
39: BEGIN {
40: &Apache::lonxml::register('Apache::caparesponse',('numericalresponse','stringresponse','formularesponse'));
41: }
42:
43: my %answer;
44: my @answers;
45: sub get_answer { return %answer; };
46: sub push_answer{ push(@answers,dclone(\%answer)); undef(%answer) }
47: sub pop_answer { %answer = %{pop(@answers)}; };
48:
49: my $cur_name;
50: my $tag_internal_answer_name = 'INTERNAL';
51:
52: sub start_answer {
53: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
54: my $result;
55: $cur_name = &Apache::lonxml::get_param('name',$parstack,$safeeval);
56: if ($cur_name =~ /^\s*$/) { $cur_name = $Apache::lonxml::curdepth; }
57: my $type = &Apache::lonxml::get_param('type',$parstack,$safeeval);
58: if (!defined($type) && $tagstack->[-2] eq 'answergroup') {
59: $type = &Apache::lonxml::get_param('type',$parstack,$safeeval,-2);
60: }
61: if (!defined($type)) { $type = 'ordered' };
62: $answer{$cur_name}= { 'type' => $type,
63: 'answers' => [] };
64: if ($target eq 'edit') {
65: $result.=&Apache::edit::tag_start($target,$token);
66: $result.=&Apache::edit::text_arg('Name:','name',$token);
67: $result.=&Apache::edit::select_arg('Type:','type',
68: [['ordered', 'Ordered' ],
69: ['unordered','Unordered'],],
70: $token);
71: $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
72: } elsif ($target eq 'modified') {
73: my $constructtag = &Apache::edit::get_new_args($token,$parstack,
74: $safeeval,'name',
75: 'type');
76: if ($constructtag) {
77: $result = &Apache::edit::rebuild_tag($token);
78: $result.= &Apache::edit::handle_insert();
79: }
80: }
81: return $result;
82: }
83:
84: sub end_answer {
85: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
86: my $result;
87: if ($target eq 'edit') {
88: $result .= &Apache::edit::tag_end();
89: }
90:
91: undef($cur_name);
92: return $result;
93: }
94:
95: sub insert_answer {
96: return '
97: <answer>
98: <value></value>
99: </answer>';
100: }
101:
102: sub start_answergroup {
103: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
104: my $result;
105: if ($target eq 'edit') {
106: $result.=&Apache::edit::tag_start($target,$token);
107: $result.=&Apache::edit::select_arg('Type:','type',
108: [['ordered', 'Ordered' ],
109: ['unordered','Unordered'],],
110: $token);
111: $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
112: } elsif ($target eq 'modified') {
113: my $constructtag = &Apache::edit::get_new_args($token,$parstack,
114: $safeeval,'name',
115: 'type');
116: if ($constructtag) {
117: $result = &Apache::edit::rebuild_tag($token);
118: $result.= &Apache::edit::handle_insert();
119: }
120: }
121: return $result;
122: }
123:
124: sub end_answergroup {
125: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
126: my $result;
127: if ($target eq 'web') {
128: if ( &Apache::response::show_answer() ) {
129: my $partid = $Apache::inputtags::part;
130: my $id = $Apache::inputtags::response[-1];
131: &set_answertext($Apache::lonhomework::history{"resource.$partid.$id.answername"},
132: $target,$token,$tagstack,$parstack,$parser,
133: $safeeval,-2);
134: }
135: } elsif ($target eq 'edit') {
136: $result .= &Apache::edit::tag_end();
137: }
138: return $result;
139: }
140:
141: sub insert_answergroup {
142: return '
143: <answergroup>
144: <answer>
145: <value></value>
146: </answer>
147: </answergroup>';
148: }
149:
150: sub start_value {
151: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
152: my $result;
153: if ( $target eq 'web' || $target eq 'tex' ||
154: $target eq 'grade' || $target eq 'webgrade' ||
155: $target eq 'answer' || $target eq 'analyze' ) {
156: my $bodytext = &Apache::lonxml::get_all_text("/value",$parser,$style);
157: $bodytext = &Apache::run::evaluate($bodytext,$safeeval,
158: $$parstack[-1]);
159:
160: push(@{ $answer{$cur_name}{'answers'} },[$bodytext]);
161:
162: } elsif ($target eq 'edit') {
163: $result.=&Apache::edit::tag_start($target,$token);
164: my $bodytext = &Apache::lonxml::get_all_text("/value",$parser,$style);
165: $result.=&Apache::edit::editline($token->[1],$bodytext,undef,40).
166: &Apache::edit::end_row();
167: } elsif ($target eq 'modified') {
168: $result=$token->[4].&Apache::edit::modifiedfield('/value',$parser);
169: }
170: return $result;
171: }
172:
173: sub end_value {
174: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
175: my $result;
176: if ($target eq 'edit') {
177: $result = &Apache::edit::end_table();
178: }
179: return $result;
180: }
181:
182: sub insert_value {
183: return '
184: <value></value>';
185: }
186:
187: sub start_vector {
188: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
189: my $result;
190: if ( $target eq 'web' || $target eq 'tex' ||
191: $target eq 'grade' || $target eq 'webgrade' ||
192: $target eq 'answer' || $target eq 'analyze' ) {
193: my $bodytext = &Apache::lonxml::get_all_text("/vector",$parser,$style);
194: my @values = &Apache::run::run($bodytext,$safeeval,$$parstack[-1]);
195: if (@values == 1) {
196: @values = split(',',$values[0]);
197: }
198: push(@{ $answer{$cur_name}{'answers'} },\@values);
199: } elsif ($target eq 'edit') {
200: $result.=&Apache::edit::tag_start($target,$token);
201: my $bodytext = &Apache::lonxml::get_all_text("/vector",$parser,$style);
202: $result.=&Apache::edit::editline($token->[1],$bodytext,undef,40).
203: &Apache::edit::end_row();
204: } elsif ($target eq 'modified') {
205: $result=$token->[4].&Apache::edit::modifiedfield('/vector',$parser);
206: }
207: return $result;
208: }
209:
210: sub end_vector {
211: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
212: my $result;
213: if ($target eq 'edit') {
214: $result = &Apache::edit::end_table();
215: }
216: return $result;
217: }
218:
219: sub insert_vector {
220: return '
221: <value></value>';
222: }
223:
224: sub start_array {
225: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
226: my $result;
227: if ( $target eq 'web' || $target eq 'tex' ||
228: $target eq 'grade' || $target eq 'webgrade' ||
229: $target eq 'answer' || $target eq 'analyze' ) {
230: my $bodytext = &Apache::lonxml::get_all_text("/array",$parser,$style);
231: my @values = &Apache::run::evaluate($bodytext,$safeeval,
232: $$parstack[-1]);
233: push(@{ $answer{$cur_name}{'answers'} },@values);
234: }
235: return $result;
236: }
237:
238: sub end_array {
239: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
240: my $result;
241: return $result;
242: }
243:
244: sub start_unit {
245: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
246: my $result;
247: return $result;
248: }
249:
250: sub end_unit {
251: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
252: my $result;
253: return $result;
254: }
255:
256: sub start_numericalresponse {
257: my ($target,$token,$tagstack,$parstack,$parser,$safeeval)=@_;
258: &Apache::lonxml::register('Apache::caparesponse',
259: ('answer','answergroup','value','array','unit',
260: 'vector'));
261: push(@Apache::lonxml::namespace,'caparesponse');
262: my $id = &Apache::response::start_response($parstack,$safeeval);
263: my $result;
264: undef(%answer);
265: undef(%{$safeeval->varglob('LONCAPA::CAPAresponse_args')});
266: if ($target eq 'edit') {
267: $result.=&Apache::edit::tag_start($target,$token);
268: $result.=&Apache::edit::text_arg('Answer:','answer',$token);
269: if ($token->[1] eq 'numericalresponse') {
270: $result.=&Apache::edit::text_arg('Incorrect Answers:','incorrect',
271: $token).
272: &Apache::loncommon::help_open_topic('numerical_wrong_answers');
273: $result.=&Apache::edit::text_arg('Unit:','unit',$token,5).
274: &Apache::loncommon::help_open_topic('Physical_Units');
275: $result.=&Apache::edit::text_arg('Format:','format',$token,4).
276: &Apache::loncommon::help_open_topic('Numerical_Response_Format');
277: } elsif ($token->[1] eq 'formularesponse') {
278: $result.=&Apache::edit::text_arg('Sample Points:','samples',
279: $token,40).
280: &Apache::loncommon::help_open_topic('Formula_Response_Sampling');
281: }
282: $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
283: } elsif ($target eq 'modified') {
284: my $constructtag;
285: if ($token->[1] eq 'numericalresponse') {
286: $constructtag=&Apache::edit::get_new_args($token,$parstack,
287: $safeeval,'answer',
288: 'incorrect','unit',
289: 'format');
290: } elsif ($token->[1] eq 'formularesponse') {
291: $constructtag=&Apache::edit::get_new_args($token,$parstack,
292: $safeeval,'answer',
293: 'samples');
294: }
295: if ($constructtag) {
296: $result = &Apache::edit::rebuild_tag($token);
297: $result.=&Apache::edit::handle_insert();
298: }
299: } elsif ($target eq 'meta') {
300: $result=&Apache::response::meta_package_write('numericalresponse');
301: } elsif ($target eq 'answer' || $target eq 'grade') {
302: &Apache::response::reset_params();
303: } elsif ($target eq 'web') {
304: my $partid = $Apache::inputtags::part;
305: my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit');
306: &Apache::lonxml::debug("Got unit $hideunit for $partid $id");
307: #no way to enter units, with radio buttons
308: if (lc($hideunit) eq "yes") {
309: my $unit=&Apache::lonxml::get_param_var('unit',$parstack,
310: $safeeval);
311: if ($unit =~ /\S/) { $result.=" (in $unit) "; }
312: }
313: if (($token->[1] eq 'formularesponse') &&
314: ($Apache::inputtags::status['-1'] eq 'CAN_ANSWER')) {
315: }
316: if ( &Apache::response::show_answer() ) {
317: &set_answertext($tag_internal_answer_name,$target,$token,$tagstack,
318: $parstack,$parser,$safeeval,-1);
319: }
320: }
321: return $result;
322: }
323:
324: sub set_answertext {
325: my ($name,$target,$token,$tagstack,$parstack,$parser,$safeeval,
326: $response_level) = @_;
327: &add_in_tag_answer($parstack,$safeeval,$response_level);
328:
329: if ($name eq '' || !ref($answer{$name})) {
330: if (ref($answer{$tag_internal_answer_name})) {
331: $name = $tag_internal_answer_name;
332: } else {
333: $name = (sort(keys(%answer)))[0];
334: }
335: }
336: return if ($name eq '' || !ref($answer{$name}));
337:
338: my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,
339: $safeeval,$response_level);
340: my $unit=&Apache::lonxml::get_param_var('unit',$parstack,$safeeval,
341: $response_level);
342:
343: &Apache::lonxml::debug("answer looks to be $name");
344: my @answertxt;
345: for (my $i=0; $i < scalar(@{$answer{$name}{'answers'}}); $i++) {
346: my $answertxt;
347: my $answer=$answer{$name}{'answers'}[$i];
348: foreach my $element (@$answer) {
349: if ( scalar(@$tagstack)
350: && $tagstack->[$response_level] ne 'numericalresponse') {
351: $answertxt.=$element.',';
352: } else {
353: my $format;
354: if ($#formats > 0) {
355: $format=$formats[$i];
356: } else {
357: $format=$formats[0];
358: }
359: if ($unit=~/\$/) { $format="\$".$format; $unit=~s/\$//g; }
360: if ($unit=~/\,/) { $format="\,".$format; $unit=~s/\,//g; }
361: my $formatted=&format_number($element,$format,$target,
362: $safeeval);
363: $answertxt.=' '.$formatted.',';
364: }
365:
366: }
367: chop($answertxt);
368: if ($target eq 'web') {
369: $answertxt.=" $unit ";
370: }
371:
372: push(@answertxt,$answertxt)
373: }
374:
375: my $id = $Apache::inputtags::response[-1];
376: $Apache::inputtags::answertxt{$id}=\@answertxt;
377: }
378:
379: sub setup_capa_args {
380: my ($safeeval,$parstack,$args,$response) = @_;
381: my $args_ref= \%{$safeeval->varglob('LONCAPA::CAPAresponse_args')};
382: undef(%{ $args_ref });
383:
384: foreach my $arg (@{$args}) {
385: $$args_ref{$arg}=
386: &Apache::lonxml::get_param($arg,$parstack,$safeeval);
387: }
388: foreach my $key (keys(%Apache::inputtags::params)) {
389: $$args_ref{$key}=$Apache::inputtags::params{$key};
390: }
391: &setup_capa_response($args_ref,$response);
392: return $args_ref;
393: }
394:
395: sub setup_capa_response {
396: my ($args_ref,$response) = @_;
397:
398: if (ref($response)) {
399: $$args_ref{'response'}=dclone($response);
400: } else {
401: $$args_ref{'response'}=dclone([$response]);
402: }
403: }
404:
405: sub check_submission {
406: my ($response,$partid,$id,$tag,$parstack,$safeeval,$ignore_sig)=@_;
407: my @args = ('type','tol','sig','format','unit','calc','samples');
408: my $args_ref = &setup_capa_args($safeeval,$parstack,\@args,$response);
409:
410: my $hideunit=
411: &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoffunit');
412: #no way to enter units, with radio buttons
413: if ($Apache::lonhomework::type eq 'exam' ||
414: lc($hideunit) eq "yes") {
415: delete($$args_ref{'unit'});
416: }
417: #sig fig don't make much sense either
418: if (($Apache::lonhomework::type eq 'exam' ||
419: &Apache::response::submitted('scantron') ||
420: $ignore_sig) &&
421: $tag eq 'numericalresponse') {
422: delete($$args_ref{'sig'});
423: }
424:
425: if ($tag eq 'formularesponse') {
426: if ($$args_ref{'samples'}) {
427: $$args_ref{'type'}='fml';
428: } else {
429: $$args_ref{'type'}='math';
430: }
431: } elsif ($tag eq 'numericalresponse') {
432: $$args_ref{'type'}='float';
433: }
434:
435: &add_in_tag_answer($parstack,$safeeval);
436:
437: if (!%answer) {
438: &Apache::lonxml::error("No answers are defined");
439: }
440:
441: my (@final_awards,@final_msgs,@names);
442: foreach my $name (keys(%answer)) {
443: &Apache::lonxml::debug(" doing $name with ".join(':',@{ $answer{$name}{'answers'} }));
444:
445: ${$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=dclone($answer{$name});
446: &setup_capa_response($args_ref,$response);
447: use Time::HiRes;
448: my $t0 = [Time::HiRes::gettimeofday()];
449: my ($result,@msgs) =
450: &Apache::run::run("&caparesponse_check_list($tag)",$safeeval);
451: &Apache::lonxml::debug("checking $name $result with $response took ".&Time::HiRes::tv_interval($t0));
452: &Apache::lonxml::debug('msgs are '.join(':',@msgs));
453: my ($awards)=split(/:/,$result);
454: my @awards= split(/,/,$awards);
455: my ($ad, $msg) = &Apache::inputtags::finalizeawards(\@awards,\@msgs);
456: push(@final_awards,$ad);
457: push(@final_msgs,$msg);
458: push(@names,$name);
459: }
460: my ($ad, $msg, $name) = &Apache::inputtags::finalizeawards(\@final_awards,
461: \@final_msgs,
462: \@names,1);
463: &Apache::lonxml::debug(" name of picked award is $name from ".join(', ',@names));
464: return($ad,$msg, $name);
465: }
466:
467: sub add_in_tag_answer {
468: my ($parstack,$safeeval,$response_level) = @_;
469: my @answer=&Apache::lonxml::get_param_var('answer',$parstack,$safeeval,
470: $response_level);
471: &Apache::lonxml::debug('answer is'.join(':',@answer));
472: if (@answer && $answer[0] =~ /\S/) {
473: $answer{$tag_internal_answer_name}= {'type' => 'ordered',
474: 'answers' => [\@answer] };
475: }
476: }
477:
478: sub capa_formula_fix {
479: my ($expression)=@_;
480: return &Apache::response::implicit_multiplication($expression);
481: }
482:
483: sub end_numericalresponse {
484: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
485:
486: &Apache::lonxml::deregister('Apache::caparesponse',
487: ('answer','answergroup','value','array','unit',
488: 'vector'));
489: pop(@Apache::lonxml::namespace);
490:
491: my $increment=1;
492: my $result = '';
493: if (!$Apache::lonxml::default_homework_loaded) {
494: &Apache::lonxml::default_homework_load($safeeval);
495: }
496: my $partid = $Apache::inputtags::part;
497: my $id = $Apache::inputtags::response[-1];
498: my $tag;
499: my $safehole = new Safe::Hole;
500: $safeeval->share_from('capa',['&caparesponse_capa_check_answer']);
501:
502: if (scalar(@$tagstack)) { $tag=$$tagstack[-1]; }
503: if ( $target eq 'grade' && &Apache::response::submitted() ) {
504: &Apache::response::setup_params($tag,$safeeval);
505: if ($Apache::lonhomework::type eq 'exam' &&
506: (($tag eq 'formularesponse') || ($tag eq 'mathresponse'))) {
507: $increment=&Apache::response::scored_response($partid,$id);
508: } else {
509: my $response = &Apache::response::getresponse();
510: if ( $response =~ /[^\s]/) {
511: my %previous = &Apache::response::check_for_previous($response,$partid,$id);
512: &Apache::lonxml::debug("submitted a $response<br>\n");
513: &Apache::lonxml::debug($$parstack[-1] . "\n<br>");
514:
515: if ( &Apache::response::submitted('scantron')) {
516: &add_in_tag_answer($parstack,$safeeval);
517: my ($values,$display)=&make_numerical_bubbles($partid,$id,
518: $target,$parstack,$safeeval);
519: $response=$values->[$response];
520: }
521: $Apache::lonhomework::results{"resource.$partid.$id.submission"}=$response;
522: my ($ad,$msg,$name)=&check_submission($response,$partid,$id,
523: $tag,$parstack,
524: $safeeval);
525:
526: &Apache::lonxml::debug('ad is'.$ad);
527: if ($ad eq 'SIG_FAIL') {
528: my ($sig_u,$sig_l)=
529: &get_sigrange($Apache::inputtags::params{'sig'});
530: $msg=join(':',$msg,$sig_l,$sig_u);
531: &Apache::lonxml::debug("sigs bad $sig_u $sig_l ".
532: $Apache::inputtags::params{'sig'});
533: }
534: &Apache::lonxml::debug("\n<br>result:$result:$Apache::lonxml::curdepth<br>\n");
535: if ($Apache::lonhomework::type eq 'survey' &&
536: ($ad eq 'INCORRECT' || $ad eq 'APPROX_ANS' ||
537: $ad eq 'EXACT_ANS')) {
538: $ad='SUBMITTED';
539: }
540: &Apache::response::handle_previous(\%previous,$ad);
541: $Apache::lonhomework::results{"resource.$partid.$id.awarddetail"}=$ad;
542: $Apache::lonhomework::results{"resource.$partid.$id.awardmsg"}=$msg;
543: $Apache::lonhomework::results{"resource.$partid.$id.answername"}=$name;
544: $result='';
545: }
546: }
547: } elsif ($target eq 'web' || $target eq 'tex') {
548: &check_for_answer_errors($parstack,$safeeval);
549: my $award = $Apache::lonhomework::history{"resource.$Apache::inputtags::part.solved"};
550: my $status = $Apache::inputtags::status['-1'];
551: if ($Apache::lonhomework::type eq 'exam') {
552: # FIXME support multi dimensional numerical problems
553: # in exam bubbles
554: my ($bubble_values,$bubble_display)=
555: &make_numerical_bubbles($partid,$id,$target,$parstack,
556: $safeeval);
557: my $number_of_bubbles = scalar(@{ $bubble_values });
558: my $unit=&Apache::lonxml::get_param_var('unit',$parstack,
559: $safeeval);
560: my @alphabet=('A'..'Z');
561: if ($target eq 'web') {
562: if ($tag eq 'numericalresponse') {
563: if ($unit=~/\S/) {$result.=' (in '.$unit.')<br /><br />';}
564: $result.= '<table border="1"><tr>';
565: my $previous=$Apache::lonhomework::history{"resource.$Apache::inputtags::part.$id.submission"};
566: for (my $ind=0;$ind<$number_of_bubbles;$ind++) {
567: my $checked='';
568: if ($previous eq $bubble_values->[$ind]) {
569: $checked=" checked='on' ";
570: }
571: $result.='<td><input type="radio" name="HWVAL_'.$id.
572: '" value="'.$bubble_values->[$ind].'" '.$checked
573: .' /><b>'.$alphabet[$ind].'</b>: '.
574: $bubble_display->[$ind].'</td>';
575: }
576: $result.='</tr></table>';
577: }
578: } elsif ($target eq 'tex') {
579: if ((defined $unit) and ($unit=~/\S/) and ($Apache::lonhomework::type eq 'exam')) {
580: $result.=' \textit{(in} \verb|'.$unit.'|\textit{)} ';
581: }
582: if ($tag eq 'numericalresponse') {
583: my ($celllength,$number_of_tables,@table_range)=
584: &get_table_sizes($number_of_bubbles,$bubble_display);
585: my $j=0;
586: my $cou=0;
587: $result.='\vskip -1 mm \noindent \begin{enumerate}\item[\textbf{'.$Apache::lonxml::counter.'}.]';
588: for (my $i=0;$i<$number_of_tables;$i++) {
589: $result.='\vskip -1 mm \noindent \setlength{\tabcolsep}{2 mm}\begin{tabular}{';
590: for (my $ind=0;$ind<$table_range[$j];$ind++) {
591: $result.='p{3 mm}p{'.$celllength.' mm}';
592: }
593: $result.='}';
594: for (my $ind=$cou;$ind<$cou+$table_range[$j];$ind++) {
595: $result.='\hskip -4 mm {\small \textbf{'.$alphabet[$ind].'}}$\bigcirc$ & \hskip -3 mm {\small '.$bubble_display->[$ind].'} ';
596: if ($ind != $cou+$table_range[$j]-1) {$result.=' & ';}
597: }
598: $cou += $table_range[$j];
599: $j++;
600: $result.='\\\\\end{tabular}\vskip 0 mm ';
601: }
602: $result.='\end{enumerate}';
603: } else {
604: $increment = &Apache::response::repetition();
605: }
606: }
607: }
608: if (($target eq 'web') && ($tag eq 'formularesponse')
609: && ($Apache::lonhomework::type ne 'exam') && ($Apache::inputtags::status['-1'] eq 'CAN_ANSWER')
610: && (&Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.turnoneditor') ne 'no')){
611: $result.=&Apache::response::edit_mathresponse_button($id,"HWVAL_$id");
612: #hier
613: }
614:
615: &Apache::response::setup_prior_tries_hash(\&format_prior_response_numerical);
616: } elsif ($target eq 'edit') {
617: $result.='</td></tr>'.&Apache::edit::end_table;
618: } elsif ($target eq 'answer' || $target eq 'analyze') {
619: my $part_id="$partid.$id";
620: if ($target eq 'analyze') {
621: push (@{ $Apache::lonhomework::analyze{"parts"} },$part_id);
622: $Apache::lonhomework::analyze{"$part_id.type"} = $tag;
623: my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,$safeeval);
624: if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); }
625: push (@{ $Apache::lonhomework::analyze{"$part_id.incorrect"} }, @incorrect);
626: &Apache::response::check_if_computed($token,$parstack,
627: $safeeval,'answer');
628: }
629: if (scalar(@$tagstack)) {
630: &Apache::response::setup_params($tag,$safeeval);
631: }
632: &add_in_tag_answer($parstack,$safeeval);
633: my (@formats)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval);
634:
635: my $unit=&Apache::lonxml::get_param_var('unit',$parstack,$safeeval);
636:
637: if ($target eq 'answer') {
638: $result.=&Apache::response::answer_header($tag,undef,
639: scalar(keys(%answer)));
640: if ($tag eq 'numericalresponse'
641: && $Apache::lonhomework::type eq 'exam') {
642: my ($bubble_values,undef,$correct) = &make_numerical_bubbles($partid,
643: $id,$target,$parstack,$safeeval);
644: $result.=&Apache::response::answer_part($tag,$correct);
645: }
646: }
647: foreach my $name (sort(keys(%answer))) {
648: my @answers = @{ $answer{$name}{'answers'} };
649: if ($target eq 'analyze') {
650: foreach my $info ('answer','ans_high','ans_low','format') {
651: $Apache::lonhomework::analyze{"$part_id.$info"}{$name}=[];
652: }
653: }
654: my ($sigline,$tolline);
655: if ($name ne $tag_internal_answer_name
656: || scalar(keys(%answer)) > 1) {
657: $result.=&Apache::response::answer_part($tag,$name);
658: }
659: for(my $i=0;$i<=$#answers;$i++) {
660: my $ans=$answers[$i];
661: my $fmt=$formats[0];
662: if (@formats && $#formats) {$fmt=$formats[$i];}
663: my ($sighigh,$siglow);
664: if ($Apache::inputtags::params{'sig'}) {
665: ($sighigh,$siglow)=&get_sigrange($Apache::inputtags::params{'sig'});
666: }
667: my @vector;
668: if (ref($ans)) {
669: @vector = @{ $ans };
670: } else {
671: @vector = ($ans);
672: }
673: my @all_answer_info;
674: foreach my $element (@vector) {
675: my ($high,$low);
676: if ($Apache::inputtags::params{'tol'}) {
677: ($high,$low)=&get_tolrange($element,$Apache::inputtags::params{'tol'});
678: }
679: if ($target eq 'answer') {
680: if ($fmt && $tag eq 'numericalresponse') {
681: $fmt=~s/e/E/g;
682: if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; }
683: if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; }
684: $element = &format_number($element,$fmt,$target,$safeeval);
685: #if ($high) {
686: # $high=&format_number($high,$fmt,$target,$safeeval);
687: # $low =&format_number($low,$fmt,$target,$safeeval);
688: #}
689: }
690: if ($high && $tag eq 'numericalresponse') {
691: $element.='; ['.$low.'; '.$high.']';
692: $tolline .= "[$low, $high]";
693: }
694: if (defined($sighigh) && $tag eq 'numericalresponse') {
695: if ($env{'form.answer_output_mode'} eq 'tex') {
696: $element.= "; Sig $siglow - $sighigh";
697: } else {
698: $element.= " Sig <i>$siglow - $sighigh</i>";
699: $sigline .= "[$siglow, $sighigh]";
700: }
701: }
702: push(@all_answer_info,$element);
703:
704: } elsif ($target eq 'analyze') {
705: push (@{ $Apache::lonhomework::analyze{"$part_id.answer"}{$name}[$i] }, $element);
706: if ($high) {
707: push (@{ $Apache::lonhomework::analyze{"$part_id.ans_high"}{$name}[$i] }, $high);
708: push (@{ $Apache::lonhomework::analyze{"$part_id.ans_low"}{$name}[$i] }, $low);
709: }
710: if ($fmt) {
711: push (@{ $Apache::lonhomework::analyze{"$part_id.format"}{$name}[$i] }, $fmt);
712: }
713: }
714: }
715: if ($target eq 'answer') {
716: $result.= &Apache::response::answer_part($tag,join('; ',@all_answer_info));
717: }
718: }
719:
720: my @fmt_ans;
721: for(my $i=0;$i<=$#answers;$i++) {
722: my $ans=$answers[$i];
723: my $fmt=$formats[0];
724: if (@formats && $#formats) {$fmt=$formats[$i];}
725: foreach my $element (@$ans) {
726: if ($fmt && $tag eq 'numericalresponse') {
727: $fmt=~s/e/E/g;
728: if ($unit=~/\$/) { $fmt="\$".$fmt; $unit=~s/\$//g; }
729: if ($unit=~/\,/) { $fmt="\,".$fmt; $unit=~s/\,//g; }
730: $element = &format_number($element,$fmt,$target,
731: $safeeval);
732: if ($fmt=~/\$/ && $unit!~/\$/) { $element=~s/\$//; }
733: }
734: }
735: push(@fmt_ans,join(',',@$ans));
736: }
737: my $response=\@fmt_ans;
738:
739: my $hideunit=&Apache::lonnet::EXT('resource.'.$partid.'_'.
740: $id.'.turnoffunit');
741: if ($unit ne '' &&
742: ! ($Apache::lonhomework::type eq 'exam' ||
743: lc($hideunit) eq "yes") ) {
744: my $cleanunit=$unit;
745: $cleanunit=~s/\$\,//g;
746: foreach my $ans (@fmt_ans) {
747: $ans.=" $cleanunit";
748: }
749: }
750: my ($ad,$msg)=&check_submission($response,$partid,$id,$tag,
751: $parstack,$safeeval);
752: if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') {
753: my $error;
754: if ($tag eq 'formularesponse') {
755: $error=&mt('Computer\'s answer is incorrect ("[_1]").',join(', ',@$response));
756: } else {
757: # answer failed check if it is sig figs that is failing
758: my ($ad,$msg)=&check_submission($response,$partid,$id,
759: $tag,$parstack,
760: $safeeval,1);
761: if ($sigline ne '') {
762: $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);
763: } else {
764: $error=&mt('Computer\'s answer is incorrect ("[_1]"). It is likely that the tolerance range [_2] needs to be adjusted.',join(', ',@$response),$tolline);
765: }
766: }
767: if ($ad ne 'EXACT_ANS' && $ad ne 'APPROX_ANS') {
768: &Apache::lonxml::error($error);
769: } else {
770: &Apache::lonxml::warning($error);
771: }
772: }
773:
774: if (defined($unit) and ($unit ne '') and
775: $tag eq 'numericalresponse') {
776: if ($target eq 'answer') {
777: if ($env{'form.answer_output_mode'} eq 'tex') {
778: $result.=&Apache::response::answer_part($tag,
779: " Unit: $unit ");
780: } else {
781: $result.=&Apache::response::answer_part($tag,
782: "Unit: <b>$unit</b>");
783: }
784: } elsif ($target eq 'analyze') {
785: push (@{ $Apache::lonhomework::analyze{"$part_id.unit"} }, $unit);
786: }
787: }
788: if ($tag eq 'formularesponse' && $target eq 'answer') {
789: my $samples=&Apache::lonxml::get_param('samples',$parstack,$safeeval);
790: $result.=&Apache::response::answer_part($tag,$samples);
791: }
792: $result.=&Apache::response::next_answer($tag,$name);
793: }
794: if ($target eq 'answer') {
795: $result.=&Apache::response::answer_footer($tag);
796: }
797: }
798: if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
799: $target eq 'tex' || $target eq 'analyze') {
800: if (($tag eq 'formularesponse') && ($target eq 'analyze')) {
801: my $type = &Apache::lonnet::EXT('resource.'.$partid.'_'.$id.'.type');
802: if ($type eq 'exam') {
803: $increment = &Apache::response::repetition();
804: }
805: }
806: &Apache::lonxml::increment_counter($increment,"$partid.$id");
807: if ($target eq 'analyze') {
808: &Apache::lonhomework::set_bubble_lines();
809: }
810: }
811: &Apache::response::end_response();
812: return $result;
813: }
814:
815: sub format_prior_response_numerical {
816: my ($mode,$answer) = @_;
817: if (ref($answer)) {
818: my $result = '<table class="LC_prior_numerical"><tr>';
819: foreach my $element (@{ $answer }) {
820: $result.= '<td><span class="LC_prior_numerical">'.
821: &HTML::Entities::encode($element,'"<>&').'</span></td>';
822: }
823: $result.='</tr></table>';
824: return $result;
825: }
826: return '<span class="LC_prior_numerical">'.
827: &HTML::Entities::encode($answer,'"<>&').'</span>';
828:
829: }
830:
831: sub check_for_answer_errors {
832: my ($parstack,$safeeval) = @_;
833: &add_in_tag_answer($parstack,$safeeval);
834: my %counts;
835: foreach my $name (keys(%answer)) {
836: push(@{$counts{scalar(@{$answer{$name}{'answers'}})}},$name);
837: }
838: if (scalar(keys(%counts)) > 1) {
839: my $counts = join(' ',map {
840: my $count = $_;
841: &mt("Answers [_1] had [_2] components.",
842: '<tt>'.join(', ',@{$counts{$count}}).'</tt>',
843: $count);
844: } (sort(keys(%counts))));
845: &Apache::lonxml::error(&mt("All answers must have the same number of components. Varying numbers of answers were seen. ").$counts);
846: }
847: my $expected_number_of_inputs = (keys(%counts))[0];
848: if ( $expected_number_of_inputs > 0
849: && $expected_number_of_inputs != scalar(@Apache::inputtags::inputlist)) {
850: &Apache::lonxml::error(&mt("Expected [_1] input fields, but there were only [_2] seen.",
851: $expected_number_of_inputs,
852: scalar(@Apache::inputtags::inputlist)));
853: }
854: }
855:
856: sub get_table_sizes {
857: my ($number_of_bubbles,$rbubble_values)=@_;
858: my $scale=2; #mm for one digit
859: my $cell_width=0;
860: foreach my $member (@$rbubble_values) {
861: my $cell_width_real=0;
862: if ($member=~/(\+|-)?(\d*)\.?(\d*)\s*\$?\\times\s*10\^{(\+|-)?(\d+)}\$?/) {
863: $cell_width_real=(length($2)+length($3)+length($5)+7)*$scale;
864: } elsif ($member=~/(\d*)\.?(\d*)(E|e)(\+|-)?(\d*)/) {
865: $cell_width_real=(length($1)+length($2)+length($5)+9)*$scale;
866: } elsif ($member=~/(\d*)\.(\d*)/) {
867: $cell_width_real=(length($1)+length($2)+3)*$scale;
868: } else {
869: $cell_width_real=(length($member)+1)*$scale*0.9;
870: }
871: if ($cell_width_real>$cell_width) {$cell_width=$cell_width_real;}
872: }
873: $cell_width+=8;
874: my $textwidth;
875: if ($env{'form.textwidth'} ne '') {
876: $env{'form.textwidth'}=~/(\d*)\.?(\d*)/;
877: $textwidth=$1.'.'.$2;
878: } else {
879: $env{'form.textwidth'}=~/(\d+)\.?(\d*)/;
880: $textwidth=$1.'.'.$2;
881: }
882: my $bubbles_per_line=int($textwidth/$cell_width);
883: if ($bubbles_per_line > $number_of_bubbles) {
884: $bubbles_per_line=$number_of_bubbles;
885: } elsif (($bubbles_per_line > $number_of_bubbles/2)
886: && ($number_of_bubbles % 2==0)) {
887: $bubbles_per_line=$number_of_bubbles/2;
888: }
889: if ($bubbles_per_line < 1) {
890: $bubbles_per_line=1;
891: }
892: my $number_of_tables = int($number_of_bubbles/$bubbles_per_line);
893: my @table_range = ();
894: for (my $i=0;$i<$number_of_tables;$i++) {push @table_range,$bubbles_per_line;}
895: if ($number_of_bubbles % $bubbles_per_line) {
896: $number_of_tables++;
897: push @table_range,($number_of_bubbles % $bubbles_per_line);
898: }
899: $cell_width-=8;
900: $cell_width=$cell_width*3/4;
901: return ($cell_width,$number_of_tables,@table_range);
902: }
903:
904: sub format_number {
905: my ($number,$format,$target,$safeeval)=@_;
906: my $ans;
907: if ($format eq '') {
908: #What is the number? (integer,decimal,floating point)
909: if ($number=~/^(\d*\.?\d*)(E|e)[+\-]?(\d*)$/) {
910: $format = '3e';
911: } elsif ($number=~/^(\d*)\.(\d*)$/) {
912: $format = '4f';
913: } elsif ($number=~/^(\d*)$/) {
914: $format = 'd';
915: }
916: }
917: if (!$Apache::lonxml::default_homework_loaded) {
918: &Apache::lonxml::default_homework_load($safeeval);
919: }
920: $ans=&Apache::run::run("&prettyprint(q\0$number\0,q\0$format\0,q\0$target\0)",$safeeval);
921: return $ans;
922: }
923:
924: sub make_numerical_bubbles {
925: my ($part,$id,$target,$parstack,$safeeval) =@_;
926:
927: if (!%answer) {
928: &Apache::lonxml::error(&mt("No answers defined for response [_1] in part [_2] to make bubbles for.",$id,$part));
929: return ([],[],undef);
930: }
931:
932: my $number_of_bubbles =
933: &Apache::response::get_response_param($part.'_'.$id,'numbubbles',8);
934:
935: my ($format)=&Apache::lonxml::get_param_var('format',$parstack,$safeeval);
936: my $name = (exists($answer{$tag_internal_answer_name})
937: ? $tag_internal_answer_name
938: : (sort(keys(%answer)))[0]);
939:
940: if ( scalar(@{$answer{$name}{'answers'}}) > 1) {
941: &Apache::lonxml::error("Only answers with 1 component are supported in exam mode");
942: }
943: if (scalar(@{$answer{$name}{'answers'}[0]}) > 1) {
944: &Apache::lonxml::error("Vector answers are unsupported in exam mode.");
945: }
946:
947: my $answer = $answer{$name}{'answers'}[0][0];
948: my (@incorrect)=&Apache::lonxml::get_param_var('incorrect',$parstack,
949: $safeeval);
950: if ($#incorrect eq 0) { @incorrect=(split(/,/,$incorrect[0])); }
951:
952: my @bubble_values=();
953: my @alphabet=('A'..'Z');
954:
955: &Apache::lonxml::debug("answer is $answer incorrect is @incorrect");
956: my @oldseed=&Math::Random::random_get_seed();
957: if (@incorrect) {
958: &Apache::lonxml::debug("inside ".(scalar(@incorrect)+1 gt $number_of_bubbles));
959: if (defined($incorrect[0]) &&
960: scalar(@incorrect)+1 >= $number_of_bubbles) {
961: &Apache::lonxml::debug("inside ".(scalar(@incorrect)+1).":$number_of_bubbles");
962: &Apache::response::setrandomnumber();
963: my @rand_inc=&Math::Random::random_permutation(@incorrect);
964: @bubble_values=@rand_inc[0..($number_of_bubbles-2)];
965: @bubble_values=sort {$a <=> $b} (@bubble_values,$answer);
966: &Apache::lonxml::debug("Answer was :$answer: returning :".$#bubble_values.": which are :".join(':',@bubble_values));
967: &Math::Random::random_set_seed(@oldseed);
968:
969: my $correct;
970: for(my $i=0; $i<=$#bubble_values;$i++) {
971: if ($bubble_values[$i] eq $answer) {
972: $correct = $alphabet[$i];
973: last;
974: }
975: }
976:
977: if (defined($format) && $format ne '') {
978: my @bubble_display;
979: foreach my $value (@bubble_values) {
980: push(@bubble_display,
981: &format_number($value,$format,$target,$safeeval));
982: }
983: return (\@bubble_values,\@bubble_display,$correct);
984: } else {
985: return (\@bubble_values,\@bubble_values,$correct);
986: }
987: }
988: if (defined($incorrect[0]) &&
989: scalar(@incorrect)+1 < $number_of_bubbles) {
990: &Apache::lonxml::warning("Not enough incorrect answers were specified in the incorrect array, ignoring the specified incorrect answers and instead generating them (".join(',',@incorrect).").");
991: }
992: }
993: my @factors = (1.13,1.17,1.25,1.33,1.45); #default values of factors
994: my @powers = (1..$number_of_bubbles);
995: &Apache::response::setrandomnumber();
996: my $ind=&Math::Random::random_uniform_integer(1,0,$#powers);
997: my $power = $powers[$ind];
998: $ind=&Math::Random::random_uniform_integer(1,0,$#factors);
999: my $factor = $factors[$ind];
1000: my @bubble_display;
1001: my $answerfactor=$answer;
1002: if ($answer==0) {
1003: $answerfactor=&Math::Random::random_uniform_integer(1,1,100)/
1004: &Math::Random::random_uniform_integer(1,1,10);
1005: }
1006: for ($ind=0;$ind<$number_of_bubbles;$ind++) {
1007: $bubble_values[$ind] = $answerfactor*($factor**($power-$powers[$#powers-$ind]));
1008: $bubble_display[$ind] = &format_number($bubble_values[$ind],
1009: $format,$target,$safeeval);
1010: }
1011: my $correct = $alphabet[$number_of_bubbles-$power];
1012: if ($answer==0) {
1013: $correct='A';
1014: $bubble_values[0]=0;
1015: $bubble_display[0] = &format_number($bubble_values[0],
1016: $format,$target,$safeeval);
1017: }
1018: &Math::Random::random_set_seed(@oldseed);
1019: return (\@bubble_values,\@bubble_display,$correct);
1020: }
1021:
1022: sub get_tolrange {
1023: my ($ans,$tol)=@_;
1024: my ($high,$low);
1025: if ($tol =~ /%$/) {
1026: chop($tol);
1027: my $change=$ans*($tol/100.0);
1028: $high=$ans+$change;
1029: $low=$ans-$change;
1030: } else {
1031: $high=$ans+$tol;
1032: $low=$ans-$tol;
1033: }
1034: return ($high,$low);
1035: }
1036:
1037: sub get_sigrange {
1038: my ($sig)=@_;
1039: #&Apache::lonxml::debug("Got a sig of :$sig:");
1040: my $courseid=$env{'request.course.id'};
1041: if ($env{'request.state'} ne 'construct'
1042: && lc($env{"course.$courseid.disablesigfigs"}) eq 'yes') {
1043: return (15,0);
1044: }
1045: my $sig_lbound;
1046: my $sig_ubound;
1047: if ($sig eq '') {
1048: $sig_lbound = 0; #SIG_LB_DEFAULT
1049: $sig_ubound =15; #SIG_UB_DEFAULT
1050: } else {
1051: ($sig_lbound,$sig_ubound) = split(/,/,$sig);
1052: if (!defined($sig_lbound)) {
1053: $sig_lbound = 0; #SIG_LB_DEFAULT
1054: $sig_ubound =15; #SIG_UB_DEFAULT
1055: }
1056: if (!defined($sig_ubound)) { $sig_ubound=$sig_lbound; }
1057: }
1058: if (($sig_ubound<$sig_lbound) ||
1059: ($sig_lbound > 15) ||
1060: ($sig =~/(\+|-)/ ) ) {
1061: my $errormsg=&mt("Invalid Significant figures detected")." ($sig)";
1062: if ($env{'request.state'} eq 'construct') {
1063: $errormsg.=
1064: &Apache::loncommon::help_open_topic('Significant_Figures');
1065: }
1066: &Apache::lonxml::error($errormsg);
1067: }
1068: return ($sig_ubound,$sig_lbound);
1069: }
1070:
1071: sub format_prior_response_string {
1072: my ($mode,$answer) =@_;
1073: return '<span class="LC_prior_string">'.
1074: &HTML::Entities::encode($answer,'"<>&').'</span>';
1075: }
1076:
1077: sub start_stringresponse {
1078: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1079: my $result;
1080: my $id = &Apache::response::start_response($parstack,$safeeval);
1081: if ($target eq 'meta') {
1082: $result=&Apache::response::meta_package_write('stringresponse');
1083: } elsif ($target eq 'edit') {
1084: $result.=&Apache::edit::tag_start($target,$token);
1085: $result.=&Apache::edit::text_arg('Answer:','answer',$token);
1086: $result.=&Apache::edit::select_arg('Type:','type',
1087: [['cs','Case Sensitive'],['ci','Case Insensitive'],
1088: ['mc','Case Insensitive, Any Order'],
1089: ['re','Regular Expression']],$token);
1090: $result.=&Apache::edit::text_arg('String to display for answer:',
1091: 'answerdisplay',$token);
1092: $result.=&Apache::edit::end_row().&Apache::edit::start_spanning_row();
1093: } elsif ($target eq 'modified') {
1094: my $constructtag;
1095: $constructtag=&Apache::edit::get_new_args($token,$parstack,
1096: $safeeval,'answer',
1097: 'type','answerdisplay');
1098: if ($constructtag) {
1099: $result = &Apache::edit::rebuild_tag($token);
1100: $result.=&Apache::edit::handle_insert();
1101: }
1102: } elsif ($target eq 'web') {
1103: if ( &Apache::response::show_answer() ) {
1104: my $answer=
1105: &Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval);
1106: if (!defined $answer || $answer eq '') {
1107: $answer=
1108: &Apache::lonxml::get_param('answer',$parstack,$safeeval);
1109: }
1110: $Apache::inputtags::answertxt{$id}=[$answer];
1111: }
1112: } elsif ($target eq 'answer' || $target eq 'grade') {
1113: &Apache::response::reset_params();
1114: }
1115: return $result;
1116: }
1117:
1118: sub end_stringresponse {
1119: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1120:
1121: my $result = '';
1122: my $part=$Apache::inputtags::part;
1123: my $id=$Apache::inputtags::response[-1];
1124: my $answer=&Apache::lonxml::get_param('answer',$parstack,$safeeval);
1125: my $type=&Apache::lonxml::get_param('type',$parstack,$safeeval);
1126: my $answerdisplay=&Apache::lonxml::get_param('answerdisplay',$parstack,$safeeval);
1127: &Apache::lonxml::debug("current $answer ".$token->[2]);
1128: if (!$Apache::lonxml::default_homework_loaded) {
1129: &Apache::lonxml::default_homework_load($safeeval);
1130: }
1131: if ( $target eq 'grade' && &Apache::response::submitted() ) {
1132: &Apache::response::setup_params('stringresponse',$safeeval);
1133: $safeeval->share_from('capa',['&caparesponse_capa_check_answer']);
1134: if ($Apache::lonhomework::type eq 'exam' ||
1135: &Apache::response::submitted('scantron')) {
1136: &Apache::response::scored_response($part,$id);
1137:
1138: } else {
1139: my $response = &Apache::response::getresponse();
1140: if ( $response =~ /[^\s]/) {
1141: my %previous = &Apache::response::check_for_previous($response,
1142: $part,$id);
1143: &Apache::lonxml::debug("submitted a $response<br>\n");
1144: &Apache::lonxml::debug($$parstack[-1] . "\n<br>");
1145: $Apache::lonhomework::results{"resource.$part.$id.submission"}=
1146: $response;
1147: my ($ad,$msg);
1148: if ($type eq 're' ) {
1149: # if the RE wasn't in a var it likely got munged,
1150: # thus grab it from the var directly
1151: # my $testans=$token->[2]->{'answer'};
1152: # if ($testans !~ m/^\s*\$/) {
1153: # $answer=$token->[2]->{'answer'};
1154: # }
1155: ${$safeeval->varglob('LONCAPA::response')}=$response;
1156: $result = &Apache::run::run('if ($LONCAPA::response=~m'.$answer.') { return 1; } else { return 0; }',$safeeval);
1157: &Apache::lonxml::debug("current $response");
1158: &Apache::lonxml::debug("current $answer");
1159: $ad = ($result) ? 'APPROX_ANS' : 'INCORRECT';
1160: } else {
1161: my @args = ('type');
1162: my $args_ref = &setup_capa_args($safeeval,$parstack,
1163: \@args,$response);
1164:
1165: &add_in_tag_answer($parstack,$safeeval);
1166: my (@final_awards,@final_msgs,@names);
1167: foreach my $name (keys(%answer)) {
1168: &Apache::lonxml::debug(" doing $name with ".join(':',@{ $answer{$name}{'answers'} }));
1169: ${$safeeval->varglob('LONCAPA::CAPAresponse_answer')}=dclone($answer{$name});
1170: my ($result, @msgs)=&Apache::run::run("&caparesponse_check_list($$tagstack[-1])",$safeeval);
1171: &Apache::lonxml::debug('msgs are'.join(':',@msgs));
1172: my ($awards)=split(/:/,$result);
1173: my (@awards) = split(/,/,$awards);
1174: ($ad,$msg) =
1175: &Apache::inputtags::finalizeawards(\@awards,\@msgs);
1176: push(@final_awards,$ad);
1177: push(@final_msgs,$msg);
1178: push(@names,$name);
1179: &Apache::lonxml::debug("\n<br>result:$result:$Apache::lonxml::curdepth<br>\n");
1180: }
1181: my ($ad, $msg, $name) =
1182: &Apache::inputtags::finalizeawards(\@final_awards,
1183: \@final_msgs,
1184: \@names,1);
1185: }
1186: if ($Apache::lonhomework::type eq 'survey' &&
1187: ($ad eq 'INCORRECT' || $ad eq 'APPROX_ANS' ||
1188: $ad eq 'EXACT_ANS')) {
1189: $ad='SUBMITTED';
1190: }
1191: &Apache::response::handle_previous(\%previous,$ad);
1192: $Apache::lonhomework::results{"resource.$part.$id.awarddetail"}=$ad;
1193: $Apache::lonhomework::results{"resource.$part.$id.awardmsg"}=$msg;
1194: }
1195: }
1196: } elsif ($target eq 'answer' || $target eq 'analyze') {
1197: &add_in_tag_answer($parstack,$safeeval);
1198: if ($target eq 'analyze') {
1199: push (@{ $Apache::lonhomework::analyze{"parts"} },"$part.$id");
1200: $Apache::lonhomework::analyze{"$part.$id.type"} = 'stringresponse';
1201: &Apache::response::check_if_computed($token,$parstack,$safeeval,
1202: 'answer');
1203: }
1204: &Apache::response::setup_params('stringresponse',$safeeval);
1205: if ($target eq 'answer') {
1206: $result.=&Apache::response::answer_header('stringresponse');
1207: }
1208: foreach my $name (keys(%answer)) {
1209: my @answers = @{ $answer{$name}{'answers'} };
1210: for (my $i=0;$i<=$#answers;$i++) {
1211: my $answer_part = $answers[$i];
1212: foreach my $element (@{$answer_part}) {
1213: if ($target eq 'answer') {
1214: $result.=&Apache::response::answer_part('stringresponse',
1215: $element);
1216: } elsif ($target eq 'analyze') {
1217: push (@{ $Apache::lonhomework::analyze{"$part.$id.answer"}{$name}[$i] },
1218: $element);
1219: }
1220: }
1221: if ($target eq 'answer' && $type eq 're') {
1222: $result.=&Apache::response::answer_part('stringresponse',
1223: $answerdisplay);
1224: }
1225: }
1226: }
1227: my $string='Case Insensitive';
1228: if ($type eq 'mc') {
1229: $string='Multiple Choice';
1230: } elsif ($type eq 'cs') {
1231: $string='Case Sensitive';
1232: } elsif ($type eq 'ci') {
1233: $string='Case Insensitive';
1234: } elsif ($type eq 're') {
1235: $string='Regular Expression';
1236: }
1237: if ($target eq 'answer') {
1238: if ($env{'form.answer_output_mode'} eq 'tex') {
1239: $result.=&Apache::response::answer_part('stringresponse',
1240: "$string");
1241: } else {
1242: $result.=&Apache::response::answer_part('stringresponse',
1243: "<b>$string</b>");
1244: }
1245: } elsif ($target eq 'analyze') {
1246: push (@{$Apache::lonhomework::analyze{"$part.$id.str_type"}},
1247: $type);
1248: }
1249: if ($target eq 'answer') {
1250: $result.=&Apache::response::answer_footer('stringresponse');
1251: }
1252: } elsif ($target eq 'edit') {
1253: $result.='</td></tr>'.&Apache::edit::end_table;
1254: } elsif ($target eq 'web' || $target eq 'tex') {
1255: &Apache::response::setup_prior_tries_hash(\&format_prior_response_string);
1256: }
1257: if ($target eq 'grade' || $target eq 'web' || $target eq 'answer' ||
1258: $target eq 'tex' || $target eq 'analyze') {
1259: &Apache::lonxml::increment_counter(&Apache::response::repetition(),
1260: "$part.$id");
1261: if ($target eq 'analyze') {
1262: &Apache::lonhomework::set_bubble_lines();
1263: }
1264: }
1265: &Apache::response::end_response;
1266: return $result;
1267: }
1268:
1269: sub start_formularesponse {
1270: my ($target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
1271: my $result;
1272: if ($target eq 'meta') {
1273: &Apache::response::start_response($parstack,$safeeval);
1274: $result=&Apache::response::meta_package_write('formularesponse');
1275: &Apache::response::end_response();
1276: } else {
1277: $result.=&start_numericalresponse(@_);
1278: }
1279: return $result;
1280: }
1281:
1282: sub end_formularesponse {
1283: return end_numericalresponse(@_);
1284: }
1285:
1286: 1;
1287: __END__
1288:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>