Parent Directory
|
Revision Log
removed unneeded arguments from calls to ImageGenerator
1 ################################################################################ 2 # WeBWorK mod_perl (c) 2000-2002 WeBWorK Project 3 # $Id$ 4 ################################################################################ 5 6 package WeBWorK::PG::Local; 7 8 =head1 NAME 9 10 WeBWorK::PG::Local - Use the WeBWorK::PG API to invoke a local 11 WeBWorK::PG::Translator object. 12 13 =head1 DESCRIPTION 14 15 WeBWorK::PG::Local encapsulates the PG translation process, making multiple 16 calls to WeBWorK::PG::Translator. Much of the flexibility of the Translator is 17 hidden, instead making choices that are appropriate for the webwork-modperl 18 system 19 20 It implements the WeBWorK::PG interface and uses a local 21 WeBWorK::PG::Translator to perform problem rendering. See the documentation for 22 the WeBWorK::PG module for information about the API. 23 24 =cut 25 26 use strict; 27 use warnings; 28 use File::Path qw(rmtree); 29 use WeBWorK::PG::ImageGenerator; 30 use WeBWorK::PG::Translator; 31 use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry makeTempDirectory); 32 BEGIN { 33 34 # This safe compartment is used to read the large macro files such as 35 # PG.pl, PGbasicmacros.pl and PGanswermacros and cache the results so that 36 # future calls have preloaded versions of these large files. 37 # This saves a significant amount of time. 38 39 $WeBWorK::PG::Local::safeCache = new Safe; 40 # warn "Creating new Safe cache compartment ".$WeBWorK::PG::Local::safeCache->root; 41 } 42 sub new { 43 my $invocant = shift; 44 my $class = ref($invocant) || $invocant; 45 my ( 46 $ce, 47 $user, 48 $key, 49 $set, 50 $problem, 51 $psvn, 52 $formFields, # in CGI::Vars format 53 $translationOptions, # hashref containing options for the 54 # translator, such as whether to show 55 # hints and the display mode to use 56 ) = @_; 57 58 # write timing log entry 59 writeTimingLogEntry($ce, "WeBWorK::PG::new", 60 "user=".$user->user_id.",problem=".$ce->{courseName}."/".$set->set_id."/".$problem->problem_id.",mode=".$translationOptions->{displayMode}, 61 "begin"); 62 63 # install a local warn handler to collect warnings 64 my $warnings = ""; 65 local $SIG{__WARN__} = sub { $warnings .= shift } 66 if $ce->{pg}->{options}->{catchWarnings}; 67 68 # create a Translator 69 #warn "PG: creating a Translator\n"; 70 my $translator = WeBWorK::PG::Translator->new; 71 72 # set the directory hash 73 #warn "PG: setting the directory hash\n"; 74 $translator->rh_directories({ 75 courseScriptsDirectory => $ce->{pg}->{directories}->{macros}, 76 macroDirectory => $ce->{courseDirs}->{macros}, 77 templateDirectory => $ce->{courseDirs}->{templates}, 78 tempDirectory => $ce->{courseDirs}->{html_temp}, 79 }); 80 81 # evaluate modules and "extra packages" 82 #warn "PG: evaluating modules and \"extra packages\"\n"; 83 my @modules = @{ $ce->{pg}->{modules} }; 84 foreach my $module_packages_ref (@modules) { 85 my ($module, @extra_packages) = @$module_packages_ref; 86 # the first item is the main package 87 $translator->evaluate_modules($module); 88 # the remaining items are "extra" packages 89 $translator->load_extra_packages(@extra_packages); 90 } 91 92 # set the environment (from defineProblemEnvir) 93 #warn "PG: setting the environment (from defineProblemEnvir)\n"; 94 my $envir = defineProblemEnvir( 95 $ce, 96 $user, 97 $key, 98 $set, 99 $problem, 100 $psvn, 101 $formFields, 102 $translationOptions, 103 ); 104 $translator->environment($envir); 105 106 # initialize the Translator 107 #warn "PG: initializing the Translator\n"; 108 $translator->initialize(); 109 # $translator->dumpSafe; # debugging code 110 ############################################################################### 111 # Preload the macros files which are used routinely: PG.pl, dangerousMacros.pl, IO.pl 112 # PGbasicmacros.pl and PGanswermacros.pl 113 # Preloading the last two files safes a significant amount of time. 114 ############################################################################### 115 116 # IO.pl, PG.pl, and dangerousMacros.pl are loaded using unrestricted_load 117 # This is hard wired into the Translator::pre_load_macro_files subroutine 118 # I'd like to change this at some point to have the same sort of interface to global.conf 119 # that the module loading does -- have a list of macros to load unrestrictedly. 120 121 # This has been replaced by the pre_load_macro_files subroutine. It loads AND caches the files. 122 # While PG.pl and dangerousMacros are not large, they are referred to by PGbasicmacros and PGanswermacros. 123 # Because these are loaded into the cached name space (e.g. Safe::Root1::) all calls to, say NEW_ANSWER_NAME 124 # are actually calls to Safe::Root1::NEW_ANSWER_NAME. It is useful to have these names inside the Safe::Root1: 125 # cached safe compartment. (NEW_ANSWER_NAME and all other subroutine names are also automatically exported into 126 # the current safe compartment Safe::Rootx:: 127 128 # The headers of both PGbasicmacros and PGanswermacros has code that insures that the constants used are imported into 129 # the current safe compartment. This involves evaluating references to, say $main::displayMode, at runtime to insure that main 130 # refers to Safe::Rootx:: and NOT to Safe::Root1::, which is the value of main:: at compile time. 131 132 133 ############################################################################### 134 # TO ENABLE CACHEING UNCOMMENT THE CACHEING CODE 135 # On webwork3 cached code is .2 seconds faster than non-cached code for an existing child. 136 137 # CACHING CODE: 138 eval{ 139 $translator->pre_load_macro_files($WeBWorK::PG::Local::safeCache, $ce->{pg}->{directories}->{macros}, 140 'PG.pl', 'dangerousMacros.pl','IO.pl','PGbasicmacros.pl','PGanswermacros.pl');}; 141 warn "Error while preloading macro files: $@" if $@; 142 143 # STANDARD LOADING CODE: for cached script files this merely initializes the constants. 144 foreach (qw( PG.pl dangerousMacros.pl IO.pl)) { 145 my $macroPath = $ce->{pg}->{directories}->{macros} . "/$_"; 146 my $err = $translator->unrestricted_load($macroPath); 147 warn "Error while loading $macroPath: |$err|" if $err; 148 } 149 ############################################################################### 150 151 # set the opcode mask (using default values) 152 #warn "PG: setting the opcode mask (using default values)\n"; 153 $translator->set_mask(); 154 155 # store the problem source 156 #warn "PG: storing the problem source\n"; 157 my $sourceFile = $problem->source_file; 158 $sourceFile = $ce->{courseDirs}->{templates}."/".$sourceFile 159 unless ($sourceFile =~ /^\//); 160 eval { $translator->source_string(readFile($sourceFile)) }; 161 if ($@) { 162 # well, we couldn't get the problem source, for some reason. 163 return bless { 164 translator => $translator, 165 head_text => "", 166 body_text => <<EOF, 167 WeBWorK::Utils::readFile($sourceFile) says: 168 $@ 169 EOF 170 answers => {}, 171 result => {}, 172 state => {}, 173 errors => "Failed to read the problem source file.", 174 warnings => $warnings, 175 flags => {error_flag => 1}, 176 }, $class; 177 } 178 179 # install a safety filter (&safetyFilter) 180 #warn "PG: installing a safety filter\n"; 181 $translator->rf_safety_filter(\&safetyFilter); 182 183 # write timing log entry -- the translator is now all set up 184 writeTimingLogEntry($ce, "WeBWorK::PG::new", 185 "initialized", 186 "intermediate"); 187 188 # translate the PG source into text 189 #warn "PG: translating the PG source into text\n"; 190 $translator->translate(); 191 192 # after we're done translating, we may have to clean up after the 193 # translator: 194 195 # for example, HTML_img mode uses a tempdir for dvipng's temp files.\ 196 # We have to remove it. 197 if ($envir->{dvipngTempDir}) { 198 rmtree($envir->{dvipngTempDir}, 0, 0); 199 } 200 201 # HTML_dpng, on the other hand, uses an ImageGenerator. We have to 202 # render the queued equations. 203 if ($envir->{imagegen}) { 204 my $sourceFile = $ce->{courseDirs}->{templates} . "/" . $problem->source_file; 205 my %mtimeOption = -e $sourceFile 206 ? (mtime => (stat $sourceFile)[9]) 207 : (); 208 209 $envir->{imagegen}->render( 210 refresh => $translationOptions->{refreshMath2img}, 211 %mtimeOption, 212 ); 213 } 214 215 my ($result, $state); # we'll need these on the other side of the if block! 216 if ($translationOptions->{processAnswers}) { 217 218 # process student answers 219 #warn "PG: processing student answers\n"; 220 $translator->process_answers($formFields); 221 222 # retrieve the problem state and give it to the translator 223 #warn "PG: retrieving the problem state and giving it to the translator\n"; 224 $translator->rh_problem_state({ 225 recorded_score => $problem->status, 226 num_of_correct_ans => $problem->num_correct, 227 num_of_incorrect_ans => $problem->num_incorrect, 228 }); 229 230 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by 231 # the PG macro package (PG.pl) 232 #warn "PG: determining an entry order\n"; 233 my @answerOrder = 234 $translator->rh_flags->{ANSWER_ENTRY_ORDER} 235 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} } 236 : keys %{ $translator->rh_evaluated_answers }; 237 238 # install a grader -- use the one specified in the problem, 239 # or fall back on the default from the course environment. 240 # (two magic strings are accepted, to avoid having to 241 # reference code when it would be difficult.) 242 #warn "PG: installing a grader\n"; 243 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE} 244 || $ce->{pg}->{options}->{grader}; 245 $grader = $translator->rf_std_problem_grader 246 if $grader eq "std_problem_grader"; 247 $grader = $translator->rf_avg_problem_grader 248 if $grader eq "avg_problem_grader"; 249 die "Problem grader $grader is not a CODE reference." 250 unless ref $grader eq "CODE"; 251 $translator->rf_problem_grader($grader); 252 253 # grade the problem 254 #warn "PG: grading the problem\n"; 255 ($result, $state) = $translator->grade_problem( 256 answers_submitted => $translationOptions->{processAnswers}, 257 ANSWER_ENTRY_ORDER => \@answerOrder, 258 ); 259 260 } 261 262 # write timing log entry 263 writeTimingLogEntry($ce, "WeBWorK::PG::new", "", "end"); 264 265 # return an object which contains the translator and the results of 266 # the translation process. this is DIFFERENT from the "format expected 267 # by Webwork.pm (and I believe processProblem8, but check.)" 268 return bless { 269 translator => $translator, 270 head_text => ${ $translator->r_header }, 271 body_text => ${ $translator->r_text }, 272 answers => $translator->rh_evaluated_answers, 273 result => $result, 274 state => $state, 275 errors => $translator->errors, 276 warnings => $warnings, 277 flags => $translator->rh_flags, 278 }, $class; 279 } 280 281 # ----- 282 283 sub defineProblemEnvir { 284 my ( 285 $ce, 286 $user, 287 $key, 288 $set, 289 $problem, 290 $psvn, 291 $formFields, 292 $options, 293 ) = @_; 294 295 my %envir; 296 297 # ---------------------------------------------------------------------- 298 299 # PG environment variables 300 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 301 # any changes are noted by "ADDED:" or "REMOVED:" 302 303 # Vital state information 304 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img, 305 # texDisposition 306 307 $envir{psvn} = $set->psvn; 308 $envir{psvnNumber} = $envir{psvn}; 309 $envir{probNum} = $problem->problem_id; 310 $envir{questionNumber} = $envir{probNum}; 311 $envir{fileName} = $problem->source_file; 312 $envir{probFileName} = $envir{fileName}; 313 $envir{problemSeed} = $problem->problem_seed; 314 $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); 315 $envir{languageMode} = $envir{displayMode}; 316 $envir{outputMode} = $envir{displayMode}; 317 $envir{displayHintsQ} = $options->{showHints}; 318 $envir{displaySolutionsQ} = $options->{showSolutions}; 319 # FIXME: this is HTML_img specific 320 #$envir{refreshMath2img} = $options->{refreshMath2img}; 321 $envir{texDisposition} = "pdf"; # in webwork-modperl, we use pdflatex 322 323 # Problem Information 324 # ADDED: courseName, formatedDueDate 325 326 $envir{openDate} = $set->open_date; 327 $envir{formattedOpenDate} = formatDateTime($envir{openDate}); 328 $envir{dueDate} = $set->due_date; 329 $envir{formattedDueDate} = formatDateTime($envir{dueDate}); 330 $envir{formatedDueDate} = $envir{formattedDueDate}; # typo in many header files 331 $envir{answerDate} = $set->answer_date; 332 $envir{formattedAnswerDate} = formatDateTime($envir{answerDate}); 333 $envir{numOfAttempts} = ($problem->num_correct || 0) + ($problem->num_incorrect || 0); 334 $envir{problemValue} = $problem->value; 335 $envir{sessionKey} = $key; 336 $envir{courseName} = $ce->{courseName}; 337 338 # Student Information 339 # ADDED: studentID 340 341 $envir{sectionName} = $user->section; 342 $envir{sectionNumber} = $envir{sectionName}; 343 $envir{recitationName} = $user->recitation; 344 $envir{recitationNumber} = $envir{recitationName}; 345 $envir{setNumber} = $set->set_id; 346 $envir{studentLogin} = $user->user_id; 347 $envir{studentName} = $user->first_name . " " . $user->last_name; 348 $envir{studentID} = $user->student_id; 349 350 # Answer Information 351 # REMOVED: refSubmittedAnswers 352 353 $envir{inputs_ref} = $formFields; 354 355 # External Programs 356 # ADDED: externalLaTeXPath, externalDvipngPath, 357 # externalGif2EpsPath, externalPng2EpsPath 358 359 $envir{externalTTHPath} = $ce->{externalPrograms}->{tth}; 360 $envir{externalLaTeXPath} = $ce->{externalPrograms}->{latex}; 361 $envir{externalDvipngPath} = $ce->{externalPrograms}->{dvipng}; 362 $envir{externalGif2EpsPath} = $ce->{externalPrograms}->{gif2eps}; 363 $envir{externalPng2EpsPath} = $ce->{externalPrograms}->{png2eps}; 364 $envir{externalGif2PngPath} = $ce->{externalPrograms}->{gif2png}; 365 366 # Directories and URLs 367 # REMOVED: courseName 368 # ADDED: dvipngTempDir 369 370 $envir{cgiDirectory} = undef; 371 $envir{cgiURL} = undef; 372 $envir{classDirectory} = undef; 373 $envir{courseScriptsDirectory} = $ce->{pg}->{directories}->{macros}."/"; 374 $envir{htmlDirectory} = $ce->{courseDirs}->{html}."/"; 375 $envir{htmlURL} = $ce->{courseURLs}->{html}."/"; 376 $envir{macroDirectory} = $ce->{courseDirs}->{macros}."/"; 377 $envir{templateDirectory} = $ce->{courseDirs}->{templates}."/"; 378 $envir{tempDirectory} = $ce->{courseDirs}->{html_temp}."/"; 379 $envir{tempURL} = $ce->{courseURLs}->{html_temp}."/"; 380 $envir{scriptDirectory} = undef; 381 $envir{webworkDocsURL} = $ce->{webworkURLs}->{docs}."/"; 382 # FIXME: this is HTML_img mode-specific 383 #$envir{dvipngTempDir} = $options->{displayMode} eq 'images' 384 # ? makeTempDirectory($envir{tempDirectory}, "webwork-dvipng") 385 # : undef; 386 387 # Information for sending mail 388 389 $envir{mailSmtpServer} = $ce->{mail}->{smtpServer}; 390 $envir{mailSmtpSender} = $ce->{mail}->{smtpSender}; 391 $envir{ALLOW_MAIL_TO} = $ce->{mail}->{allowedRecipients}; 392 393 # Default values for evaluating answers 394 395 my $ansEvalDefaults = $ce->{pg}->{ansEvalDefaults}; 396 $envir{$_} = $ansEvalDefaults->{$_} foreach (keys %$ansEvalDefaults); 397 398 # ---------------------------------------------------------------------- 399 400 my $basename = "equation-$envir{psvn}.$envir{probNum}"; 401 $basename .= ".$envir{problemSeed}" if $envir{problemSeed}; 402 403 # Object for generating equation images 404 $envir{imagegen} = WeBWorK::PG::ImageGenerator->new( 405 tempDir => $ce->{webworkDirs}->{tmp}, # global temp dir 406 latex => $envir{externalLaTeXPath}, 407 dvipng => $envir{externalDvipngPath}, 408 useCache => 1, 409 cacheDir => $ce->{webworkDirs}->{equationCache}, 410 cacheURL => $ce->{webworkURLs}->{equationCache}, 411 cacheDB => $ce->{webworkFiles}->{equationCacheDB}, 412 ); 413 414 # Other things... 415 $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes 416 $envir{PROBLEM_GRADER_TO_USE} = $ce->{pg}->{options}->{grader}; 417 $envir{PRINT_FILE_NAMES_FOR} = $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR}; 418 419 # variables for interpreting capa problems. 420 $envir{CAPA_Tools} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_Tools}; 421 $envir{CAPA_MCTools} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_MCTools}; 422 $envir{CAPA_Graphics_URL} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_Graphics_URL}; 423 $envir{CAPA_GraphicsDirectory} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_GraphicsDirectory}; 424 425 return \%envir; 426 } 427 428 sub translateDisplayModeNames($) { 429 my $name = shift; 430 return { 431 tex => "TeX", 432 plainText => "HTML", 433 formattedText => "HTML_tth", 434 images => "HTML_dpng", # "HTML_img", 435 }->{$name}; 436 } 437 438 sub safetyFilter { 439 my $answer = shift; # accepts one answer and checks it 440 my $submittedAnswer = $answer; 441 $answer = '' unless defined $answer; 442 my ($errorno); 443 $answer =~ tr/\000-\037/ /; 444 # Return if answer field is empty 445 unless ($answer =~ /\S/) { 446 #$errorno = "<BR>No answer was submitted."; 447 $errorno = 0; ## don't report blank answer as error 448 return ($answer,$errorno); 449 } 450 # replace ^ with ** (for exponentiation) 451 # $answer =~ s/\^/**/g; 452 # Return if forbidden characters are found 453 unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\[\]\(\)\,\|]+$/ ) { 454 $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; 455 $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; 456 return ($answer,$errorno); 457 } 458 $errorno = 0; 459 return($answer, $errorno); 460 } 461 462 1; 463 464 __END__ 465 466 =head1 OPERATION 467 468 WeBWorK::PG goes through the following operations when constructed: 469 470 =over 471 472 =item Get database information 473 474 Retrieve information about the current user, set, and problem from the 475 database. 476 477 =item Create a translator 478 479 Instantiate a WeBWorK::PG::Translator object. 480 481 =item Set the directory hash 482 483 Set the translator's directory hash (courseScripts, macros, templates, and temp 484 directories) from the course environment. 485 486 =item Evaluate PG modules 487 488 Using the module list from the course environment (pg->modules), perform a 489 "use"-like operation to evaluate modules at runtime. 490 491 =item Set the problem environment 492 493 Use data from the user, set, and problem, as well as the course environemnt and 494 translation options, to set the problem environment. 495 496 =item Initialize the translator 497 498 Call &WeBWorK::PG::Translator::initialize. What more do you want? 499 500 =item Load PG.pl and dangerousMacros.pl 501 502 These macros must be loaded without opcode masking, so they are loaded here. 503 504 =item Set the opcode mask 505 506 Set the opcode mask to the default specified by WeBWorK::PG::Translator. 507 508 =item Load the problem source 509 510 Give the problem source to the translator. 511 512 =item Install a safety filter 513 514 The safety filter is used to preprocess student input before evaluation. The 515 default safety filter, &WeBWorK::PG::safetyFilter, is used. 516 517 =item Translate the problem source 518 519 Call &WeBWorK::PG::Translator::translate to render the problem source into the 520 format given by the display mode. 521 522 =item Process student answers 523 524 Use form field inputs to evaluate student answers. 525 526 =item Load the problem state 527 528 Use values from the database to initialize the problem state, so that the 529 grader will have a point of reference. 530 531 =item Determine an entry order 532 533 Use the ANSWER_ENTRY_ORDER flag to determine the order of answers in the 534 problem. This is important for problems with dependancies among parts. 535 536 =item Install a grader 537 538 Use the PROBLEM_GRADER_TO_USE flag, or a default from the course environment, 539 to install a grader. 540 541 =item Grade the problem 542 543 Use the selected grader to grade the problem. 544 545 =back 546 547 =head1 AUTHOR 548 549 Written by Sam Hathaway, sh002i (at) math.rochester.edu. 550 551 =cut
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |