#!/usr/local/bin/webwork-perl ################################################################ # Copyright @1995-1999 by Michael E. Gage, Arnold K. Pizer and # WeBWorK at the University of Rochester. All rights reserved. ################################################################ my $debugON=0; use lib '.'; use webworkInit; # WeBWorKInitLine require 5.001; use strict; use Global; use Auth; use CGI qw(:standard); use Net::SMTP; use Safe; use PGtranslator; use vars qw($modules_to_evaluate $extra_packages_to_be_loaded); $/ ="\n"; BEGIN { # set to 1 to enable timing_log # (contains information about time taken by scripts to run) $main::logTimingData = 0; # begin Timing code if( $main::logTimingData == 1 ) { use Benchmark; $main::beginTime = new Benchmark; } # end Timing code # Setting these time out comstants to zeros removes the time constraint completely. (zero = infinity :=) ) $main::TIME_OUT_CONSTANT = 60; # one minute wait for on screen problems $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT = 1200; #twenty minutes $main::CLASS_DOWNLOAD_NICE = 5; # higher numbers indicated lower priorities # $main::DOWNLOAD_TIME_OUT_CONSTANT = 300; # give it five minutes # $main::DOWNLOAD_NICE = 2; # ATTENTION: The handlers PG_floating_point_exception_handler and PG_warnings_handler # have to be installed after CGI::Carp is called since it also # modifes the die and warn labels. Finding the right warning mechanism using these two # methods bears further investigation # They are defined in Global.pm $SIG{'FPE'} = \&Global::PG_floating_point_exception_handler; $SIG{__WARN__}=\&Global::PG_warnings_handler; $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $! stopped at $0\n"; }; $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $! stopped at $0\n"; }; $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) }; alarm($main::TIME_OUT_CONSTANT); # By explicitly catching the signals and dieing one forces the execution of the END statements which clean up the files. }; ################################################################################ # main ######################################################################### ################################################################################ &CGI::ReadParse; my %inputs=%main::in; my $query = $main::in{CGI}; # verify that the rest of the information has been received my $Course = $inputs{'course'}; my $User = $inputs{'user'}; my @local_psvns = $query -> param('local_psvns'); my $psvn = $local_psvns[0]; # get the first one for doing problem sets $inputs{'probSetKey'} = $psvn; # only used by htmlBOTTOM my $Session_key = $inputs{'key'}; &Global::getCourseEnvironment($Course); my $scriptDirectory = getWebworkScriptDirectory(); my $databaseDirectory = getCourseDatabaseDirectory(); my $courseScriptsDirectory = getCourseScriptsDirectory(); my $templateDirectory = getCourseTemplateDirectory(); my $tempDirectory = getCourseTempDirectory(); eval{require "${courseScriptsDirectory}$Global::displayMacros_pl";}; eval{require "${scriptDirectory}$Global::DBglue_pl";}; eval{require "${scriptDirectory}$Global::classlist_DBglue_pl";}; eval{require "${scriptDirectory}$Global::HTMLglue_pl";}; eval{require "${scriptDirectory}$Global::FILE_pl";}; # load the modules to be used in PGtranslator require "${courseScriptsDirectory}PG_module_list.pl" or wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl"); my $keyFile = &Global::getCourseKeyFile($Course); my $permissionsFile = &getCoursePermissionsFile($Course); # check to see if prob set has been selected if(not defined($psvn) or $psvn eq "") { selectionError(); exit; } # log access &Global::log_info('', query_string); &verify_key($inputs{'user'}, $Session_key, $keyFile, $Course); my $permissions = &get_permissions($User,$permissionsFile); &attachProbSetRecord($psvn); my $login_name_for_psvn = &getStudentLogin($psvn); attachCLRecord($login_name_for_psvn); my $setNumber=&getSetNumber($psvn); $setNumber = $inputs{'setNo'} if defined $inputs{'setNo'}; ## script called from profChangeDates.pl # keep strict happy -sh my $tempTexFileBaseName; # check to see that it is after the open date my ($currentTime,$odts,$ddts,$remainingTime, $TimeString); $currentTime = time; $odts=&getOpenDate($psvn); $ddts=&getDueDate($psvn); $remainingTime=$ddts-$currentTime; if($currentTime<$odts && $permissions !=$Global::instructor_permissions) { print &htmlTOP("Before open date error"); print "

Sorry, cannot download or do problem set $setNumber yet.
It is before the open date.

"; print &htmlBOTTOM("downloadPS.pl",\%inputs); exit(0); } my %PSVNHashForSet = %{getPSVNHashForSet($setNumber)}; my $action = $inputs{'action'}; my $downloadType= $inputs{'downloadType'}; # either pdf, ps, tex, or dvi # Verify that the problem set has been created if a psvn number has been passed unless ($action eq 'Get_all_copies') { unless (defined $PSVNHashForSet{$psvn} ) { print &htmlTOP("Problem set version number $psvn not created"); print ( "Pin number $psvn was not created for set $setNumber"); print &htmlBOTTOM("downloadPS.pl", \%inputs); exit(0); } } my $save_errors = ''; if ($action eq 'Do problem set' or $action eq 'Do_problem_set') { displayProbSet(); } elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { downloadAllSets(); } elsif ($action eq 'Get_all_copies') { downloadAllSets(); } else { wwerror($0, "Unknown action: $action"); } # begin Timing code #my $endTime = new Benchmark; #&Global::logTimingInfo($main::beginTime,$endTime,$0,$Course,$User); # end Timing code exit; ################################################################################ # displayProbSet ############################################################### ################################################################################ sub displayProbSet { my $studentName=&CL_getStudentName($login_name_for_psvn); my $probHeaderFileName = &getProbHeaderFileName($psvn); sub numerical { $a <=> $b}; my @problems=sort numerical &getAllProblemsForProbSetRecord($psvn); my $numberOfProblems = @problems; print &probSet_htmlTOP("Problem Set $setNumber from $inputs{'course'} for $studentName"); #see subroutines at the bottom of this file #this allows the use of a small gif for the webwork logo #and takes up less screen real estate. print &probSet_titleBar("Problem Set $setNumber from $inputs{'course'} for $studentName"); print <<"ENDOFHTML";
Select one of the $numberOfProblems problems to try:


"; my $practiceUser = $Global::practiceUser; if (($currentTime > $ddts) or ($User =~ /^$practiceUser/)) { print ' Show my old answers
'; } else { print ' Show my old answers
'; } print &sessionKeyInputs(\%inputs); my $mode = $inputs{'Mode'}; $mode = $Global::htmlModeDefault unless ($mode); &displaySelectModeLine($mode); ## displays mode select buttons ## displaySelectModeLine() is in "${courseScriptsDirectory}$Global::displayMacros_pl" print <<"ENDOFHTML";
$TimeString

ENDOFHTML print "

"; print &sessionKeyInputs(\%inputs); print <<"ENDOFHTML";

ENDOFHTML # process problem and save @printlines my $probHeader = $Global::PROB_HEADER; # default value if ((defined($probHeaderFileName)) and ($probHeaderFileName =~ /\S/)) { $probHeader = $probHeaderFileName; } # use $probHeader as default unless $probHeaderFileName is defined in the set definition file my $source; if (-e "${templateDirectory}$probHeader") { unless (-r "${templateDirectory}$probHeader") { wwerror($0, "Can't read ${templateDirectory}$probHeader"); } open(PROB,"<${templateDirectory}$probHeader"); $source = join("",); close(PROB); } # translate the problem header file my %envir=defineProblemEnvir($mode,0,$psvn,$Course); my $pt = new PGtranslator; # pt stands for problem translator; $pt->environment(\%envir); $pt->initialize(); $pt->set_mask(); $pt->source_string($source); $pt->unrestricted_load("${courseScriptsDirectory}PG.pl"); $pt->unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); $pt->translate(); my $PG_PROBLEM_TEXT_REF = $pt->ra_text(); my $PG_HEADER_TEXT_REF = $pt->r_header; #\$PG_HEADER_TEXT; my $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; my $PG_FLAGS_REF = $pt->rh_flags; my @printlines; if($mode eq "HTML" || $mode eq 'HTML_tth') { @printlines = @{$PG_PROBLEM_TEXT_REF}; #@printlines = @{$pt->ra_text()}; } elsif ($mode eq 'Latex2HTML') { @printlines = &createDisplayedInsert($setNumber,$probHeader,$psvn,$Course,$PG_PROBLEM_TEXT_REF); } print @printlines; print "
"; print &htmlBOTTOM('welcomeAction.pl', \%inputs,'probSetHelp.html'); } ################################################################################ # downloadAllSets (and related subroutines) #################################### ################################################################################ ################### # downloadAllSets # ################### sub downloadAllSets { system("/usr/bin/renice +$main::CLASS_DOWNLOAD_NICE -p $$ 1>/dev/null") && warn "Could not renice process. pid $$"; alarm( $main::CLASS_DOWNLOAD_TIME_OUT_CONSTANT); my $downloadMulti = "unknown"; $downloadMulti = "multistudent" if $action eq "Get_all_copies"; $downloadMulti = "multiset" if $action eq "Get_hard_copy"; my @psvns_to_download = $query->param('local_psvns'); my $num_psvns_to_download = @psvns_to_download; my $max_psvns_to_download = $Global::max_num_of_ps_downloads_allowed; if($num_psvns_to_download > 1 and $permissions != $Global::instructor_permissions) { wwerror("Non-professors are not permitted to download more than one problem set at a time."); } if(@psvns_to_download > $Global::max_num_of_ps_downloads_allowed) { my $tooManyWhat = $downloadMulti eq "multiset" ? "problem sets" : "students"; wwerror("Too many $tooManyWhat are selected for download.", "The maximum number of $tooManyWhat which can be downloaded at one time is $Global::max_num_of_ps_downloads_allowed." ." You selected $num_psvns_to_download. Go back and select fewer $tooManyWhat." ." (This maximun is set by the variable \$max_num_of_ps_downloads_allowed in Global.pm.)"); } my ($cumulativeTexSource, $currentTexSourceRef, $currentTexSource, $currentTexErrorRef); # this could be used when eliminating pre-foreach createTexSourceHandleErrors call # s/\\end\{document\}.*?\\begin\{document\}/\n\\newpage\n/s; $tempTexFileBaseName = "${tempDirectory}Temp_downloadAllSets_$User"; my $first_psvn = $psvns_to_download[0]; my $current_psvn = shift @psvns_to_download; ($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn); @psvns_to_download = () if(@$currentTexErrorRef); $currentTexSource = $$currentTexSourceRef; $currentTexSource =~ s|\\end\{document\}\s$|\n|s; $cumulativeTexSource .= $currentTexSource; foreach $current_psvn (@psvns_to_download) { ($currentTexSourceRef, $currentTexErrorRef) = createTexSource($current_psvn); @psvns_to_download = () if(@$currentTexErrorRef); $currentTexSource = $$currentTexSourceRef; $currentTexSource =~ s|^.*?\\begin\{document\}|\n\\newpage\n|s; $currentTexSource =~ s|\\end\{document\}\s$|\n|s; $cumulativeTexSource .= $currentTexSource; } $cumulativeTexSource .= "\n\\end{document}\n"; open TEXOUTPUT, ">$tempTexFileBaseName.tex" or wwerror("Can't open $tempTexFileBaseName.tex for output."); print TEXOUTPUT $cumulativeTexSource; close TEXOUTPUT; if(@$currentTexErrorRef) { PG_error_print($tempTexFileBaseName, $current_psvn, @$currentTexErrorRef); } else { $downloadType = lc $downloadType; my $mimeType = prepareHardcopy($tempTexFileBaseName, $downloadType); my ($setName, $userName); &attachProbSetRecord($first_psvn); if($downloadMulti eq "multistudent") { if($num_psvns_to_download == 1) { $setName = getSetNumber($first_psvn); $userName = getStudentLogin($first_psvn); } else { $setName = getSetNumber($first_psvn); $userName = "multistudent"; } } elsif($downloadMulti eq "multiset") { if($num_psvns_to_download == 1) { $setName = getSetNumber($first_psvn); $userName = getStudentLogin($first_psvn); } else { $setName = "multiset"; $userName = getStudentLogin($first_psvn); } } my $hardCopyName = "$Course.$userName.$setName.$downloadType"; open(TEXINPUT, "$tempTexFileBaseName.$downloadType") or wwerror($0, "Can't open $tempTexFileBaseName.$downloadType: $!\n"); print "Content-type: $mimeType\n"; print "Content-disposition: attachment; filename=\"$hardCopyName\"\n\n"; print while (); close TEXINPUT; } } ################### # createTexSource # ################### sub createTexSource { my $psvn = shift; # Check that the psvn corresponds to the user and that it is after the open date. # This should only fail if someone is trying to break into WeBWorK. &attachProbSetRecord($psvn); $login_name_for_psvn = &getStudentLogin($psvn); attachCLRecord($login_name_for_psvn); if ((($User ne &getStudentLogin($psvn)) ||($currentTime < $odts)) and ($permissions != $Global::instructor_permissions) and ($permissions != $Global::TA_permissions)) { &hackerError; exit; } my $probSetHeader = $Global::SET_HEADER; my $setHeaderFileName = &getSetHeaderFileName($psvn); my $answersRequestedQ = 0; $answersRequestedQ= $inputs{'ShowAns'} if defined($inputs{'ShowAns'}); my $adts=&getAnswerDate($psvn); my $displayCorrectAnswersQ = 0; #initialize $displayCorrectAnswersQ =1 if $answersRequestedQ && ($currentTime > $adts); $displayCorrectAnswersQ =1 if $answersRequestedQ && ($permissions == $Global::instructor_permissions); my $texSource =''; print STDERR "%%Creating a tex version of set $setNumber
\n" if $debugON; print STDERR "%%For", &CL_getStudentName($login_name_for_psvn), "psvn=$psvn
\n" if $debugON; # print TeX preamble and header $texSource .= &texInput($Global::TEX_SET_PREAMBLE); $texSource .= &texInput($Global::TEX_SET_HEADER); # print set header my $mode = "TeX"; my @PG_COMPILE_ERRORS = (); if ((defined($setHeaderFileName)) and $setHeaderFileName =~ /\S/) { $probSetHeader = $setHeaderFileName; } if (open(INPUT,"${templateDirectory}$probSetHeader")) { $probSetHeader =~ /\.([^\.]*)$/; my $displayMode = $1; if ($displayMode eq 'pg') { my %envir=defineProblemEnvir($mode, 0, $psvn, $Course, undef()); my $input_string= join("",); my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF); # BEGIN fork if (open TEX_PIPE, "-|") { # parent: local $/ = "\n"; my $curr_pg_compile_error = ; chomp $curr_pg_compile_error; push @PG_COMPILE_ERRORS, $curr_pg_compile_error if $curr_pg_compile_error; undef $/; $texSource .= ; } else { # child: $texSource = ''; # clear this at beginning of fork @PG_COMPILE_ERRORS = (); # clear this as well # ----- my $pt = new PGtranslator; $pt -> evaluate_modules( @{main::modules_to_evaluate}) ; $pt -> load_extra_packages(@{main::extra_packages_to_be_loaded}); # The variables in the two preceding lines are defined in PG_module_list.pl # require "${courseScriptsDirectory}PG_module_list.pl"; # (Modules are defined by require statement above found near the top of this file) $pt->environment(\%envir); $pt->initialize(); $pt->set_mask(); $pt->source_string($input_string); $pt->unrestricted_load("${courseScriptsDirectory}PG.pl"); $pt->unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); $pt->translate(); $PG_PROBLEM_TEXT_REF = $pt->ra_text(); $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; $PG_ANSWER_HASH_REF = $pt->rh_correct_answers; $PG_FLAGS_REF = $pt->rh_flags; $texSource .= join '', @{$PG_PROBLEM_TEXT_REF}; # begin non-FORK code # if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} == 1) { # push(@PG_COMPILE_ERRORS, qq{$probSetHeader} ); # } # end non-FORK code # begin FORK-only code my $stupid_forked_error_string; if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { $texSource = qq{$probSetHeader} . "\n" . $texSource; } else { $texSource = "\n" . $texSource; } # end FORK code if (defined($Global::WARNINGS) and $Global::WARNINGS) { my $warnings = '{\\bf WARNINGS:\par{\\tiny ' . $Global::WARNINGS . ' }}'; $warnings =~ s|/|\\\-/|g; # allow linebreaks in the middle of URLs $warnings =~ s/
/\\par\n/ig; # introduce breaks at linebreaks and paragraphs $warnings =~ s/

/\\par\n/ig; $warnings =~ s/\#/\\\#/g; # protect against some of the symbols which are reserved in tex $warnings =~ s/\_/\\\_/g; $warnings =~ s/\>/\\\>/g; $warnings =~ s/\\n"; } close INPUT; } else { print STDERR ( "Can't open ${templateDirectory}${probSetHeader}\n") if $debugON; wwerror("$0", "\n######## Could not open the set header file: ${templateDirectory}${probSetHeader}","",""); } # Print problems my @problems = sort { $a <=> $b } &getAllProblemsForProbSetRecord($psvn); my @refSubmittedAnswers = (); my $probNum; foreach $probNum (@problems) { my $source; my $probFileName = &getProblemFileName($probNum,$psvn); if (-e "${templateDirectory}$probFileName") { unless (-r "${templateDirectory}$probFileName") { wwerror($0, "Can't read ${templateDirectory}$probFileName"); } open(PROB,"<${templateDirectory}$probFileName"); $source = join("",); close(PROB); } local($^W) =0; ##########CHANGE THIS BACK!!!! # what do you mean by that? my %envir=defineProblemEnvir('TeX',$probNum,$psvn,$Course,undef()); my ($PG_PROBLEM_TEXT_REF, $PG_HEADER_TEXT_REF, $PG_ANSWER_HASH_REF, $PG_FLAGS_REF,$PG_EVALUATED_ANSWERS_REF); # BEGIN fork if (open TEX_PIPE, "-|") { # parent: local $/ = "\n"; my $curr_pg_compile_error = ; chomp $curr_pg_compile_error; push @PG_COMPILE_ERRORS, $curr_pg_compile_error if $curr_pg_compile_error; undef $/; $texSource .= ; } else { # child: $texSource = ''; # clear this at beginning of fork @PG_COMPILE_ERRORS = (); # clear this as well # ----- my $pt = new PGtranslator; #pt stands for problem translator; $pt->environment(\%envir) ; $pt->initialize(); $pt-> set_mask(); $pt->source_string($source); $pt->unrestricted_load("${courseScriptsDirectory}PG.pl"); $pt->unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl"); $pt->translate(); $PG_PROBLEM_TEXT_REF = $pt->ra_text(); $PG_HEADER_TEXT_REF = $pt->r_header;#\$PG_HEADER_TEXT; #$PG_ANSWER_HASH_REF = $pt->rh_correct_answers; $PG_EVALUATED_ANSWERS_REF = $pt->process_answers; $PG_FLAGS_REF = $pt ->rh_flags; $texSource .= join '', @{$PG_PROBLEM_TEXT_REF}; # begin non-FORK code # if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { # push(@PG_COMPILE_ERRORS, qq{$probNum} ); # } # end non-FORK code # begin FORK-only code if (defined($PG_FLAGS_REF->{'error_flag'}) and $PG_FLAGS_REF->{'error_flag'} ==1) { $texSource = qq{$probNum} . "\n" . $texSource; } else { $texSource = "\n" . $texSource; } # end FORK code if ($displayCorrectAnswersQ) { my %correctAnswerHash = (); my @correctAnswerList = (); my %submittedAnswerHash = (); if (ref($PG_EVALUATED_ANSWERS_REF) eq 'HASH') { %correctAnswerHash = %$PG_EVALUATED_ANSWERS_REF; } else { warn "ERROR: Please pass the PG answer list as a hash not a list."; } if (%correctAnswerHash) { my ($correctFlag,$normalizedCorrectAnswer, $normalizedSubmittedAnswer, $answerMessage) = (); # determine the correct order for the answers my @answer_entry_order = (defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER})) ? @{$pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}} : keys %{$pt->rh_evaluated_answers}; $texSource .= "Correct Answers:\\par\\begin{itemize}\n"; foreach my $ky (@answer_entry_order) { $normalizedCorrectAnswer = $correctAnswerHash{$ky}->{correct_ans}; $normalizedCorrectAnswer =~ s/\^/\\\^\{\}/g; $normalizedCorrectAnswer =~ s/\_/\\\_/g; $texSource .= "\\item $normalizedCorrectAnswer\n"; } $texSource .= "\\end{itemize} \\par\n"; } } if (defined($Global::WARNINGS) and $Global::WARNINGS) { my $warnings = '{\\bf WARNINGS:\par{\\tiny ' . $Global::WARNINGS . ' }}'; unless (@PG_COMPILE_ERRORS) { # prepare warnings for TeX output in this case $warnings =~ s|/|\\\-/|g; # allow linebreaks in the middle of URLs $warnings =~ s/
/\\par\n/ig; # introduce breaks at linebreaks and paragraphs $warnings =~ s/

/\\par\n/ig; $warnings =~ s/\#/\\\#/g; # protect against some of the symbols which are reserved in tex $warnings =~ s/\_/\\\_/g; $warnings =~ s/\>/\\\>/g; $warnings =~ s/\/dev/null 2>/dev/null"; my $psCommandLine = "$Global::externalDvipsPath -o $texFileBaseName.ps $texFileBaseName.dvi >/dev/null 2>/dev/null"; my $pdfCommandLine = "$Global::externalGsPath -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$texFileBaseName.pdf -c save pop -f $texFileBaseName.ps"; # my $pdfCommandLine = "$Global::externalPs2pdfPath $texFileBaseName.ps $texFileBaseName.pdf"; # make sure that you are not using old copies of the following files: unlink("$texFileBaseName.dvi","$texFileBaseName.ps", "$texFileBaseName.pdf"); # we use logPrint() for TeX->DVI errors as they are usually caused if($targetFormat eq "pdf") { system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); system($psCommandLine); -e "$texFileBaseName.ps" or die "ps generation failed."; system($pdfCommandLine); -e "$texFileBaseName.pdf" or die "pdf generation failed."; $mimeType = "application/pdf"; } elsif($targetFormat eq "ps") { system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); system($psCommandLine); -e "$texFileBaseName.ps" or die "ps generation failed."; $mimeType = "application/postscript"; } elsif($targetFormat eq "dvi") { system($dviCommandLine); -e "$texFileBaseName.dvi" or &logPrint($texFileBaseName); $mimeType = "application/x-dvi"; } elsif($targetFormat eq "tex") { $mimeType = "application/tex"; } else { die "unrecognized format: $targetFormat"; } return $mimeType; } ################## # PG_error_print # ################## sub PG_error_print { my ($tempTexFileBaseName, $current_psvn, @errors) = @_; # get set name and student name from psvn &attachProbSetRecord($current_psvn); my $userName = &getStudentLogin($current_psvn); my $setName = &getSetNumber($current_psvn); # print error page header print &htmlTOP("PG compile error"); print "

PG error while compiling problem number", (@errors>1) ? 's ' : ' ', join(', ', @errors), " in problem set $setName for $userName.

"; print "

TeX source file:

"; # open temp tex file if(open TEXINPUT, "$tempTexFileBaseName.tex") { print "
\n";
		my $lineNumber = 1;
		while() {
			if(/\n";
		close TEXINPUT;
	} else {
		print "

Unable to open TeX source file:
$tempTexFileBaseName.tex

"; } # print page footer print &htmlBOTTOM("welcomeAction.pl", \%inputs); exit; } sub logPrint { my $texFileBaseName=shift; print &htmlTOP("TeX Error or error in creating PostScript file"); open (LOGFILE, " $texFileBaseName.log") || print "

Can't open log file:

path= $texFileBaseName.log
$!

" ; print "

TeX Error Log:

"; my $print_error_switch = ($debugON) ? 1: 0; my $out=''; #warn ord $/, ord "\n", ord "\r"; #warn "length of separator = ", length($/); $/ = "\n"; #warn ord $/, ord "\n", ord "\r"; while () { $out = $_; $print_error_switch = 1 if $out =~ /^!/; # after a fatal error start printing messages print protect_HTML($out)."
\n" if $print_error_switch; } close(LOGFILE); open (TEXFILE, "$texFileBaseName.tex") || print "

Can't open tex source file:

path= $texFileBaseName.tex:
$!

\n"; print "
\n

TeX Source File:


\n"; print "
";

    my $lineNumber = 1;
    while () {
		print protect_HTML("$lineNumber $_")."\n";
        $lineNumber++;
    }
    close(TEXFILE);
    print "
"; print &htmlBOTTOM("welcomeAction.pl", \%inputs); } sub protect_HTML { my $line = shift; chomp($line); $line =~s/\&/&/g; $line =~s//>/g; $line; } sub selectionError { print &htmlTOP("Selection error"); print"

Error:

You must first select a problem set in order to download a hard copy!\n"; print "

"; print &sessionKeyInputs(\%inputs); print <<"ENDOFHTML";

ENDOFHTML print &htmlBOTTOM("welcomeAction.pl", \%inputs); } sub probSet_htmlTOP { my ($title, $bg_url) = @_; my $background_url = $bg_url || $Global::background_plain_url; my $out = < $title

ENDhtmlTOP $out; } sub probSet_titleBar { my ($title) = @_; my $title_bar = ""; $title_bar .= qq{
WeBWorK

$title

}; my $inputkeys = &sessionKeyInputs(\%inputs); $title_bar .= qq{ $inputkeys

}; $title_bar; } sub hackerError { ## prints hacker error message my $msg = "Attempt to hack into WeBWorK \n Remote Host is: ". remote_host()."\n"; $msg .= query_string; &Global::log_error('hacker error', $msg); ## log attempt ## notify by email my $toAdd = $Global::feedbackAddress; my $emailMsg = "To: $toAdd Subject: Attempt to hack into WeBWorK Here are the details on the attempt to hack into weBWorK:\n $msg \n"; my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20); $smtp->mail($Global::webmaster); $smtp->recipient($Global::feedbackAddress); $smtp->data($msg); $smtp->quit; # my $SENDMAIL = $Global::SENDMAIL; # open (MAIL,"|$SENDMAIL"); # print MAIL "$emailMsg"; # close (MAIL); print &htmlTOP("Hacker Error"), "

Error:Please do not try to hack into WeBWorK!

", startform(-action=>"${Global::cgiWebworkURL}${Global::welcomeAction_CGI}"), "

", &sessionKeyInputs(\%inputs), hidden(-name=>'local_psvns', -value=>$psvn), hidden(-name=>'action', -value=>'Do_problem_set'), submit(-value=>"Return to Problem Set"), endform(), &htmlBOTTOM($0, \%inputs); } sub defineProblemEnvir { my ($mode,$probNum,$psvn,$courseName,$refSubmittedAnswers) = @_; my %envir=(); my $loginName = &getStudentLogin($psvn); ##how to put an array submittedAnswers in a hash?? $envir{'refSubmittedAnswers'} = $refSubmittedAnswers if defined($refSubmittedAnswers); $envir{'psvnNumber'} = $psvn; $envir{'psvn'} = $psvn; $envir{'studentName'} = &CL_getStudentName($loginName); $envir{'studentLogin'} = $loginName; $envir{'sectionName'} = &CL_getClassSection($loginName); $envir{'sectionNumber'} = &CL_getClassSection($loginName); $envir{'recitationName'} = &CL_getClassRecitation($loginName); $envir{'recitationNumber'} = &CL_getClassRecitation($loginName); $envir{'setNumber'} = &getSetNumber($psvn); $envir{'questionNumber'} = $probNum; $envir{'probNum'} = $probNum; $envir{'openDate'} = &getOpenDate($psvn); $envir{'formatedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn)); $envir{'formattedOpenDate'} = &formatDateAndTime(&getOpenDate($psvn)); $envir{'dueDate'} = &getDueDate($psvn); $envir{'formatedDueDate'} = &formatDateAndTime(&getDueDate($psvn)); $envir{'formattedDueDate'} = &formatDateAndTime(&getDueDate($psvn)); $envir{'answerDate'} = &getAnswerDate($psvn); $envir{'formatedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn)); $envir{'formattedAnswerDate'} = &formatDateAndTime(&getAnswerDate($psvn)); $envir{'problemValue'} = &getProblemValue($probNum,$psvn); $envir{'fileName'} = &getProblemFileName($probNum,$psvn); $envir{'probFileName'} = &getProblemFileName($probNum,$psvn); $envir{'languageMode'} = $mode; $envir{'displayMode'} = $mode; $envir{'outputMode'} = $mode; $envir{'courseName'} = $courseName; $envir{'sessionKey'} = ( defined($inputs{'key'}) ) ?$inputs{'key'} : " "; # initialize constants for PGanswermacros.pl $envir{'numRelPercentTolDefault'} = getNumRelPercentTolDefault(); $envir{'numZeroLevelDefault'} = getNumZeroLevelDefault(); $envir{'numZeroLevelTolDefault'} = getNumZeroLevelTolDefault(); $envir{'numAbsTolDefault'} = getNumAbsTolDefault(); $envir{'numFormatDefault'} = getNumFormatDefault(); $envir{'functRelPercentTolDefault'} = getFunctRelPercentTolDefault(); $envir{'functZeroLevelDefault'} = getFunctZeroLevelDefault(); $envir{'functZeroLevelTolDefault'} = getFunctZeroLevelTolDefault(); $envir{'functAbsTolDefault'} = getFunctAbsTolDefault(); $envir{'functNumOfPoints'} = getFunctNumOfPoints(); $envir{'functVarDefault'} = getFunctVarDefault(); $envir{'functLLimitDefault'} = getFunctLLimitDefault(); $envir{'functULimitDefault'} = getFunctULimitDefault(); $envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration(); $envir{'numOfAttempts'} = undef(); # this is defined only for problems # defining directorys and URLs $envir{'templateDirectory'} = &getCourseTemplateDirectory(); $envir{'classDirectory'} = $Global::classDirectory; $envir{'cgiDirectory'} = $Global::cgiDirectory; $envir{'macroDirectory'} = getCourseMacroDirectory(); $envir{'courseScriptsDirectory'} = getCourseScriptsDirectory(); $envir{'htmlDirectory'} = getCourseHtmlDirectory(); $envir{'htmlURL'} = getCourseHtmlURL(); $envir{'tempDirectory'} = getCourseTempDirectory(); $envir{'tempURL'} = getCourseTempURL(); $envir{'scriptDirectory'} = $Global::scriptDirectory; $envir{'webworkDocsURL'} = $Global::webworkDocsURL; $envir{'externalTTHPath'} = $Global::externalTTHPath; $envir{'inputs_ref'} = \%inputs; my $seed = &getProblemSeed($probNum, $psvn); $seed = 1111 unless defined($seed); $envir{'problemSeed'} = $seed if defined($seed); # here is a way to pass environment variables defined in webworkCourse.ph my $k; foreach $k (keys %Global::PG_environment ) { $envir{$k} = $Global::PG_environment{$k}; } %envir; } ################################################################################ # cleanup routines ############################################################# ################################################################################ BEGIN { # This subroutine cleans up temporary files after the postscript copy has been created. sub cleanup_downloadPS { unless (defined($action) and ($action eq 'Do problem set' or $action eq 'Do_problem_set')) { my $ERRORS = $save_errors; unless ($debugON) { eval { chdir $tempDirectory; unlink( "#tempTexFileBaseName.dvi", "$tempTexFileBaseName.ps", "$tempTexFileBaseName.pdf", "$tempTexFileBaseName.log", "$tempTexFileBaseName.aux", "$tempTexFileBaseName.tex" ); unlink("${tempDirectory}eps/${login_name_for_psvn}*.eps"); }; $ERRORS .= $ERRORS . $@; } my $query = query_string(); $query = "" unless defined($query); wwerror("$0", "ERROR: in downloadPS subroutine of welcomeAction.pl $ERRORS","","",$query) if $ERRORS; } } } END { if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) { alarm(0); # turn off the alarm my $hard_copy_message = qq{Content-type: text/html\n\n

WeBWorK hard copy download time out.

\n

This download was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.

This may be because the WeBWorK server is extraordinarily busy, or because there was an error in the problem, or because you tried to download a set with too many problems (more than 50).

\n Use the back button to return to the previous page and try again.
\n If the problem is repeated you can report this to your instructor using the feedback button.

Because the WeBWorK server at the Unversity of Rochester is experiencing heavy use we have made downloading hard copies a low priority during the times of very heavy useage. It will be helpful if you download hard copies during times when the load is not too heavy.

The load is usually heaviest in the evenings , particularly a few hours before assignments are due. The best times to download hard copies are in the morning and afternoon -- or an hour after the due date and time of the previous assignment -- nobody is using the system then :-)

}; my $do_problem_message = qq{Content-type: text/html\n\n

WeBWorK heavy useage time out.

\n

Your request (action = $action) was cancelled because it took more than $main::TIME_OUT_CONSTANT seconds.

This is probably because the WeBWorK server is extraordinarily busy.

\n You should be warned that WeBWorK response will be unusually slow. If possible you should try to use WeBWorK at another time when the load is not as high. The highest useage periods are in the evening, particularly in the two hours before assignments are due.

\n Use the back button to return to the previous page and try again.

\n If the high useage problem continues you can report this to your instructor using the feedback button.

}; if ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { print $hard_copy_message; } else{ print $do_problem_message; } } # begin Timing code if( $main::logTimingData == 1 ) { my $endTime = new Benchmark; my $error_str=''; if ($main::SIGPIPE) { $error_str = 'broken PIPE--'; } elsif ($main::SIG_TIME_OUT) { $error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --"; } elsif ($action eq 'Get hard copy' or $action eq 'Get_hard_copy') { $error_str = 'successful download -- '; } &Global::logTimingInfo($main::beginTime,$endTime,$error_str.'welcomeAction.pl',$Course,$User); } # end Timing code cleanup_downloadPS(); } 1;