Parent Directory
|
Revision Log
Added support for HTML_dpng (dvipng) mode.
1 #!/usr/local/bin/webwork-perl 2 3 ################################################################ 4 # Copyright @1995-1999 by Michael E. Gage, Arnold K. Pizer and 5 # WeBWorK at the University of Rochester. All rights reserved. 6 ################################################################ 7 8 my $debugON=0; 9 10 use lib '.'; use webworkInit; # WeBWorKInitLine 11 12 require 5.001; 13 use strict; 14 use Global; 15 use Auth; 16 use CGI qw(:standard); 17 use Net::SMTP; 18 use Safe; 19 20 use PGtranslator; 21 use vars qw($modules_to_evaluate $extra_packages_to_be_loaded); 22 23 $/ ="\n"; 24 25 BEGIN { 26 # set to 1 to enable timing_log 27 # (contains information about time taken by scripts to run) 28 $main::logTimingData = 0; 29 30 # begin Timing code 31 if( $main::logTimingData == 1 ) { 32 use Benchmark; 33 $main::beginTime = new Benchmark; 34 } 35 # end Timing code 36 37 # Setting these time out comstants to zeros removes the time constraint completely. (zero = infinity :=) ) 38 $main::TIME_OUT_CONSTANT = 60; # one minute wait for on screen problems 39 $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT = 1200; #twenty minutes 40 $main::CLASS_DOWNLOAD_NICE = 5; # higher numbers indicated lower priorities 41 # $main::DOWNLOAD_TIME_OUT_CONSTANT = 300; # give it five minutes 42 # $main::DOWNLOAD_NICE = 2; 43 44 # ATTENTION: The handlers PG_floating_point_exception_handler and PG_warnings_handler 45 # have to be installed after CGI::Carp is called since it also 46 # modifes the die and warn labels. Finding the right warning mechanism using these two 47 # methods bears further investigation 48 # They are defined in Global.pm 49 $SIG{'FPE'} = \&Global::PG_floating_point_exception_handler; 50 $SIG{__WARN__}=\&Global::PG_warnings_handler; 51 $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $! stopped at $0\n"; }; 52 $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $! stopped at $0\n"; }; 53 $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) }; 54 55 alarm($main::TIME_OUT_CONSTANT); 56 # By explicitly catching the signals and dieing one forces the execution of the END statements which clean up the files. 57 }; 58 59 ################################################################################ 60 # main ######################################################################### 61 ################################################################################ 62 63 &CGI::ReadParse; 64 my %inputs=%main::in; 65 my $query = $main::in{CGI}; 66 67 # verify that the rest of the information has been received 68 my $Course = $inputs{'course'}; 69 my $User = $inputs{'user'}; 70 71 my @local_psvns = $query -> param('local_psvns'); 72 my $psvn = $local_psvns[0]; # get the first one for doing problem sets 73 $inputs{'probSetKey'} = $psvn; # only used by htmlBOTTOM 74 my $Session_key = $inputs{'key'}; 75 76 &Global::getCourseEnvironment($Course); 77 78 my $scriptDirectory = getWebworkScriptDirectory(); 79 my $databaseDirectory = getCourseDatabaseDirectory(); 80 my $courseScriptsDirectory = getCourseScriptsDirectory(); 81 my $templateDirectory = getCourseTemplateDirectory(); 82 my $tempDirectory = getCourseTempDirectory(); 83 84 eval{require "${courseScriptsDirectory}$Global::displayMacros_pl";}; 85 eval{require "${scriptDirectory}$Global::DBglue_pl";}; 86 eval{require "${scriptDirectory}$Global::classlist_DBglue_pl";}; 87 eval{require "${scriptDirectory}$Global::HTMLglue_pl";}; 88 eval{require "${scriptDirectory}$Global::FILE_pl";}; 89 90 # load the modules to be used in PGtranslator 91 require "${courseScriptsDirectory}PG_module_list.pl" 92 or wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl"); 93 94 my $keyFile = &Global::getCourseKeyFile($Course); 95 my $permissionsFile = &getCoursePermissionsFile($Course); 96 97 # check to see if prob set has been selected 98 if(not defined($psvn) or $psvn eq "") { 99 selectionError(); 100 exit; 101 } 102 103 # log access 104 &Global::log_info('', query_string); 105 106 &verify_key($inputs{'user'}, $Session_key, $keyFile, $Course); 107 my $permissions = &get_permissions($User,$permissionsFile); 108 109 &attachProbSetRecord($psvn); 110 my $login_name_for_psvn = &getStudentLogin($psvn); 111 attachCLRecord($login_name_for_psvn); 112 113 my $setNumber=&getSetNumber($psvn); 114 $setNumber = $inputs{'setNo'} if defined $inputs{'setNo'}; ## script called from profChangeDates.pl 115 116 # keep strict happy -sh 117 my $tempTexFileBaseName; 118 119 # check to see that it is after the open date 120 my ($currentTime,$odts,$ddts,$adts,$remainingTime, $TimeString); 121 $currentTime = time; 122 $odts=&getOpenDate($psvn); 123 $ddts=&getDueDate($psvn); 124 $adts=&getAnswerDate($psvn); 125 $remainingTime=$ddts-$currentTime; 126 127 if($currentTime<$odts && $permissions !=$Global::instructor_permissions) { 128 print &htmlTOP("Before open date error"); 129 print "<CENTER><h2>Sorry, cannot download or do problem set $setNumber yet. 130 <BR>It is before the open date.</h2></CENTER>"; 131 print &htmlBOTTOM("downloadPS.pl",\%inputs); 132 exit(0); 133 } 134 135 my %PSVNHashForSet = %{getPSVNHashForSet($setNumber)}; 136 my $action = $inputs{'action'}; 137 my $downloadType= $inputs{'downloadType'}; # either pdf, ps, tex, or dvi 138 139 # Verify that the problem set has been created if a psvn number has been passed 140 unless ($action eq 'Get_all_copies') { 141 unless (defined $PSVNHashForSet{$psvn} ) { 142 print &htmlTOP("Problem set version number $psvn not created"); 143 print ( "Pin number $psvn was not created for set $setNumber"); 144 print &htmlBOTTOM("downloadPS.pl", \%inputs); 145 exit(0); 146 } 147 } 148 149 my $save_errors = ''; 150 151 # check if solutions should be displayed 152 153 my $solutionsRequestedQ= 0; 154 $solutionsRequestedQ= $inputs{'ShowSol'} if defined($inputs{'ShowSol'}); 155 156 my $displaySolutionsQ = 0; #initialize 157 $displaySolutionsQ =1 if $solutionsRequestedQ && ($currentTime > $adts); 158 $displaySolutionsQ =1 if $solutionsRequestedQ && ($permissions == $Global::instructor_permissions); 159 160 if ($action eq 'Do problem set' or $action eq 'Do_problem_set') { displayProbSet(); } 161 elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { downloadAllSets(); } 162 elsif ($action eq 'Get_all_copies') { downloadAllSets(); } 163 else { wwerror($0, "Unknown action: $action"); } 164 165 # begin Timing code 166 #my $endTime = new Benchmark; 167 #&Global::logTimingInfo($main::beginTime,$endTime,$0,$Course,$User); 168 # end Timing code 169 170 exit; 171 172 ################################################################################ 173 # displayProbSet ############################################################### 174 ################################################################################ 175 176 sub displayProbSet 177 { 178 my $studentName=&CL_getStudentName($login_name_for_psvn); 179 my $probHeaderFileName = &getProbHeaderFileName($psvn); 180 181 sub numerical { $a <=> $b}; 182 my @problems=sort numerical &getAllProblemsForProbSetRecord($psvn); 183 my $numberOfProblems = @problems; 184 185 print &probSet_htmlTOP("Problem Set $setNumber from $inputs{'course'} for $studentName"); 186 #see subroutines at the bottom of this file 187 #this allows the use of a small gif for the webwork logo 188 #and takes up less screen real estate. 189 190 print &probSet_titleBar("Problem Set $setNumber from $inputs{'course'} for $studentName"); 191 192 print <<"ENDOFHTML"; 193 <TABLE BORDER=1> 194 <TR> 195 <!-- Row 1 Column 1 --> 196 <TD> 197 Select one of the $numberOfProblems problems to try: 198 <FORM METHOD=POST ACTION="$Global::processProblem_CGI"> 199 <INPUT TYPE=HIDDEN NAME=probSetKey VALUE=$psvn> 200 <P> 201 <SELECT NAME=probNum SIZE=11> 202 ENDOFHTML 203 204 my ($problemAttempted, $problemStatus, $longProblemStatus); 205 foreach my $problem (@problems) { 206 $problemStatus = getProblemStatus($problem,$psvn); 207 $problemAttempted = getProblemAttempted($problem,$psvn); 208 209 if (!$problemAttempted) { 210 $longProblemStatus = ''; 211 } elsif ($problemStatus >= 0 and $problemStatus <=1 ) { 212 my $percentCorr = int(100*$problemStatus+.5); 213 $longProblemStatus = "${percentCorr}\% correct" 214 } else { 215 $longProblemStatus = 'unknown status'; # default value 216 } 217 print "<OPTION VALUE=\"$problem\">Problem $problem -- $longProblemStatus</OPTION>\n"; 218 } 219 220 # nice note to warn if there's less than one day left to complete problem set 221 if ($remainingTime < 86400 and $remainingTime > 0) { 222 $TimeString = "<BR><EM>Note: you have less than one day left to complete this problem set</EM>"; 223 } else { 224 $TimeString = ""; 225 } 226 227 print "</SELECT><BR>"; 228 229 my $practiceUser = $Global::practiceUser; 230 if (($currentTime > $ddts) or ($User =~ /^$practiceUser/)) { 231 print '<INPUT type="checkbox" name="show_old_answers" value="1"> Show my old answers<BR>'; 232 } 233 else { 234 print '<INPUT type="checkbox" name="show_old_answers" value="1" checked> Show my old answers<BR>'; 235 } 236 237 print &sessionKeyInputs(\%inputs); 238 239 my $mode = $inputs{'Mode'}; 240 $mode = $Global::htmlModeDefault unless ($mode); 241 &displaySelectModeLine($mode); ## displays mode select buttons 242 ## displaySelectModeLine() is in "${courseScriptsDirectory}$Global::displayMacros_pl" 243 print <<"ENDOFHTML"; 244 <BR> 245 <INPUT TYPE=SUBMIT VALUE="Get Problem"> 246 $TimeString 247 </FORM> 248 ENDOFHTML 249 250 print "<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>"; 251 print &sessionKeyInputs(\%inputs); 252 253 print <<"ENDOFHTML"; 254 <INPUT TYPE=HIDDEN NAME="probSetKey" VALUE=$psvn> 255 <INPUT TYPE=SUBMIT VALUE="Problem Sets"> 256 </FORM> 257 </TD> 258 <!-- Row 1 Column 2 --> 259 <TD> 260 ENDOFHTML 261 262 263 # process problem and save @printlines 264 my $probHeader = $Global::PROB_HEADER; # default value 265 if ((defined($probHeaderFileName)) and ($probHeaderFileName =~ /\S/)) { 266 $probHeader = $probHeaderFileName; 267 } 268 269 # use $probHeader as default unless $probHeaderFileName is defined in the set definition file 270 my $source; 271 if (-e "${templateDirectory}$probHeader") { 272 unless (-r "${templateDirectory}$probHeader") { 273 wwerror($0, "Can't read ${templateDirectory}$probHeader"); 274 } 275 open(PROB,"<${templateDirectory}$probHeader"); 276 $source = join("",<PROB>); 277 close(PROB); 278 } 279 280 # translate the problem header file 281 my %envir=defineProblemEnvir($mode,0,$psvn,$Course); 282 283 my $pt = new PGtranslator; # pt stands for problem translator; 284 $pt->environment(\%envir); 285 $pt->initialize(); 286 $pt->set_mask(); 287 $pt->source_string($source); 288 $pt->unrestricted_load("${courseScriptsDirectory}PG.pl"); 289 $pt->unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); 290 $pt->translate(); 291 292 my $PG_PROBLEM_TEXT_REF = $pt->ra_text(); 293 my $PG_HEADER_TEXT_REF = $pt->r_header; #\$PG_HEADER_TEXT; 294 my $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; 295 my $PG_FLAGS_REF = $pt->rh_flags; 296 297 my @printlines; 298 if($mode eq "HTML" || $mode eq 'HTML_tth' || $mode eq 'HTML_dpng') { 299 @printlines = @{$PG_PROBLEM_TEXT_REF}; 300 #@printlines = @{$pt->ra_text()}; 301 } 302 elsif ($mode eq 'Latex2HTML') { 303 @printlines = 304 &createDisplayedInsert($setNumber,$probHeader,$psvn,$Course,$PG_PROBLEM_TEXT_REF); 305 } 306 print @printlines; 307 print "</TD></TR></TABLE>"; 308 309 print &htmlBOTTOM('welcomeAction.pl', \%inputs,'probSetHelp.html'); 310 } 311 312 ################################################################################ 313 # downloadAllSets (and related subroutines) #################################### 314 ################################################################################ 315 316 ################### 317 # downloadAllSets # 318 ################### 319 320 sub downloadAllSets { 321 system("/usr/bin/renice +$main::CLASS_DOWNLOAD_NICE -p $$ 1>/dev/null") && warn "Could not renice process. pid $$"; 322 alarm( $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT); 323 324 my $downloadMulti = "unknown"; 325 $downloadMulti = "multistudent" if $action eq "Get_all_copies"; 326 $downloadMulti = "multiset" if $action eq "Get_hard_copy"; 327 328 my @psvns_to_download = $query->param('local_psvns'); 329 my $num_psvns_to_download = @psvns_to_download; 330 my $max_psvns_to_download = $Global::max_num_of_ps_downloads_allowed; 331 332 if($num_psvns_to_download > 1 and $permissions != $Global::instructor_permissions) { 333 wwerror("Non-professors are not permitted to download more than one problem set at a time."); 334 } 335 336 if(@psvns_to_download > $Global::max_num_of_ps_downloads_allowed) { 337 my $tooManyWhat = $downloadMulti eq "multiset" ? "problem sets" : "students"; 338 wwerror("Too many $tooManyWhat are selected for download.", 339 "The maximum number of $tooManyWhat which can be downloaded at one time is $Global::max_num_of_ps_downloads_allowed." 340 ." You selected $num_psvns_to_download. Go back and select fewer $tooManyWhat." 341 ." (This maximun is set by the variable \$max_num_of_ps_downloads_allowed in Global.pm.)"); 342 } 343 344 my ($cumulativeTexSource, $currentTexSourceRef, $currentTexSource, $currentTexErrorRef); 345 346 # this could be used when eliminating pre-foreach createTexSourceHandleErrors call 347 # s/\\end\{document\}.*?\\begin\{document\}/\n\\newpage\n/s; 348 349 $tempTexFileBaseName = "${tempDirectory}Temp_downloadAllSets_$User"; 350 my $first_psvn = $psvns_to_download[0]; 351 352 my $current_psvn = shift @psvns_to_download; 353 ($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn); 354 @psvns_to_download = () if(@$currentTexErrorRef); 355 $currentTexSource = $$currentTexSourceRef; 356 $currentTexSource =~ s|\\end\{document\}\s$|\n|s; 357 $cumulativeTexSource .= $currentTexSource; 358 359 foreach $current_psvn (@psvns_to_download) { 360 ($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn); 361 @psvns_to_download = () if(@$currentTexErrorRef); 362 $currentTexSource = $$currentTexSourceRef; 363 $currentTexSource =~ s|^.*?\\begin\{document\}|\n\\newpage\n|s; 364 $currentTexSource =~ s|\\end\{document\}\s$|\n|s; 365 $cumulativeTexSource .= $currentTexSource; 366 } 367 368 $cumulativeTexSource .= "\n\\end{document}\n"; 369 370 open TEXOUTPUT, ">$tempTexFileBaseName.tex" 371 or wwerror("Can't open $tempTexFileBaseName.tex for output."); 372 print TEXOUTPUT $cumulativeTexSource; 373 close TEXOUTPUT; 374 375 if(@$currentTexErrorRef) { 376 PG_error_print($tempTexFileBaseName, $current_psvn, @$currentTexErrorRef); 377 } else { 378 $downloadType = lc $downloadType; 379 my $mimeType = prepareHardcopy($tempTexFileBaseName, $downloadType); 380 381 my ($setName, $userName); 382 &attachProbSetRecord($first_psvn); 383 if($downloadMulti eq "multistudent") { 384 if($num_psvns_to_download == 1) { 385 $setName = getSetNumber($first_psvn); 386 $userName = getStudentLogin($first_psvn); 387 } else { 388 $setName = getSetNumber($first_psvn); 389 $userName = "multistudent"; 390 } 391 } elsif($downloadMulti eq "multiset") { 392 if($num_psvns_to_download == 1) { 393 $setName = getSetNumber($first_psvn); 394 $userName = getStudentLogin($first_psvn); 395 } else { 396 $setName = "multiset"; 397 $userName = getStudentLogin($first_psvn); 398 } 399 } 400 my $hardCopyName = "$Course.$userName.$setName.$downloadType"; 401 402 open(TEXINPUT, "$tempTexFileBaseName.$downloadType") 403 or wwerror($0, "Can't open $tempTexFileBaseName.$downloadType: $!\n"); 404 print "Content-type: $mimeType\n"; 405 print "Content-disposition: attachment; filename=\"$hardCopyName\"\n\n"; 406 print while (<TEXINPUT>); 407 close TEXINPUT; 408 } 409 } 410 411 ################### 412 # createTexSource # 413 ################### 414 415 sub createTexSource { 416 my $psvn = shift; 417 418 # Check that the psvn corresponds to the user and that it is after the open date. 419 # This should only fail if someone is trying to break into WeBWorK. 420 &attachProbSetRecord($psvn); 421 $login_name_for_psvn = &getStudentLogin($psvn); 422 attachCLRecord($login_name_for_psvn); 423 424 if ((($User ne &getStudentLogin($psvn)) ||($currentTime < $odts)) 425 and ($permissions != $Global::instructor_permissions) 426 and ($permissions != $Global::TA_permissions)) 427 { 428 &hackerError; 429 exit; 430 } 431 432 my $probSetHeader = $Global::SET_HEADER; 433 my $setHeaderFileName = &getSetHeaderFileName($psvn); 434 435 my $answersRequestedQ = 0; 436 $answersRequestedQ= $inputs{'ShowAns'} if defined($inputs{'ShowAns'}); 437 438 my $adts=&getAnswerDate($psvn); 439 440 my $displayCorrectAnswersQ = 0; #initialize 441 $displayCorrectAnswersQ =1 if $answersRequestedQ && ($currentTime > $adts); 442 $displayCorrectAnswersQ =1 if $answersRequestedQ && ($permissions == $Global::instructor_permissions); 443 444 445 446 447 my $texSource =''; 448 449 print STDERR "%%Creating a tex version of set $setNumber<BR>\n" if $debugON; 450 print STDERR "%%For", &CL_getStudentName($login_name_for_psvn), "psvn=$psvn<BR>\n" if $debugON; 451 452 # print TeX preamble and header 453 $texSource .= &texInput($Global::TEX_SET_PREAMBLE); 454 $texSource .= &texInput($Global::TEX_SET_HEADER); 455 456 # print set header 457 my $mode = "TeX"; 458 my @PG_COMPILE_ERRORS = (); 459 if ((defined($setHeaderFileName)) and $setHeaderFileName =~ /\S/) { 460 $probSetHeader = $setHeaderFileName; 461 } 462 if (open(INPUT,"${templateDirectory}$probSetHeader")) { 463 $probSetHeader =~ /\.([^\.]*)$/; 464 my $displayMode = $1; 465 466 if ($displayMode eq 'pg') { 467 my %envir=defineProblemEnvir($mode, 0, $psvn, $Course, undef()); 468 my $input_string= join("",<INPUT>); 469 my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF); 470 471 # BEGIN fork 472 if (open TEX_PIPE, "-|") { 473 # parent: 474 local $/ = "\n"; 475 my $curr_pg_compile_error = <TEX_PIPE>; 476 chomp $curr_pg_compile_error; 477 push @PG_COMPILE_ERRORS, $curr_pg_compile_error if $curr_pg_compile_error; 478 479 undef $/; 480 $texSource .= <TEX_PIPE>; 481 } else { 482 # child: 483 $texSource = ''; # clear this at beginning of fork 484 @PG_COMPILE_ERRORS = (); # clear this as well 485 # ----- 486 my $pt = new PGtranslator; 487 $pt -> evaluate_modules( @{main::modules_to_evaluate}) ; 488 $pt -> load_extra_packages(@{main::extra_packages_to_be_loaded}); 489 # The variables in the two preceding lines are defined in PG_module_list.pl 490 # require "${courseScriptsDirectory}PG_module_list.pl"; 491 # (Modules are defined by require statement above found near the top of this file) 492 $pt->environment(\%envir); 493 $pt->initialize(); 494 $pt->set_mask(); 495 $pt->source_string($input_string); 496 $pt->unrestricted_load("${courseScriptsDirectory}PG.pl"); 497 $pt->unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); 498 $pt->translate(); 499 500 $PG_PROBLEM_TEXT_REF = $pt->ra_text(); 501 $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; 502 $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; 503 $PG_FLAGS_REF = $pt->rh_flags; 504 505 $texSource .= join '', @{$PG_PROBLEM_TEXT_REF}; 506 507 # begin non-FORK code 508 # if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} == 1) { 509 # push(@PG_COMPILE_ERRORS, qq{<A HREF="#problem0">$probSetHeader</A>} ); 510 # } 511 # end non-FORK code 512 513 # begin FORK-only code 514 my $stupid_forked_error_string; 515 if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { 516 $texSource = qq{<A HREF="#problem0">$probSetHeader</A>} . "\n" . $texSource; 517 } else { 518 $texSource = "\n" . $texSource; 519 } 520 # end FORK code 521 522 if (defined($Global::WARNINGS) and $Global::WARNINGS) { 523 my $warnings = '{\\bf WARNINGS:\par{\\tiny ' . $Global::WARNINGS . ' }}'; 524 $warnings =~ s|/|\\\-/|g; # allow linebreaks in the middle of URLs 525 $warnings =~ s/<br>/\\par\n/ig; # introduce breaks at linebreaks and paragraphs 526 $warnings =~ s/<p>/\\par\n/ig; 527 $warnings =~ s/\#/\\\#/g; # protect against some of the symbols which are reserved in tex 528 $warnings =~ s/\_/\\\_/g; 529 $warnings =~ s/\>/\\\>/g; 530 $warnings =~ s/\</\\\</g; 531 $texSource .= $warnings; 532 } 533 $Global::WARNINGS = ''; # reset the Global::WARNINGS parameter 534 # ----- 535 print $texSource; 536 exit; 537 } 538 # END fork 539 } else { 540 $texSource .= "Don't understand languages with extension $displayMode.<BR>\n"; 541 } 542 close INPUT; 543 } else { 544 print STDERR ( "Can't open ${templateDirectory}${probSetHeader}\n") if $debugON; 545 wwerror("$0", "\n######## Could not open the set header file: ${templateDirectory}${probSetHeader}","",""); 546 } 547 548 # Print problems 549 my @problems = sort { $a <=> $b } &getAllProblemsForProbSetRecord($psvn); 550 my @refSubmittedAnswers = (); 551 552 my $probNum; 553 foreach $probNum (@problems) { 554 my $source; 555 my $probFileName = &getProblemFileName($probNum,$psvn); 556 if (-e "${templateDirectory}$probFileName") { 557 unless (-r "${templateDirectory}$probFileName") { 558 wwerror($0, "Can't read ${templateDirectory}$probFileName"); 559 } 560 open(PROB,"<${templateDirectory}$probFileName"); 561 $source = join("",<PROB>); 562 close(PROB); 563 } 564 local($^W) =0; ##########CHANGE THIS BACK!!!! # what do you mean by that? 565 my %envir=defineProblemEnvir('TeX',$probNum,$psvn,$Course,undef()); 566 my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF,$PG_EVALUATED_ANSWERS_REF); 567 568 # BEGIN fork 569 if (open TEX_PIPE, "-|") { 570 # parent: 571 local $/ = "\n"; 572 my $curr_pg_compile_error = <TEX_PIPE>; 573 chomp $curr_pg_compile_error; 574 push @PG_COMPILE_ERRORS, $curr_pg_compile_error if $curr_pg_compile_error; 575 576 undef $/; 577 $texSource .= <TEX_PIPE>; 578 } else { 579 # child: 580 $texSource = ''; # clear this at beginning of fork 581 @PG_COMPILE_ERRORS = (); # clear this as well 582 # ----- 583 my $pt = new PGtranslator; #pt stands for problem translator; 584 $pt->environment(\%envir) ; 585 $pt->initialize(); 586 $pt-> set_mask(); 587 $pt->source_string($source); 588 $pt->unrestricted_load("${courseScriptsDirectory}PG.pl"); 589 $pt->unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); 590 $pt->translate(); 591 592 $PG_PROBLEM_TEXT_REF = $pt->ra_text(); 593 $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; 594 #$PG_ANSWER_HASH_REF = $pt->rh_correct_answers; 595 $PG_EVALUATED_ANSWERS_REF = $pt->process_answers; 596 $PG_FLAGS_REF = $pt ->rh_flags; 597 598 $texSource .= join '', @{$PG_PROBLEM_TEXT_REF}; 599 600 # begin non-FORK code 601 # if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { 602 # push(@PG_COMPILE_ERRORS, qq{<A HREF="#problem$probNum">$probNum</A>} ); 603 # } 604 # end non-FORK code 605 606 # begin FORK-only code 607 if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { 608 $texSource = qq{<A HREF="#problem$probNum">$probNum</A>} . "\n" . $texSource; 609 } else { 610 $texSource = "\n" . $texSource; 611 } 612 # end FORK code 613 614 if ($displayCorrectAnswersQ) { 615 my %correctAnswerHash = (); 616 my @correctAnswerList = (); 617 my %submittedAnswerHash = (); 618 619 if (ref($PG_EVALUATED_ANSWERS_REF) eq 'HASH') { 620 %correctAnswerHash = %$PG_EVALUATED_ANSWERS_REF; 621 } else { 622 warn "ERROR: Please pass the PG answer list as a hash not a list."; 623 } 624 625 if (%correctAnswerHash) { 626 my ($correctFlag,$normalizedCorrectAnswer, 627 $normalizedSubmittedAnswer, 628 $answerMessage) = (); 629 630 # determine the correct order for the answers 631 my @answer_entry_order = 632 (defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER})) 633 ? @{$pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}} 634 : keys %{$pt->rh_evaluated_answers}; 635 636 $texSource .= "Correct Answers:\\par\\begin{itemize}\n"; 637 foreach my $ky (@answer_entry_order) { 638 $normalizedCorrectAnswer = $correctAnswerHash{$ky}->{correct_ans}; 639 $normalizedCorrectAnswer =~ s/\^/\\\^\{\}/g; 640 $normalizedCorrectAnswer =~ s/\_/\\\_/g; 641 $texSource .= "\\item $normalizedCorrectAnswer\n"; 642 643 } 644 $texSource .= "\\end{itemize} \\par\n"; 645 } 646 } 647 648 if (defined($Global::WARNINGS) and $Global::WARNINGS) { 649 my $warnings = '{\\bf WARNINGS:\par{\\tiny ' . $Global::WARNINGS . ' }}'; 650 unless (@PG_COMPILE_ERRORS) { # prepare warnings for TeX output in this case 651 $warnings =~ s|/|\\\-/|g; # allow linebreaks in the middle of URLs 652 $warnings =~ s/<br>/\\par\n/ig; # introduce breaks at linebreaks and paragraphs 653 $warnings =~ s/<p>/\\par\n/ig; 654 $warnings =~ s/\#/\\\#/g; # protect against some of the symbols which are reserved in tex 655 $warnings =~ s/\_/\\\_/g; 656 $warnings =~ s/\>/\\\>/g; 657 $warnings =~ s/\</\\\</g; 658 $texSource .= $warnings; 659 } 660 } 661 $Global::WARNINGS = ''; #reset the Global::WARNINGS parameter 662 # ----- 663 print $texSource; 664 exit; 665 } 666 # END fork 667 } # this is the end of the foreach problem loop 668 669 # print Tex postamble 670 $texSource .= &texInput($Global::TEX_SET_FOOTER); 671 672 return \$texSource, \@PG_COMPILE_ERRORS; 673 } 674 675 ################### 676 # prepareHardcopy # 677 ################### 678 679 sub prepareHardcopy 680 { 681 my ($texFileBaseName, $targetFormat) = @_; 682 my $mimeType; 683 684 chdir $tempDirectory; 685 686 my $dviCommandLine = "$Global::externalLatexPath $texFileBaseName.tex >/dev/null 2>/dev/null"; 687 my $psCommandLine = "$Global::externalDvipsPath -o $texFileBaseName.ps $texFileBaseName.dvi >/dev/null 2>/dev/null"; 688 my $pdfCommandLine = "$Global::externalGsPath -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$texFileBaseName.pdf -c save pop -f $texFileBaseName.ps"; 689 # my $pdfCommandLine = "$Global::externalPs2pdfPath $texFileBaseName.ps $texFileBaseName.pdf"; 690 691 # make sure that you are not using old copies of the following files: 692 unlink("$texFileBaseName.dvi","$texFileBaseName.ps", "$texFileBaseName.pdf"); 693 694 # we use logPrint() for TeX->DVI errors as they are usually caused 695 if($targetFormat eq "pdf") { 696 system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); 697 system($psCommandLine); -e "$texFileBaseName.ps" or die "ps generation failed."; 698 system($pdfCommandLine); -e "$texFileBaseName.pdf" or die "pdf generation failed."; 699 $mimeType = "application/pdf"; 700 } elsif($targetFormat eq "ps") { 701 system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); 702 system($psCommandLine); -e "$texFileBaseName.ps" or die "ps generation failed."; 703 $mimeType = "application/postscript"; 704 } elsif($targetFormat eq "dvi") { 705 system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); 706 $mimeType = "application/x-dvi"; 707 } elsif($targetFormat eq "tex") { 708 $mimeType = "application/tex"; 709 } else { 710 die "unrecognized format: $targetFormat"; 711 } 712 713 return $mimeType; 714 } 715 716 ################## 717 # PG_error_print # 718 ################## 719 720 sub PG_error_print 721 { 722 my ($tempTexFileBaseName, $current_psvn, @errors) = @_; 723 724 # get set name and student name from psvn 725 &attachProbSetRecord($current_psvn); 726 my $userName = &getStudentLogin($current_psvn); 727 my $setName = &getSetNumber($current_psvn); 728 729 # print error page header 730 print &htmlTOP("PG compile error"); 731 print "<H3>PG error while compiling problem number", (@errors>1) ? 's ' : ' ', 732 join(', ', @errors), " in problem set $setName for $userName.</H3>"; 733 print "<h3>TeX source file:</h3>"; 734 735 # open temp tex file 736 if(open TEXINPUT, "$tempTexFileBaseName.tex") { 737 print "<pre>\n"; 738 my $lineNumber = 1; 739 while(<TEXINPUT>) { 740 if(/<A NAME/) { print $_; } 741 else { print protect_HTML("$lineNumber $_"), "\n"; } 742 $lineNumber++; 743 } 744 print "</pre>\n"; 745 close TEXINPUT; 746 } else { 747 print "<p>Unable to open TeX source file:<br><tt>$tempTexFileBaseName.tex</tt></p>"; 748 } 749 750 # print page footer 751 print &htmlBOTTOM("welcomeAction.pl", \%inputs); 752 exit; 753 } 754 755 sub logPrint { 756 my $texFileBaseName=shift; 757 print &htmlTOP("TeX Error or error in creating PostScript file"); 758 open (LOGFILE, " $texFileBaseName.log") 759 || print "<H3>Can't open log file:</H3> path= $texFileBaseName.log<BR>$!<BR><BR>" ; 760 761 762 print "<H3>TeX Error Log:</H3>"; 763 my $print_error_switch = ($debugON) ? 1: 0; 764 my $out=''; 765 #warn ord $/, ord "\n", ord "\r"; 766 #warn "length of separator = ", length($/); 767 $/ = "\n"; 768 #warn ord $/, ord "\n", ord "\r"; 769 while (<LOGFILE>) { 770 $out = $_; 771 $print_error_switch = 1 if $out =~ /^!/; # after a fatal error start printing messages 772 print protect_HTML($out)."<BR>\n" if $print_error_switch; 773 } 774 close(LOGFILE); 775 776 open (TEXFILE, "$texFileBaseName.tex") 777 || print "<H3>Can't open tex source file:</H3> path= $texFileBaseName.tex:<BR> $!<BR><BR>\n"; 778 print "<BR>\n<H3>TeX Source File:</H3><BR>\n"; 779 print "<PRE>"; 780 781 my $lineNumber = 1; 782 while (<TEXFILE>) { 783 print protect_HTML("$lineNumber $_")."\n"; 784 $lineNumber++; 785 } 786 close(TEXFILE); 787 print "</PRE>"; 788 print &htmlBOTTOM("welcomeAction.pl", \%inputs); 789 } 790 sub protect_HTML { 791 my $line = shift; 792 chomp($line); 793 $line =~s/\&/&/g; 794 $line =~s/</</g; 795 $line =~s/>/>/g; 796 $line; 797 } 798 sub selectionError { 799 print &htmlTOP("Selection error"); 800 print"<H2>Error:</H2> You must first select a problem set in order to download a hard copy!\n"; 801 print "<FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P>"; 802 print &sessionKeyInputs(\%inputs); 803 print <<"ENDOFHTML"; 804 <INPUT TYPE=SUBMIT VALUE="Return to Welcome Page"> 805 </FORM> 806 ENDOFHTML 807 print &htmlBOTTOM("welcomeAction.pl", \%inputs); 808 } 809 810 sub probSet_htmlTOP { 811 my ($title, $bg_url) = @_; 812 my $background_url = $bg_url || $Global::background_plain_url; 813 814 815 my $out = <<ENDhtmlTOP; 816 Content-type: text/html 817 Expires: 0 818 819 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 820 <HTML> 821 <HEAD> 822 <TITLE>$title</TITLE> 823 </HEAD> 824 <BODY BACKGROUND="$background_url"><p> 825 <P> 826 827 ENDhtmlTOP 828 $out; 829 } 830 831 sub probSet_titleBar { 832 my ($title) = @_; 833 my $title_bar = ""; 834 $title_bar .= qq{ 835 <TABLE BORDER="0" WIDTH="100%"> 836 <TR ALIGN=CENTER > 837 <TD ALIGN=LEFT > 838 <A HREF="$Global::webworkDocsURL"> 839 <IMG SRC="$Global::squareWebworkGif" BORDER=1 ALT="WeBWorK"></A> 840 </TD> 841 <TD VALIGN=MIDDLE> 842 <H2 ALIGN=CENTER> 843 $title 844 </H2> 845 </TD> 846 <TD ALIGN=RIGHT > 847 <FORM METHOD=POST ACTION=\"${Global::cgiWebworkURL}welcome.pl\"><P> 848 }; 849 my $inputkeys = &sessionKeyInputs(\%inputs); 850 851 $title_bar .= qq{ 852 $inputkeys 853 <INPUT TYPE=HIDDEN NAME=\"probSetKey\" VALUE=$psvn> 854 <INPUT TYPE=SUBMIT VALUE=\"Problem Sets\"> 855 </FORM> 856 </TD> 857 </TABLE> 858 }; 859 $title_bar; 860 } 861 862 sub hackerError { ## prints hacker error message 863 864 my $msg = "Attempt to hack into WeBWorK \n Remote Host is: ". remote_host()."\n"; 865 $msg .= query_string; 866 &Global::log_error('hacker error', $msg); ## log attempt 867 868 ## notify by email 869 870 my $toAdd = $Global::feedbackAddress; 871 872 my $emailMsg = "To: $toAdd 873 Subject: Attempt to hack into WeBWorK 874 875 Here are the details on the attempt to hack into weBWorK:\n 876 $msg 877 \n"; 878 879 my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20); 880 $smtp->mail($Global::webmaster); 881 $smtp->recipient($Global::feedbackAddress); 882 $smtp->data($msg); 883 $smtp->quit; 884 885 886 # my $SENDMAIL = $Global::SENDMAIL; 887 # open (MAIL,"|$SENDMAIL"); 888 # print MAIL "$emailMsg"; 889 # close (MAIL); 890 891 print &htmlTOP("Hacker Error"), 892 "<H2>Error:Please do not try to hack into WeBWorK!</H2>", 893 startform(-action=>"${Global::cgiWebworkURL}${Global::welcomeAction_CGI}"), 894 "<p>", 895 &sessionKeyInputs(\%inputs), 896 hidden(-name=>'local_psvns', -value=>$psvn), 897 hidden(-name=>'action', -value=>'Do_problem_set'), 898 submit(-value=>"Return to Problem Set"), 899 endform(), 900 &htmlBOTTOM($0, \%inputs); 901 } 902 903 sub defineProblemEnvir { 904 my ($mode,$probNum,$psvn,$courseName,$refSubmittedAnswers) = @_; 905 my %envir=(); 906 my $loginName = &getStudentLogin($psvn); 907 ##how to put an array submittedAnswers in a hash?? 908 $envir{'refSubmittedAnswers'} = $refSubmittedAnswers if defined($refSubmittedAnswers); 909 $envir{'psvnNumber'} = $psvn; 910 $envir{'psvn'} = $psvn; 911 $envir{'studentName'} = &CL_getStudentName($loginName); 912 $envir{'studentLogin'} = $loginName; 913 $envir{'studentID'} = &CL_getStudentID($loginName); 914 $envir{'sectionName'} = &CL_getClassSection($loginName); 915 $envir{'sectionNumber'} = &CL_getClassSection($loginName); 916 $envir{'recitationName'} = &CL_getClassRecitation($loginName); 917 $envir{'recitationNumber'} = &CL_getClassRecitation($loginName); 918 $envir{'setNumber'} = &getSetNumber($psvn); 919 $envir{'questionNumber'} = $probNum; 920 $envir{'probNum'} = $probNum; 921 $envir{'openDate'} = &getOpenDate($psvn); 922 $envir{'formatedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn)); 923 $envir{'formattedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn)); 924 $envir{'dueDate'} = &getDueDate($psvn); 925 $envir{'formatedDueDate'} = &formatDateAndTime(&getDueDate($psvn)); 926 $envir{'formattedDueDate'} = &formatDateAndTime(&getDueDate($psvn)); 927 $envir{'answerDate'} = &getAnswerDate($psvn); 928 $envir{'formatedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn)); 929 $envir{'formattedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn)); 930 $envir{'problemValue'} = &getProblemValue($probNum,$psvn); 931 $envir{'fileName'} = &getProblemFileName($probNum,$psvn); 932 $envir{'probFileName'} = &getProblemFileName($probNum,$psvn); 933 $envir{'languageMode'} = $mode; 934 $envir{'displayMode'} = $mode; 935 $envir{'outputMode'} = $mode; 936 $envir{'courseName'} = $courseName; 937 $envir{'sessionKey'} = ( defined($inputs{'key'}) ) ?$inputs{'key'} : " "; 938 939 # initialize constants for PGanswermacros.pl 940 $envir{'numRelPercentTolDefault'} = getNumRelPercentTolDefault(); 941 $envir{'numZeroLevelDefault'} = getNumZeroLevelDefault(); 942 $envir{'numZeroLevelTolDefault'} = getNumZeroLevelTolDefault(); 943 $envir{'numAbsTolDefault'} = getNumAbsTolDefault(); 944 $envir{'numFormatDefault'} = getNumFormatDefault(); 945 $envir{'functRelPercentTolDefault'} = getFunctRelPercentTolDefault(); 946 $envir{'functZeroLevelDefault'} = getFunctZeroLevelDefault(); 947 $envir{'functZeroLevelTolDefault'} = getFunctZeroLevelTolDefault(); 948 $envir{'functAbsTolDefault'} = getFunctAbsTolDefault(); 949 $envir{'functNumOfPoints'} = getFunctNumOfPoints(); 950 $envir{'functVarDefault'} = getFunctVarDefault(); 951 $envir{'functLLimitDefault'} = getFunctLLimitDefault(); 952 $envir{'functULimitDefault'} = getFunctULimitDefault(); 953 $envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration(); 954 $envir{'numOfAttempts'} = undef(); # this is defined only for problems 955 956 # defining directorys and URLs 957 $envir{'templateDirectory'} = &getCourseTemplateDirectory(); 958 $envir{'classDirectory'} = $Global::classDirectory; 959 $envir{'cgiDirectory'} = $Global::cgiDirectory; 960 $envir{'macroDirectory'} = getCourseMacroDirectory(); 961 $envir{'courseScriptsDirectory'} = getCourseScriptsDirectory(); 962 $envir{'htmlDirectory'} = getCourseHtmlDirectory(); 963 $envir{'htmlURL'} = getCourseHtmlURL(); 964 $envir{'tempDirectory'} = getCourseTempDirectory(); 965 $envir{'tempURL'} = getCourseTempURL(); 966 $envir{'scriptDirectory'} = $Global::scriptDirectory; 967 $envir{'webworkDocsURL'} = $Global::webworkDocsURL; 968 $envir{'externalTTHPath'} = $Global::externalTTHPath; 969 970 971 $envir{'inputs_ref'} = \%inputs; 972 973 974 my $seed = &getProblemSeed($probNum, $psvn); 975 $seed = 1111 unless defined($seed); 976 $envir{'problemSeed'} = $seed if defined($seed); 977 $envir{'displaySolutionsQ'} = $displaySolutionsQ; 978 979 # here is a way to pass environment variables defined in webworkCourse.ph 980 my $k; 981 foreach $k (keys %Global::PG_environment ) { 982 $envir{$k} = $Global::PG_environment{$k}; 983 } 984 %envir; 985 } 986 987 ################################################################################ 988 # cleanup routines ############################################################# 989 ################################################################################ 990 991 BEGIN { 992 # This subroutine cleans up temporary files after the postscript copy has been created. 993 sub cleanup_downloadPS { 994 unless (defined($action) and ($action eq 'Do problem set' or $action eq 'Do_problem_set')) { 995 my $ERRORS = $save_errors; 996 unless ($debugON) { 997 eval { 998 chdir $tempDirectory; 999 unlink( 1000 "#tempTexFileBaseName.dvi", 1001 "$tempTexFileBaseName.ps", 1002 "$tempTexFileBaseName.pdf", 1003 "$tempTexFileBaseName.log", 1004 "$tempTexFileBaseName.aux", 1005 "$tempTexFileBaseName.tex" 1006 ); 1007 unlink("${tempDirectory}eps/${login_name_for_psvn}*.eps"); 1008 }; 1009 $ERRORS .= $ERRORS . $@; 1010 } 1011 my $query = query_string(); 1012 $query = "" unless defined($query); 1013 wwerror("$0", "ERROR: in downloadPS subroutine of welcomeAction.pl $ERRORS","","",$query) if $ERRORS; 1014 } 1015 } 1016 } 1017 1018 END { 1019 if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) { 1020 alarm(0); # turn off the alarm 1021 my $hard_copy_message = qq{Content-type: text/html\n\n 1022 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 1023 <HTML><BODY BGCOLOR = "FF99CC"> 1024 <BLOCKQUOTE><H3>WeBWorK hard copy download time out.</H3>\n 1025 <H4>This download was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.</H4> This may be because the 1026 WeBWorK server is extraordinarily busy, or because there was an error in the problem, 1027 or because you tried to download a set with too many problems (more than 50).<P>\n 1028 Use the back button to return to the previous page and try again.<BR>\n 1029 If the problem is repeated you can report this to your instructor using the feedback button. 1030 <P> 1031 Because the WeBWorK server at the Unversity of Rochester is experiencing heavy use we have made downloading 1032 hard copies a low priority during the times of very heavy useage. It will be helpful if you 1033 download hard copies during times when the load is not too heavy. 1034 <P> 1035 The load is usually heaviest in the evenings , particularly a few hours before assignments 1036 are due. The best times to download hard copies are in the morning and afternoon 1037 -- or an hour after the due date and time of the previous assignment -- nobody is using the system then :-) 1038 </BLOCKQUOTE></BODY></HTML> 1039 }; 1040 my $do_problem_message = qq{Content-type: text/html\n\n 1041 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 1042 <HTML><BODY BGCOLOR = "FF99CC"> 1043 <BLOCKQUOTE><H3>WeBWorK heavy useage time out.</H3>\n 1044 <H4>Your request (action = $action) was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.</H4> 1045 This is probably because the 1046 WeBWorK server is extraordinarily busy.<P>\n 1047 You should be warned that WeBWorK response will be unusually slow. If possible you should try 1048 to use WeBWorK at another time when the load is not as high. The highest useage periods are in the 1049 evening, particularly in the two hours before assignments are due.<P>\n 1050 Use the back button to return to the previous page and try again.<P>\n 1051 If the high useage problem continues you can report this to your instructor using the feedback button. 1052 <P> 1053 1054 </BLOCKQUOTE></BODY></HTML> 1055 }; 1056 if ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { 1057 print $hard_copy_message; 1058 } else{ 1059 print $do_problem_message; 1060 } 1061 1062 1063 } 1064 1065 # begin Timing code 1066 if( $main::logTimingData == 1 ) { 1067 my $endTime = new Benchmark; 1068 my $error_str=''; 1069 1070 if ($main::SIGPIPE) { 1071 $error_str = 'broken PIPE--'; 1072 } elsif ($main::SIG_TIME_OUT) { 1073 $error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --"; 1074 } elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { 1075 $error_str = 'successful download -- '; 1076 } 1077 1078 &Global::logTimingInfo($main::beginTime,$endTime,$error_str.'welcomeAction.pl',$Course,$User); 1079 } 1080 # end Timing code 1081 1082 cleanup_downloadPS(); 1083 } 1084 1085 1;
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |