Parent Directory
|
Revision Log
modifications so that the number of points plotted is not so flakey
1 2 #use AnswerEvaluator; 3 4 5 # provided by the translator 6 # initialize PGcore and PGrandom 7 8 9 $main::VERSION ="WW2"; 10 11 sub _PG_init{ 12 $main::VERSION ="WW2.9+"; 13 } 14 sub not_null {PGcore::not_null(@_)}; 15 16 sub pretty_print {PGcore::pretty_print(@_)}; 17 18 our $PG; 19 20 sub DEBUG_MESSAGE { 21 my @msg = @_; 22 $PG->debug_message("---- ".join(" ",caller())." ------", @msg,"__________________________"); 23 } 24 sub WARN_MESSAGE{ 25 my @msg = @_; 26 $PG->warning_message("---- ".join(" ",caller())." ------", @msg,"__________________________"); 27 } 28 sub DOCUMENT { 29 30 # get environment 31 $rh_envir = \%envir; #KLUDGE FIXME 32 # warn "rh_envir is ",ref($rh_envir); 33 $PG = new PGcore($rh_envir, # can add key/value options to modify 34 ); 35 $PG->clear_internal_debug_messages; 36 # initialize main:: variables 37 38 $ANSWER_PREFIX = $PG->{ANSWER_PREFIX}; 39 $QUIZ_PREFIX = $PG->{QUIZ_PREFIX}; 40 $showPartialCorrectAnswers = $PG->{flags}->{showPartialCorrectAnswers}; 41 $showHint = $PG->{flags}->{showHint}; 42 $solutionExists = $PG->{flags}->{solutionExists}; 43 $hintExists = $PG->{flags}->{hintExists}; 44 $pgComment = ''; 45 %gifs_created = %{ $PG->{gifs_created}}; 46 %external_refs = %{ $PG->{external_refs}}; 47 48 @KEPT_EXTRA_ANSWERS =(); #temporary hack 49 50 my %envir = %$rh_envir; 51 $displayMode = $PG->{displayMode}; 52 $PG_random_generator = $PG->{PG_random_generator}; 53 # Save the file name for use in error messages 54 # Doesn't appear to be used FIXME 55 # my ($callpkg,$callfile) = caller(0); 56 # $envir{__files__}{$callfile} = $envir{templateDirectory}.$envir{fileName}; 57 58 #no strict; 59 foreach my $var (keys %envir) { 60 PG_restricted_eval(qq!\$main::$var = \$envir{$var}!); #whew!! makes sure $var is interpolated but $main:: is evaluated at run time. 61 warn "Problem defining $var while initializing the PG problem: $@" if $@; 62 } 63 #use strict; 64 #FIXME 65 # load java script needed for displayModes 66 if ($envir{displayMode} eq 'HTML_jsMath') { 67 my $prefix = ""; 68 if (!$envir{jsMath}{reportMissingFonts}) { 69 $prefix .= '<SCRIPT>noFontMessage = 1</SCRIPT>'."\n"; 70 } elsif ($main::envir{jsMath}{missingFontMessage}) { 71 $prefix .= '<SCRIPT>missingFontMessage = "'.$main::envir{jsMath}{missingFontMessage}.'"</SCRIPT>'."\n"; 72 } 73 $prefix .= '<SCRIPT>processDoubleClicks = '.($main::envir{jsMath}{processDoubleClicks}?'1':'0')."</SCRIPT>\n"; 74 TEXT( 75 $prefix, 76 '<SCRIPT SRC="'.$envir{jsMathURL}. '"></SCRIPT>' . "\n" , 77 '<NOSCRIPT><CENTER><FONT COLOR="#CC0000">' , 78 "$BBOLD", 'Warning: the mathematics on this page requires JavaScript.', ,$BR, 79 'If your browser supports it, be sure it is enabled.', 80 "$EBOLD", 81 '</FONT></CENTER><p> 82 </NOSCRIPT>' 83 ); 84 TEXT('<SCRIPT>jsMath.Setup.Script("plugins/noImageFonts.js")</SCRIPT>') 85 if ($envir{jsMath}{noImageFonts}); 86 } elsif ($envir{displayMode} eq 'HTML_asciimath') { 87 TEXT('<SCRIPT SRC="'.$main::envir{asciimathURL}.'"></SCRIPT>' . "\n" , 88 '<SCRIPT>mathcolor = "black"</SCRIPT>' ); 89 } elsif ($envir{displayMode} eq 'HTML_LaTeXMathML') { 90 TEXT('<SCRIPT SRC="'.$envir{LaTeXMathMLURL}.'"></SCRIPT>'."\n"); 91 92 } 93 94 } 95 $main::displayMode = $PG->{displayMode}; 96 $main::PG = $PG; 97 sub TEXT { 98 $PG->TEXT(@_) ; 99 } 100 101 sub HEADER_TEXT { 102 $PG->HEADER_TEXT(@_); 103 } 104 105 sub LABELED_ANS { 106 my @in = @_; 107 my @out = (); 108 #prepend labels with the quiz and section prefixes. 109 while (@in ) { 110 my $label = shift @in; 111 $label = join("", $PG->{QUIZ_PREFIX}, $PG->{SECTION_PREFIX}, $label); 112 $ans_eval = shift @in; 113 push @out, $label, $ans_eval; 114 } 115 $PG->LABELED_ANS(@out); # returns pointer to the labeled answer group 116 } 117 118 sub NAMED_ANS { 119 &LABELED_ANS(@_); # returns pointer to the labeled answer group 120 } 121 122 sub ANS { 123 #warn "using PGnew for ANS"; 124 $PG->ANS(@_); # returns pointer to the labeled answer group 125 } 126 127 sub RECORD_ANS_NAME { 128 $PG->record_ans_name(@_); 129 } 130 131 sub inc_ans_rule_count { 132 #$PG->{unlabeled_answer_blank_count}++; 133 #my $num = $PG->{unlabeled_answer_blank_count}; 134 DEBUG_MESSAGE( " using PG to inc_ans_rule_count = $num ", caller(2)); 135 warn " using PG to inc_ans_rule_count = $num ", caller(2); 136 $PG->{unlabeled_answer_blank_count}; 137 } 138 sub ans_rule_count { 139 $PG->{unlabeled_answer_blank_count}; 140 } 141 sub NEW_ANS_NAME { 142 return "" if $PG_STOP_FLAG; 143 #my $number=shift; 144 # we have an internal count so the number not actually used. 145 my $name =$PG->record_unlabeled_ans_name(); 146 $name; 147 } 148 sub NEW_ARRAY_NAME { 149 return "" if $PG_STOP_FLAG; 150 my $name =$PG->record_unlabeled_array_name(); 151 $name; 152 } 153 154 # new subroutine 155 sub NEW_ANS_BLANK { 156 return "" if $PG_STOP_FLAG; 157 $PG->record_unlabeled_ans_name(@_); 158 } 159 160 sub ANS_NUM_TO_NAME { 161 $PG->new_label(@_); # behaves as in PG.pl 162 } 163 164 sub store_persistent_data { 165 $PG->store_persistent_data(@_); #needs testing 166 } 167 sub RECORD_FORM_LABEL { # this stores form data (such as sticky answers), but does nothing more 168 # it's a bit of hack since we are storing these in the 169 # KEPT_EXTRA_ANSWERS queue even if they aren't answers per se. 170 #FIXME 171 # warn "Using RECORD_FORM_LABEL -- deprecated? use $PG->store_persistent_data instead."; 172 RECORD_EXTRA_ANSWERS(@_); 173 } 174 175 sub RECORD_EXTRA_ANSWERS { 176 return "" if $PG_STOP_FLAG; 177 my $label = shift; # the label of the input box or textarea 178 eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes 179 $label; 180 181 } 182 183 184 sub NEW_ANS_ARRAY_NAME { # this keeps track of the answers within an array which are entered implicitly, 185 # rather than with a specific label 186 return "" if $PG_STOP_FLAG; 187 my $number=shift; 188 $main::vecnum = -1; 189 my $row = shift; 190 my $col = shift; 191 # my $array_ans_eval_label = "ArRaY"."$number"."__"."$vecnum".":"; 192 my $label = $PG->{QUIZ_PREFIX}.$PG->{ARRAY_PREFIX}."$number"."__"."$vecnum".":"."$row".":"."$col"."__"; 193 # my $response_group = new PGresponsegroup($label,undef); 194 # $PG->record_ans_name($array_ans_eval_label, $response_group); 195 # What does vecnum do? 196 # The name is simply so that it won't conflict when placed on the HTML page 197 # my $array_label = shift; 198 $PG->record_array_name($label); # returns $array_label, $ans_label 199 } 200 201 sub NEW_ANS_ARRAY_NAME_EXTENSION { 202 NEW_ANS_ARRAY_ELEMENT_NAME(@_); 203 } 204 205 sub NEW_ANS_ARRAY_ELEMENT_NAME { # creates a new array element answer name and records it 206 207 return "" if $PG_STOP_FLAG; 208 my $number=shift; 209 my $row_num = shift; 210 my $col_num = shift; 211 if( $row_num == 0 && $col_num == 0 ){ 212 $main::vecnum += 1; 213 } 214 # my $ans_label = "ArRaY".sprintf("%04u", $number); 215 my $ans_label = $PG->new_array_label($number); 216 my $element_ans_label = $PG->new_array_element_label($ans_label,$row_num, $col_num,vec_num=>$vecnum); 217 my $response = new PGresponsegroup($ans_label,$element_ans_label, undef); 218 $PG->extend_ans_group($ans_label,$response); 219 $element_ans_label; 220 } 221 sub NEW_LABELED_ANS_ARRAY { #not in PG_original 222 my $ans_label = shift; 223 my @response_list = @_; 224 #$PG->extend_ans_group($ans_label,@response_list); 225 $PG->{PG_ANSWERS_HASH}->{$ans_label}->insert_responses(@response_list); 226 # should this return an array of labeled answer blanks??? 227 } 228 sub EXTEND_ANS_ARRAY { #not in PG_original 229 my $ans_label = shift; 230 my @response_list = @_; 231 #$PG->extend_ans_group($ans_label,@response_list); 232 $PG->{PG_ANSWERS_HASH}->{$ans_label}->append_responses(@response_list); 233 } 234 sub CLEAR_RESPONSES { 235 my $ans_label = shift; 236 # my $response_label = shift; 237 # my $ans_value = shift; 238 if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) { 239 my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response}; 240 if ( ref($responsegroup) ) { 241 $responsegroup->clear; 242 } else { 243 $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response} = new PGresponsegroup($label); 244 } 245 } 246 ''; 247 } 248 sub INSERT_RESPONSE { 249 my $ans_label = shift; 250 my $response_label = shift; 251 my $ans_value = shift; 252 my $selected = shift; 253 # warn "\n\nanslabel $ans_label responselabel $response_label value $ans_value"; 254 if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) { 255 my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response}; 256 $responsegroup->append_response($response_label, $ans_value, $selected); 257 #warn "\n$responsegroup responses are now ", $responsegroup->responses; 258 } 259 ''; 260 } 261 262 sub EXTEND_RESPONSE { # for radio buttons and checkboxes 263 my $ans_label = shift; 264 my $response_label = shift; 265 my $ans_value = shift; 266 my $selected = shift; 267 # warn "\n\nanslabel $ans_label responselabel $response_label value $ans_value"; 268 if (defined ($PG->{PG_ANSWERS_HASH}->{$ans_label}) ) { 269 my $responsegroup = $PG->{PG_ANSWERS_HASH}->{$ans_label}->{response}; 270 $responsegroup->extend_response($response_label, $ans_value,$selected); 271 #warn "\n$responsegroup responses are now ", pretty_print($response_group); 272 } 273 ''; 274 } 275 sub ENDDOCUMENT { 276 # check that answers match 277 # gather up PG_FLAGS elements 278 279 $PG->{flags}->{showPartialCorrectAnswers} = defined($showPartialCorrectAnswers)? $showPartialCorrectAnswers : 1 ; 280 $PG->{flags}->{recordSubmittedAnswers} = defined($recordSubmittedAnswers)? $recordSubmittedAnswers : 1 ; 281 $PG->{flags}->{refreshCachedImages} = defined($refreshCachedImages)? $refreshCachedImages : 0 ; 282 $PG->{flags}->{hintExists} = defined($hintExists)? $hintExists : 0 ; 283 $PG->{flags}->{solutionExists} = defined($solutionExists)? $solutionExists : 0 ; 284 $PG->{flags}->{comment} = defined($pgComment)? $pgComment :'' ; 285 $PG->{flags}->{showHintLimit} = defined($showHint)? $showHint : 0 ; 286 287 288 # install problem grader 289 if (defined($PG->{flags}->{PROBLEM_GRADER_TO_USE}) ) { 290 # problem grader defined within problem -- no further action needed 291 } elsif ( defined( $rh_envir->{PROBLEM_GRADER_TO_USE} ) ) { 292 if (ref($rh_envir->{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) { # user defined grader 293 $PG->{flags}->{PROBLEM_GRADER_TO_USE} = $rh_envir->{PROBLEM_GRADER_TO_USE}; 294 } elsif ($rh_envir->{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) { 295 if (defined(&std_problem_grader) ){ 296 $PG->{flags}->{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl 297 } # std_problem_grader is the default in any case so don't give a warning. 298 } elsif ($rh_envir->{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) { 299 if (defined(&avg_problem_grader) ){ 300 $PG->{flags}->{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl 301 } 302 } else { 303 warn "Error: ". $PG->{flags}->{PROBLEM_GRADER_TO_USE} . "is not a known program grader."; 304 } 305 } elsif (defined(&std_problem_grader)) { 306 $PG->{flags}->{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl 307 } else { 308 # PGtranslator will install its default problem grader 309 } 310 311 # add javaScripts 312 if ($rh_envir->{displayMode} eq 'HTML_jsMath') { 313 TEXT('<SCRIPT> jsMath.wwProcess() </SCRIPT>'); 314 } elsif ($rh_envir->{displayMode} eq 'HTML_asciimath') { 315 TEXT('<SCRIPT> translate() </SCRIPT>'); 316 my $STRING = join("", @{$PG->{HEADER_ARRAY} }); 317 unless ($STRING =~ m/mathplayer/) { 318 HEADER_TEXT('<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n" . 319 '</object><?import namespace="mml" implementation="#mathplayer"?>' 320 ); 321 } 322 323 } 324 TEXT( MODES(%{$rh_envir->{problemPostamble}}) ); 325 326 327 328 329 330 @PG_ANSWERS=(); 331 332 #warn keys %{ $PG->{PG_ANSWERS_HASH} }; 333 @PG_ANSWER_ENTRY_ORDER = (); 334 my $ans_debug = 0; 335 foreach my $key (keys %{ $PG->{PG_ANSWERS_HASH} }) { 336 $answergroup = $PG->{PG_ANSWERS_HASH}->{$key}; 337 #warn "$key is defined =", defined($answergroup), "PG object is $PG"; 338 ################# 339 # EXTRA ANSWERS KLUDGE 340 ################# 341 # The first response in each answer group is placed in @PG_ANSER_ENTRY_ORDER and %PG_ANSWERS_HASH 342 # The remainder of the response keys are placed in the EXTRA ANSWERS ARRAY 343 if (defined($answergroup)) { 344 my @response_keys = $answergroup->{response}->response_labels; 345 warn pretty_print($answergroup->{response}) if $ans_debug==1; 346 my $response_key = shift @response_keys; 347 #unshift @response_keys, $response_key unless ($response_key eq $answer_group->{ans_label}); 348 # don't save the first response key if it is the same as the ans_label 349 # maybe we should insure that the first response key is always the same as the answer label? 350 # even if no answer blank is printed for it? or a hidden answer blank? 351 # this is still a KLUDGE 352 # for compatibility the first response key is closer to the old method than the $ans_label 353 # this is because a response key might indicate an array but an answer label won't 354 push @PG_ANSWERS, $response_key,$answergroup->{ans_eval}; 355 push @PG_ANSWER_ENTRY_ORDER, $response_key; 356 push @KEPT_EXTRA_ANSWERS, @response_keys; 357 } else { 358 #warn "$key is ", join("|",%{$PG->{PG_ANSWERS_HASH}->{$key}}); 359 } 360 } 361 push @KEPT_EXTRA_ANSWERS, keys %{$PG->{PERSISTENCE_HASH}}; 362 my %PG_ANSWERS_HASH = @PG_ANSWERS; 363 $PG->{flags}->{KEPT_EXTRA_ANSWERS} = \@KEPT_EXTRA_ANSWERS; 364 $PG->{flags}->{ANSWER_ENTRY_ORDER} = \@PG_ANSWER_ENTRY_ORDER; 365 warn "KEPT_EXTRA_ANSWERS", join(" ", @KEPT_EXTRA_ANSWERS), $BR if $ans_debug==1; 366 warn "PG_ANSWER_ENTRY_ORDER",join(" ",@PG_ANSWER_ENTRY_ORDER), $BR if $ans_debug==1; 367 warn "DEBUG messages", join( "$BR",@{$PG->get_debug_messages} ) if $ans_debug==1; 368 warn "INTERNAL_DEBUG messages", join( "$BR",@{$PG->get_internal_debug_messages} ) if $ans_debug==1; 369 $STRINGforOUTPUT = join("", @{$PG->{OUTPUT_ARRAY} }); 370 371 372 $STRINGforHEADER_TEXT = join("", @{$PG->{HEADER_ARRAY} }); 373 374 # warn pretty_print($PG->{PG_ANSWERS_HASH}); 375 #warn "printing another warning"; 376 377 (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH, $PG->{flags} , $PG ); 378 } 379 ################################################################################ 380 # 381 # macros from dangerousMacros 382 # 383 ################################################################################ 384 sub alias { 385 #warn "alias called ",@_; 386 $PG->{PG_alias}->make_alias(@_) ; 387 } 388 sub insertGraph { 389 $PG->insertGraph(@_); 390 } 391 392 sub findMacroFile { 393 $PG->{PG_alias}->findMacroFile(@_); 394 } 395 sub check_url { 396 $PG->{PG_alias}->check_url(@_); 397 } 398 sub findAppletCodebase { 399 my $appletName = shift; 400 my $url = eval{$PG->{PG_alias}->findAppletCodebase($appletName)}; 401 # warn is already trapped under the old system 402 $PG->warning_message("While using findAppletCodebase to search for applet$appletName: $@") if $@; 403 $url; 404 } 405 406 sub loadMacros { 407 $PG->{PG_loadMacros}->loadMacros(@_); 408 } 409 # FIXME? these were taken from the former dangerousMacros.pl file and might have issues when placed here. 410 # 411 # Some constants that can be used in perl expressions 412 # 413 414 # ^function i 415 # ^uses $_parser_loaded 416 # ^uses &Complex::i 417 # ^uses &Value::Package 418 sub i () { 419 # check if Parser.pl is loaded, otherwise use Complex package 420 if (!eval(q!$main::_parser_loaded!)) {return Complex::i} 421 return Value->Package("Formula")->new('i')->eval; 422 } 423 424 # ^function j 425 # ^uses $_parser_loaded 426 # ^uses &Value::Package 427 sub j () { 428 if (!eval(q!$main::_parser_loaded!)) {return 'j'} 429 Value->Package("Formula")->new('j')->eval; 430 } 431 432 # ^function k 433 # ^uses $_parser_loaded 434 # ^uses &Value::Package 435 sub k () { 436 if (!eval(q!$main::_parser_loaded!)) {return 'k'} 437 Value->Package("Formula")->new('k')->eval; 438 } 439 440 # ^function pi 441 # ^uses &Value::Package 442 sub pi () {Value->Package("Formula")->new('pi')->eval} 443 444 # ^function Infinity 445 # ^uses &Value::Package 446 sub Infinity () {Value->Package("Infinity")->new()} 447 448 449 # ^function abs 450 # ^function sqrt 451 # ^function exp 452 # ^function log 453 # ^function sin 454 # ^function cos 455 # ^function atan2 456 # 457 # Allow these functions to be overridden 458 # (needed for log() to implement $useBaseTenLog) 459 # 460 use subs 'abs', 'sqrt', 'exp', 'log', 'sin', 'cos', 'atan2'; 461 sub abs($) {return CORE::abs($_[0])}; 462 sub sqrt($) {return CORE::sqrt($_[0])}; 463 sub exp($) {return CORE::exp($_[0])}; 464 sub log($) {return CORE::log($_[0])}; 465 sub sin($) {return CORE::sin($_[0])}; 466 sub cos($) {return CORE::cos($_[0])}; 467 sub atan2($$) {return CORE::atan2($_[0],$_[1])}; 468 469 sub Parser::defineLog {eval {sub log($) {CommonFunction->Call("log",@_)}}}; 470 =head2 Filter utilities 471 472 These two subroutines can be used in filters to set default options. They 473 help make filters perform in uniform, predictable ways, and also make it 474 easy to recognize from the code which options a given filter expects. 475 476 477 =head4 assign_option_aliases 478 479 Use this to assign aliases for the standard options. It must come before set_default_options 480 within the subroutine. 481 482 assign_option_aliases(\%options, 483 'alias1' => 'option5' 484 'alias2' => 'option7' 485 ); 486 487 488 If the subroutine is called with an option " alias1 => 23 " it will behave as if it had been 489 called with the option " option5 => 23 " 490 491 =cut 492 493 494 # ^function assign_option_aliases 495 sub assign_option_aliases { 496 my $rh_options = shift; 497 warn "The first entry to set_default_options must be a reference to the option hash" unless ref($rh_options) eq 'HASH'; 498 my @option_aliases = @_; 499 while (@option_aliases) { 500 my $alias = shift @option_aliases; 501 my $option_key = shift @option_aliases; 502 503 if (defined($rh_options->{$alias} )) { # if the alias appears in the option list 504 if (not defined($rh_options->{$option_key}) ) { # and the option itself is not defined, 505 $rh_options->{$option_key} = $rh_options->{$alias}; # insert the value defined by the alias into the option value 506 # the FIRST alias for a given option takes precedence 507 # (after the option itself) 508 } else { 509 warn "option $option_key is already defined as", $rh_options->{$option_key}, "<br>\n", 510 "The attempt to override this option with the alias $alias with value ", $rh_options->{$alias}, 511 " was ignored."; 512 } 513 } 514 delete($rh_options->{$alias}); # remove the alias from the initial list 515 } 516 517 } 518 519 =head4 set_default_options 520 521 set_default_options(\%options, 522 '_filter_name' => 'filter', 523 'option5' => .0001, 524 'option7' => 'ascii', 525 'allow_unknown_options => 0, 526 } 527 528 Note that the first entry is a reference to the options with which the filter was called. 529 530 The option5 is set to .0001 unless the option is explicitly set when the subroutine is called. 531 532 The B<'_filter_name'> option should always be set, although there is no error if it is missing. 533 It is used mainly for debugging answer evaluators and allows 534 you to keep track of which filter is currently processing the answer. 535 536 If B<'allow_unknown_options'> is set to 0 then if the filter is called with options which do NOT appear in the 537 set_default_options list an error will be signaled and a warning message will be printed out. This provides 538 error checking against misspelling an option and is generally what is desired for most filters. 539 540 Occasionally one wants to write a filter which accepts a long list of options, not all of which are known in advance, 541 but only uses a subset of the options 542 provided. In this case, setting 'allow_unkown_options' to 1 prevents the error from being signaled. 543 544 =cut 545 546 # ^function set_default_options 547 # ^uses pretty_print 548 sub set_default_options { 549 my $rh_options = shift; 550 warn "The first entry to set_default_options must be a reference to the option hash" unless ref($rh_options) eq 'HASH'; 551 my %default_options = @_; 552 unless ( defined($default_options{allow_unknown_options}) and $default_options{allow_unknown_options} == 1 ) { 553 foreach my $key1 (keys %$rh_options) { 554 warn "This option |$key1| is not recognized in this subroutine<br> ", pretty_print($rh_options) unless exists($default_options{$key1}); 555 } 556 } 557 foreach my $key (keys %default_options) { 558 if ( not defined($rh_options->{$key} ) and defined( $default_options{$key} ) ) { 559 $rh_options->{$key} = $default_options{$key}; #this allows tol => undef to allow the tol option, but doesn't define 560 # this key unless tol is explicitly defined. 561 } 562 } 563 } 564 1; 565 __END__ 566 567 ################################################################################ 568 # WeBWorK Online Homework Delivery System 569 # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ 570 # $CVSHeader: pg/macros/PG.pl,v 1.46 2010/05/27 02:22:51 gage Exp $ 571 # 572 # This program is free software; you can redistribute it and/or modify it under 573 # the terms of either: (a) the GNU General Public License as published by the 574 # Free Software Foundation; either version 2, or (at your option) any later 575 # version, or (b) the "Artistic License" which comes with this package. 576 # 577 # This program is distributed in the hope that it will be useful, but WITHOUT 578 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 579 # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the 580 # Artistic License for more details. 581 ################################################################################ 582 583 =head1 NAME 584 585 PG.pl - Provides core Program Generation Language functionality. 586 587 =head1 SYNPOSIS 588 589 In a PG problem: 590 591 DOCUMENT(); # should be the first statment in the problem 592 593 loadMacros(.....); # (optional) load other macro files if needed. 594 # (loadMacros is defined in F<dangerousMacros.pl>) 595 596 HEADER_TEXT(...); # (optional) used only for inserting javaScript into problems. 597 598 TEXT( # insert text of problems 599 "Problem text to be displayed. ", 600 "Enter 1 in this blank:", 601 ANS_RULE(1,30) # ANS_RULE() defines an answer blank 30 characters long. 602 # It is defined in F<PGbasicmacros.pl> 603 ); 604 605 ANS(answer_evalutors); # see F<PGanswermacros.pl> for examples of answer evaluatiors. 606 607 ENDDOCUMENT() # must be the last statement in the problem 608 609 =head1 DESCRIPTION 610 611 This file provides the fundamental macros that define the PG language. It 612 maintains a problem's text, header text, and answers: 613 614 =over 615 616 =item * 617 618 Problem text: The text to appear in the body of the problem. See TEXT() 619 below. 620 621 =item * 622 623 Header text: When a problem is processed in an HTML-based display mode, 624 this variable can contain text that the caller should place in the HEAD of the 625 resulting HTML page. See HEADER_TEXT() below. 626 627 =item * 628 629 Implicitly-labeled answers: Answers that have not been explicitly 630 assigned names, and are associated with their answer blanks by the order in 631 which they appear in the problem. These types of answers are designated using 632 the ANS() macro. 633 634 =item * 635 636 Explicitly-labeled answers: Answers that have been explicitly assigned 637 names with the LABELED_ANS() macro, or a macro that uses it. An explicitly- 638 labeled answer is associated with its answer blank by name. 639 640 =item * 641 642 "Extra" answers: Names of answer blanks that do not have a 1-to-1 643 correspondance to an answer evaluator. For example, in matrix problems, there 644 will be several input fields that correspond to the same answer evaluator. 645 646 =back 647 648 =head1 USAGE 649 650 This file is automatically loaded into the namespace of every PG problem. The 651 macros within can then be called to define the structure of the problem. 652 653 DOCUMENT() should be the first executable statement in any problem. It 654 initializes vriables and defines the problem environment. 655 656 ENDDOCUMENT() must be the last executable statement in any problem. It packs 657 up the results of problem processing for delivery back to WeBWorK. 658 659 The HEADER_TEXT(), TEXT(), and ANS() macros add to the header text string, 660 body text string, and answer evaluator queue, respectively. 661 662 =over 663 664 =item HEADER_TEXT() 665 666 HEADER_TEXT("string1", "string2", "string3"); 667 668 HEADER_TEXT() concatenates its arguments and appends them to the stored header 669 text string. It can be used more than once in a file. 670 671 The macro is used for material which is destined to be placed in the HEAD of 672 the page when in HTML mode, such as JavaScript code. 673 674 Spaces are placed between the arguments during concatenation, but no spaces are 675 introduced between the existing content of the header text string and the new 676 content being appended. 677 678 679 680 =item TEXT() 681 682 TEXT("string1", "string2", "string3"); 683 684 TEXT() concatenates its arguments and appends them to the stored problem text 685 string. It is used to define the text which will appear in the body of the 686 problem. It can be used more than once in a file. 687 688 This macro has no effect if rendering has been stopped with the STOP_RENDERING() 689 macro. 690 691 This macro defines text which will appear in the problem. All text must be 692 passed to this macro, passed to another macro that calls this macro, or included 693 in a BEGIN_TEXT/END_TEXT block, which uses this macro internally. No other 694 statements in a PG file will directly appear in the output. Think of this as the 695 "print" function for the PG language. 696 697 Spaces are placed between the arguments during concatenation, but no spaces are 698 introduced between the existing content of the header text string and the new 699 content being appended. 700 701 702 703 =item ANS() 704 705 TEXT(ans_rule(), ans_rule(), ans_rule()); 706 ANS($answer_evaluator1, $answer_evaluator2, $answer_evaluator3); 707 708 Adds the answer evaluators listed to the list of unlabeled answer evaluators. 709 They will be paired with unlabeled answer rules (a.k.a. answer blanks) in the 710 order entered. This is the standard method for entering answers. 711 712 In the above example, answer_evaluator1 will be associated with the first 713 answer rule, answer_evaluator2 with the second, and answer_evaluator3 with the 714 third. In practice, the arguments to ANS() will usually be calls to an answer 715 evaluator generator such as the cmp() method of MathObjects or the num_cmp() 716 macro in L<PGanswermacros.pl>. 717 718 719 720 =item LABELED_ANS() 721 722 TEXT(labeled_ans_rule("name1"), labeled_ans_rule("name2")); 723 LABELED_ANS(name1 => answer_evaluator1, name2 => answer_evaluator2); 724 725 Adds the answer evaluators listed to the list of labeled answer evaluators. 726 They will be paired with labeled answer rules (a.k.a. answer blanks) in the 727 order entered. This allows pairing of answer evaluators and answer rules that 728 may not have been entered in the same order. 729 730 731 732 733 =item STOP_RENDERING() 734 735 STOP_RENDERING() unless all_answers_are_correct(); 736 737 Temporarily suspends accumulation of problem text and storing of answer blanks 738 and answer evaluators until RESUME_RENDERING() is called. 739 740 741 742 =item RESUME_RENDERING() 743 744 RESUME_RENDERING(); 745 746 Resumes accumulating problem text and storing answer blanks and answer 747 evaluators. Reverses the effect of STOP_RENDERING(). 748 749 750 751 =item ENDDOCUMENT() 752 753 ENDDOCUMENT(); 754 755 When PG problems are evaluated, the result of evaluating the entire problem is 756 interpreted as the return value of ENDDOCUMENT(). Therefore, ENDDOCUMENT() must 757 be the last executable statement of every problem. It can only appear once. It 758 returns a list consisting of: 759 760 761 762 763 =item * 764 765 A reference to a string containing the rendered text of the problem. 766 767 =item * 768 769 A reference to a string containing text to be placed in the HEAD block 770 when in and HTML-based mode (e.g. for JavaScript). 771 772 =item * 773 774 A reference to the hash mapping answer labels to answer evaluators. 775 776 =item * 777 778 A reference to a hash containing various flags: 779 780 781 782 =item * 783 784 C<showPartialCorrectAnswers>: determines whether students are told which of their answers in a problem are wrong. 785 786 =item * 787 788 C<recordSubmittedAnswers>: determines whether students submitted answers are saved. 789 790 =item * 791 792 C<refreshCachedImages>: determines whether the cached image of the problem in typeset mode is always refreshed 793 (i.e. setting this to 1 means cached images are not used). 794 795 =item * 796 797 C<solutionExits>: indicates the existence of a solution. 798 799 =item * 800 801 C<hintExits>: indicates the existence of a hint. 802 803 =item * 804 805 C<comment>: contents of COMMENT commands if any. 806 807 =item * 808 809 C<showHintLimit>: determines the number of attempts after which hint(s) will be shown 810 811 =item * 812 813 C<PROBLEM_GRADER_TO_USE>: a reference to the chosen problem grader. 814 ENDDOCUMENT chooses the problem grader as follows: 815 816 =over 817 818 =item * 819 820 If a problem grader has been chosen in the problem by calling 821 C<install_problem_grader(\&grader)>, it is used. 822 823 =item * 824 825 Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable 826 contains a reference to a subroutine, it is used. 827 828 =item * 829 830 Otherwise, if the C<PROBLEM_GRADER_TO_USE> PG environment variable 831 contains the string C<std_problem_grader> or the string C<avg_problem_grader>, 832 C<&std_problem_grader> or C<&avg_problem_grader> are used. These graders are defined 833 in L<PGanswermacros.pl>. 834 835 =item * 836 837 Otherwise, the PROBLEM_GRADER_TO_USE flag will contain an empty value 838 and the PG translator should select C<&std_problem_grader>. 839 840 =back 841 842 =back 843 844 845 846 =cut 847 848 849 ################################################################################ 850 851 =head1 PRIVATE MACROS 852 853 These macros should only be used by other macro files. In practice, they are 854 used exclusively by L<PGbasicmacros.pl>. 855 856 =over 857 858 =item inc_ans_rule_count() 859 860 NEW_ANS_NAME(); 861 862 Increments the internal count of the number of answer blanks that have been 863 defined ($ans_rule_count) and returns the new count. This should only be used 864 when one is about to define a new answer blank, for example with NEW_ANS_NAME(). 865 866 =cut 867 868 =item RECORD_ANS_NAME() 869 870 RECORD_ANS_NAME("label", "VALUE"); 871 872 Records the label for an answer blank. Used internally by L<PGbasicmacros.pl> 873 to record the order of explicitly-labelled answer blanks. 874 875 =cut 876 877 =item NEW_ANS_NAME() 878 879 NEW_ANS_NAME(); 880 881 Generates an anonymous answer label from the internal count The label is 882 added to the list of implicity-labeled answers. Used internally by 883 L<PGbasicmacros.pl> to generate labels for unlabeled answer blanks. 884 885 =cut 886 887 =item ANS_NUM_TO_NAME() 888 889 ANS_NUM_TO_NAME($num); 890 891 Generates an answer label from the supplied answer number, but does not add it 892 to the list of inplicitly-labeled answers. Used internally by 893 L<PGbasicmacros.pl> in generating answers blanks that use radio buttons or 894 check boxes. (This type of answer blank uses multiple HTML INPUT elements with 895 the same label, but the label should only be added to the list of implicitly- 896 labeled answers once.) 897 898 =cut 899 900 =item RECORD_FROM_LABEL() 901 902 RECORD_FORM_LABEL("label"); 903 904 Stores the label of a form field in the "extra" answers list. This is used to 905 keep track of answer blanks that are not associated with an answer evaluator. 906 907 =cut 908 909 =item NEW_ANS_ARRAY_NAME() 910 911 NEW_ANS_ARRAY_NAME($num, $row, $col); 912 913 Generates a new answer label for an array (vector) element and adds it to the 914 list of implicitly-labeled answers. 915 916 =cut 917 918 =item NEW_ANS_ARRAY_NAME_EXTENSION() 919 920 NEW_ANS_ARRAY_NAME_EXTENSION($num, $row, $col); 921 922 Generate an additional answer label for an existing array (vector) element and 923 add it to the list of "extra" answers. 924 925 =cut 926 927 =item get_PG_ANSWERS_HASH() 928 929 get_PG_ANSWERS_HASH(); 930 get_PG_ANSWERS_HASH($key); 931 932 933 934 =cut 935 936 =item includePGproblem($filePath) 937 938 includePGproblem($filePath); 939 940 Essentially runs the pg problem specified by $filePath, which is 941 a path relative to the top of the templates directory. The output 942 of that problem appears in the given problem. 943 944 =cut 945 946 =back 947 948 =head1 SEE ALSO 949 950 L<PGbasicmacros.pl>, L<PGanswermacros.pl>. 951 952 =cut 953 954 955 956 957 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |