[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator / Problem.pm Repository:
ViewVC logotype

Diff of /trunk/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 391 Revision 392
4use lib '/Users/gage/webwork-modperl/lib'; 4use lib '/Users/gage/webwork-modperl/lib';
5use PGtranslator5; 5use PGtranslator5;
6use WeBWorK::ContentGenerator; 6use WeBWorK::ContentGenerator;
7use Apache::Constants qw(:common); 7use Apache::Constants qw(:common);
8 8
9###############################################################################
10# Configuration
11###############################################################################
12
13my $COURSE_SCRIPTS_DIRECTORY = '/Users/gage/webwork/system/courseScripts/';
14my $MACRO_DIRECTORY = '/Users/gage/webwork/courseData/templates/macro/';
15my $TEMPLATE_DIRECTORY = '/Users/gage/webwork/rochester_problib/';
16my $TEMP_URL = 'http://127.0.0.1/~gage/rochester_problibtmp/';
17##my $HTML_DIRECTORY = '/Users/gage/Sites/rochester_problib/' #already obtained from courseEnvironment
18my $HTML_URL = 'http://127.0.0.1/~gage/rochester_problib/';
19
20###############################################################################
21# End configuration
22###############################################################################
23
9sub title { 24sub title {
10 my ($self, $problem_set, $problem) = @_; 25 my ($self, $problem_set, $problem) = @_;
11 my $r = $self->{r}; 26 my $r = $self->{r};
12 my $user = $r->param('user'); 27 my $user = $r->param('user');
13 return "Problem $problem of problem set $problem_set for $user"; 28 return "Problem $problem of problem set $problem_set for $user";
14} 29}
15 30
31###############################################################################
32#
33# INITIALIZATION
34#
35# The following code initializes an instantiation of PGtranslator5 in the
36# parent process. This initialized object is then share with each of the
37# children forked from this parent process by the daemon.
38#
39# As far as I can tell, the child processes don't share any variable values even
40# though their namespaces are the same.
41###############################################################################
42# First some dummy values to use for testing.
43# These should be available from the problemEnvironment(it might be ok to assume that PG and dangerousMacros
44# live in the courseScripts (system level macros) directory.
45
46print STDERR "Begin intitalization\n";
47my $dummy_envir = { courseScriptsDirectory => $COURSE_SCRIPTS_DIRECTORY,
48 displayMode => 'HTML_tth',
49 macroDirectory => $MACRO_DIRECTORY,
50 cgiURL => 'foo_cgiURL'};
51
52
53my $PG_PL = "${COURSE_SCRIPTS_DIRECTORY}PG.pl";
54my $DANGEROUS_MACROS_PL = "${COURSE_SCRIPTS_DIRECTORY}dangerousMacros.pl";
55my @MODULE_LIST = ( "Exporter", "DynaLoader", "GD", "WWPlot", "Fun",
56 "Circle", "Label", "PGrandom", "Units", "Hermite",
57 "List", "Match","Multiple", "Select", "AlgParser",
58 "AnswerHash", "Fraction", "VectorField", "Complex1",
59 "Complex", "MatrixReal1", "Matrix","Distributions",
60 "Regression"
61);
62my @EXTRA_PACKAGES = ( "AlgParserWithImplicitExpand", "Expr",
63 "ExprWithImplicitExpand", "AnswerEvaluator",
64
65);
66$INITIAL_MACRO_PACKAGES = <<END_OF_TEXT;
67 DOCUMENT();
68 loadMacros(
69 "PGbasicmacros.pl",
70 "PGchoicemacros.pl",
71 "PGanswermacros.pl",
72 "PGnumericalmacros.pl",
73 "PGgraphmacros.pl",
74 "PGauxiliaryFunctions.pl",
75 "PGmatrixmacros.pl",
76 "PGcomplexmacros.pl",
77 "PGstatisticsmacros.pl"
78
79 );
80
81 TEXT("Hello world");
82
83 ENDDOCUMENT();
84
85END_OF_TEXT
86
87#These here documents have their drawbacks. KEEP END_OF_TEXT left justified!!!!!!
88
89###############################################################################
90# Now to define the body subroutine which does the hard work.
91###############################################################################
92
93
94#my $SOURCE1 = $INITIAL_MACRO_PACKAGES;
95
16sub body { 96sub body {
17 my ($self, $problem_set, $problem) = @_; 97 my ($self, $problem_set, $problem) = @_;
18 my $r = $self->{r}; 98 my $r = $self->{r};
19 my $courseEnvironment = $self->{courseEnvironment}; 99 my $courseEnvironment = $self->{courseEnvironment};
20 my $user = $r->param('user'); 100 my $user = $r->param('user');
21 101
102
103 my $SOURCE1 = readFile('set0/prob1c.pg');
104 print STDERR "SOURCEFILE: \n$SOURCE1\n\n";
105
106 ###########################################################################
107 # The pg problem class should have a method for installing it's problemEnvironment
108 ###########################################################################
109
110 $problemEnvir_rh = defineProblemEnvir($self);
111
112
113 ##################################################################################
114 # Prime the PGtranslator object and set it loose
115 ##################################################################################
116
117
118 ###############################################################################
119
120 ###############################################################################
121 #Create the PG translator.
122 ###############################################################################
123
124 my $pt = new PGtranslator5; #pt stands for problem translator;
125
126
127 # All of these hard coded directories need to be drawn from courseEnvironment.
128 # In addition I don't think that PGtranslator uses this stack internally yet.
129 # Passing these directories through the problemEnvironment variable is what
130 # is currently being done, but I don't think it is quite right, at least for most
131 # of them.
132
133
134 $pt ->rh_directories( { courseScriptsDirectory => $COURSE_SCRIPTS_DIRECTORY,
135 macroDirectory => $MACRO_DIRECTORY,
136 ,
137 templateDirectory => $TEMPLATE_DIRECTORY,
138 tempDirectory => $TEMP_DIRECTORY,
139 }
140 );
141
142 ###############################################################################
143 # First we load the modules from courseScripts directory.
144 # These do the "heavy lifting" in terms of formatting, creating graphs, and
145 # performing other heavy duty algorithms.
146 #
147 ###############################################################################
148
149 $pt -> evaluate_modules( @MODULE_LIST);
150 $pt -> load_extra_packages( @EXTRA_PACKAGES );
151
152 ###############################################################################
153 # Load the environment constants. Some are used by the PGtranslator object but
154 # most of them are installed inside the Safe compartment where the problem
155 # runs.
156 ###############################################################################
157 #$pt -> environment($dummy_envir);
158 $pt -> environment($problemEnvir_rh);
159
160
161 # I've forgotten what this does exactly :-)
162 $pt->initialize();
163
164 ###############################################################################
165 # PG.pl contains the basic code which defines the problem interface, input and output.
166 # dangerousMacros.pl contains subroutines which have access to the hard drive and
167 # and the directory structure. All use of external resources by the problem is supposed
168 # to go through these subroutines. The idea is to put the potentially dangerous
169 # algorithms in on place so they can be watched closely.
170 # These two files are evaluated in the Safe compartment without any restrictions.
171 # They have full use of the perl commands.
172 ###############################################################################
173 my $loadErrors = $pt -> unrestricted_load($PG_PL );
174 print STDERR "$loadErrors\n" if ($loadErrors);
175 $loadErrors = $pt -> unrestricted_load($DANGEROUS_MACROS_PL);
176 print STDERR "$loadErrors\n" if ($loadErrors);
177
178 ###############################################################################
179 # Now set the mask to restrict the operations which can be performed within
180 # a problem or a macro file.
181 ###############################################################################
182 $pt-> set_mask();
183
184 # print "\nPG.pl: $PG_PL<br>\n";
185 # print "DANGEROUS_MACROS_PL: $DANGEROUS_MACROS_PL<br>\n";
186 # print "Print dummy environment<br>\n";
187 # print pretty_print_rh($dummy_envir), "<p>\n\n";
188
189 # Read in the source code for the problem
190
191 #$INITIAL_MACRO_PACKAGES =~ tr /\r/\n/; # change everything to unix line endings.
192 $SOURCE1 =~ tr /\r/\n/;
193 #print STDERR "Source again \n $SOURCE1";
194 $pt->source_string( $SOURCE1 );
195
196 ###############################################################################
197 # Install a safety filter for screening student answers. The default is now the blank
198 # filter since the answer evaluators do a pretty good job of recompiling and screening
199 # student's answers. Still, you could prohibit back ticks, or something of the kind.
200 ###############################################################################
201
202 $pt ->rf_safety_filter( \&safetyFilter); # install blank safety filter
203
204
205 print STDERR "New PGtranslator object inititialization completed.<br>\n";
206 ################################################################################
207 ## This ends the initialization of the PGtranslator object
208 ################################################################################
209
210
211 ################################################################################
212 # Run the problem (output the html text) but also store it within the object.
213 # The correct answers are also calculated and stored within the object
214 ################################################################################
215 $pt ->translate();
216
217 #print problem output
22 print "Problem goes here<p>\n"; 218 print "Problem goes here<p>\n";
219 print "Problem output <br>\n";
220 print "################################################################################<br<br>";
221 print ${$pt->r_text()};
222 print "<br><br>################################################################################<br>";
223 print "<p>End of problem output<br>";
224
225
226 #print source code
227 print "Source code<pre>\n";
228 print $SOURCE1;
229 print "</pre>End source code<p>";
230 ################################################################################
231 # The format for the output is described here. We'll need a local variable
232 # to handle the warnings. From within the problem the warning command
233 # has been slaved to the __WARNINGS__ routine which is defined in Global.
234 # We'll need to provide an alternate mechanism.
235 # The base64 encoding is only needed for xml transmission.
236 ################################################################################
237 print "################################################################################<br>";
238 print "Warnings output<br>";
239 my $WARNINGS = "Let this be a warning:";
240
241 print $WARNINGS;
242
243 ################################################################################
244 # Install the standard problem grader. See gage/xmlrpc/daemon.pm or processProblem8 for detailed
245 # code on how to choose which problem grader to install, depending on courseEnvironment and problem data.
246 # See also PG.pl which provides for problem by problem overrides.
247 ################################################################################
248
249 $pt->rf_problem_grader($pt->rf_std_problem_grader);
250
251 ################################################################################
252 # creates and stores a hash of answer results inside the object: $rh_answer_results
253 ################################################################################
254 $pt -> process_answers($rh->{envir}->{inputs_ref});
255
256
257 # THE UPDATE AND GRADING LOGIC COULD USE AN OVERHAUL. IT WAS SOMEWHAT CONSTRAINED
258 # BY LEGACY CONDITIONS IN THE ORIGINAL PROCESSPROBLEM8. IT'S NOT BAD
259 # BUT IT COULD PROBABLY BE MADE A LITTLE MORE STRAIGHT FORWARD.
260 ################################################################################
261 # updates the problem state stored by the translator object from the problemEnvironment data
262 ################################################################################
263
264 # $pt->rh_problem_state({ recorded_score => $rh->{problem_state}->{recorded_score},
265 # num_of_correct_ans => $rh->{problem_state}->{num_of_correct_ans} ,
266 # num_of_incorrect_ans => $rh->{problem_state}->{num_of_incorrect_ans}
267 # } );
268 ################################################################################
269 # grade the problem (and update the problem state again.)
270 ################################################################################
271
272 # Define an entry order -- the default is the order they are received from the browser.
273 # (Which as I understand it is NOT guaranteed to be the Left->Right Up-> Down order we're
274 # used to in the West.
275
276 my %PG_FLAGS = $pt->h_flags;
277 my $ra_answer_entry_order = ( defined($PG_FLAGS{ANSWER_ENTRY_ORDER}) ) ?
278 $PG_FLAGS{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
279 # Decide whether any answers were submitted.
280 my $answers_submitted = 0;
281 $answers_submitted = 1 if defined( $rh->{answer_form_submitted} ) and 1 == $rh->{answer_form_submitted};
282 # If there are answers, grade them
283 my ($rh_problem_result,$rh_problem_state) = $pt->grade_problem( answers_submitted => $answers_submitted,
284 ANSWER_ENTRY_ORDER => $ra_answer_entry_order
285 ); # grades the problem.
286
287 # Output format expected by Webwork.pm (and I believe processProblem8, but check.)
288 my $out = {
289 text => ${$pt ->r_text()}, # encode_base64( ${$pt ->r_text()} ),
290 header_text => $pt->r_header, # encode_base64( ${ $pt->r_header } ),
291 answers => $pt->rh_evaluated_answers,
292 errors => $pt-> errors(),
293 WARNINGS => $WARNINGS, #encode_base64($WARNINGS ),
294 problem_result => $rh_problem_result,
295 problem_state => $rh_problem_state,
296 PG_flag => \%PG_flag
297 };
298 ##########################################################################################
299 # Debugging printout of environment tables
300 ##########################################################################################
23 301
24 print "<P>Request item<P>\n\n"; 302 print "<P>Request item<P>\n\n";
25 print "<TABLE border=\"3\">"; 303 print "<TABLE border=\"3\">";
26 print $self->print_form_data('<tr><td>','</td><td>','</td></tr>'); 304 print $self->print_form_data('<tr><td>','</td><td>','</td></tr>');
27 print "</table>\n"; 305 print "</table>\n";
306 print "path info <br>\n";
307 print $r->path_info();
28 print "<P>\n\ncourseEnvironment<P>\n\n"; 308 print "<P>\n\ncourseEnvironment<P>\n\n";
29 print pretty_print_rh($courseEnvironment); 309 print pretty_print_rh($courseEnvironment);
30
31 ###########################################################################
32 # The pg problem class should have a method for installing it's problemEnvironment
33 ###########################################################################
34
35 $problemEnvir_rh = defineProblemEnvir($self);
36
37 print "<P>\n\nproblemEnvironment<P>\n\n"; 310 print "<P>\n\nproblemEnvironment<P>\n\n";
38 print pretty_print_rh($problemEnvir_rh); 311 print pretty_print_rh($problemEnvir_rh);
39# my $sig = do "pgGenerator.pl" ; 312
40# print "File not found $1" unless defined(sig); 313 ##########################################################################################
41# print "Errors $@"; 314 # End
42# print pgHTML(); 315 ##########################################################################################
43
44 ""; 316 "";
45} 317}
318# End the"body" routine for the Problem object.
319
320
321
322
46 323
47 324
48######################################################################################## 325########################################################################################
49# This is the structure that needs to be filled out in order to call PGtranslator; 326# This is the problemEnvironment structure that needs to be filled out in order to provide
327# information to PGtranslator which in turn supports the problem environment
50######################################################################################## 328########################################################################################
51 329
52sub defineProblemEnvir { 330sub defineProblemEnvir {
53 my $self = shift; 331 my $self = shift;
54 my $r = $self->{r}; 332 my $r = $self->{r};
106# defining directorys and URLs 384# defining directorys and URLs
107 $envir{'templateDirectory'} = $courseEnvironment ->{courseDirs}->{templates}; 385 $envir{'templateDirectory'} = $courseEnvironment ->{courseDirs}->{templates};
108############ $envir{'classDirectory'} = $Global::classDirectory; 386############ $envir{'classDirectory'} = $Global::classDirectory;
109# $envir{'cgiDirectory'} = $Global::cgiDirectory; 387# $envir{'cgiDirectory'} = $Global::cgiDirectory;
110# $envir{'cgiURL'} = getWebworkCgiURL(); 388# $envir{'cgiURL'} = getWebworkCgiURL();
111# $envir{'macroDirectory'} = getCourseMacroDirectory(); 389
112# $envir{'courseScriptsDirectory'} = getCourseScriptsDirectory();
113 $envir{'htmlDirectory'} = $courseEnvironment ->{courseDirectory}->{html};
114# $envir{'htmlURL'} = getCourseHtmlURL();
115# $envir{'tempDirectory'} = getCourseTempDirectory();
116# $envir{'tempURL'} = getCourseTempURL();
117# $envir{'scriptDirectory'} = $Global::scriptDirectory;##omit 390# $envir{'scriptDirectory'} = $Global::scriptDirectory;##omit
118 $envir{'webworkDocsURL'} = 'http://webwork.math.rochester.edu'; 391 $envir{'webworkDocsURL'} = 'http://webwork.math.rochester.edu';
119 $envir{'externalTTHPath'} = '/usr/local/bin/tth'; 392 $envir{'externalTTHPath'} = '/usr/local/bin/tth';
120 393
121 394
123 $envir{'inputs_ref'} = $r->param; 396 $envir{'inputs_ref'} = $r->param;
124 $envir{'problemSeed'} = 3245; 397 $envir{'problemSeed'} = 3245;
125 $envir{'displaySolutionsQ'} = 1; 398 $envir{'displaySolutionsQ'} = 1;
126 $envir{'displayHintsQ'} = 1; 399 $envir{'displayHintsQ'} = 1;
127 400
401# Directory values -- do we really need them here?
402 $envir{courseScriptsDirectory} = $COURSE_SCRIPTS_DIRECTORY;
403 $envir{macroDirectory} = $MACRO_DIRECTORY;
404 $envir{templateDirectory} = $TEMPLATE_DIRECTORY;
405 $envir{tempDirectory} = $TEMP_DIRECTORY;
406 $envir{tempURL} = $TEMP_URL;
407 $envir{htmlURL} = $HTML_URL;
408 $envir{'htmlDirectory'} = $courseEnvironment ->{courseDirectory}->{html};
128 # here is a way to pass environment variables defined in webworkCourse.ph 409 # here is a way to pass environment variables defined in webworkCourse.ph
129# my $k; 410# my $k;
130# foreach $k (keys %Global::PG_environment ) { 411# foreach $k (keys %Global::PG_environment ) {
131# $envir{$k} = $Global::PG_environment{$k}; 412# $envir{$k} = $Global::PG_environment{$k};
132# } 413# }
181 $out = ($@ eq '') ? 1 : 0; 462 $out = ($@ eq '') ? 1 : 0;
182 $@=''; 463 $@='';
183 $SIG{__DIE__} = $save_SIG_die_trap; 464 $SIG{__DIE__} = $save_SIG_die_trap;
184 $out; 465 $out;
185} 466}
467
468######
469# Utility for slurping souce files
470#######
471
472sub readFile {
473 my $input = shift; # The set and problem: 'set0/prob1.pg'
474 my $filePath =$TEMPLATE_DIRECTORY .$input;
475 print STDERR "Reading problem from file $filePath \n";
476 print STDERR "<br>Reading problem from file $filePath <br>\n";
477 my $out;
478 print "The file is readable = ", -r $filePath, "\n";
479 if (-r $filePath) {
480 open IN, "<$filePath" or print STDERR "Hey, this file was supposed to be readable\n";
481 local($/)=undef;
482 $out = <IN>;
483 close(IN);
484 } else {
485 print "Could not read file at |$filePath|";
486 print STDERR "Could not read file at |$filePath|";
487 }
488 return($out);
489}
490
491my $foo =0;
492
493# The warning mechanism. This needs to be turned into an object of its own
494###############
495## Error message routines cribbed from CGI
496###############
497
498BEGIN { #error message routines cribbed from CGI
499
500 my $CarpLevel = 0; # How many extra package levels to skip on carp.
501 my $MaxEvalLen = 0; # How much eval '...text...' to show. 0 = all.
502
503 sub longmess {
504 my $error = shift;
505 my $mess = "";
506 my $i = 1 + $CarpLevel;
507 my ($pack,$file,$line,$sub,$eval,$require);
508
509 while (($pack,$file,$line,$sub,undef,undef,$eval,$require) = caller($i++)) {
510 if ($error =~ m/\n$/) {
511 $mess .= $error;
512 }
513 else {
514 if (defined $eval) {
515 if ($require) {
516 $sub = "require $eval";
517 }
518 else {
519 $eval =~ s/[\\\']/\\$&/g;
520 if ($MaxEvalLen && length($eval) > $MaxEvalLen) {
521 substr($eval,$MaxEvalLen) = '...';
522 }
523 $sub = "eval '$eval'";
524 }
525 }
526 elsif ($sub eq '(eval)') {
527 $sub = 'eval {...}';
528 }
529
530 $mess .= "\t$sub " if $error eq "called";
531 $mess .= "$error at $file line $line\n";
532 }
533
534 $error = "called";
535 }
536
537 $mess || $error;
538 }
539}
540###############
541### Our error messages for giving maximum feedback to the user for errors within problems.
542###############
543BEGIN {
544 sub PG_floating_point_exception_handler { # 1st argument is signal name
545 my($sig) = @_;
546 print "Content-type: text/html\n\n<H4>There was a floating point arithmetic error (exception SIG$sig )</H4>--perhaps
547 you divided by zero or took the square root of a negative number?
548 <BR>\n Use the back button to return to the previous page and recheck your entries.<BR>\n";
549 exit(0);
550 }
551
552 $SIG{'FPE'} = \&PG_floating_point_exception_handler;
553
554 sub PG_warnings_handler {
555 my @input = @_;
556 my $msg_string = longmess(@_);
557 my @msg_array = split("\n",$msg_string);
558 my $out_string = '';
559
560 # Extra stack information is provided in this next block
561 # If the warning message does NOT end in \n then a line
562 # number is appended (see Perl manual about warn function)
563 # The presence of the line number is detected below and extra
564 # stack information is added.
565 # To suppress the line number and the extra stack information
566 # add \n to the end of a warn message (in .pl files. In .pg
567 # files add ~~n instead
568
569 if ($input[$#input]=~/line \d*\.\s*$/) {
570 $out_string .= "##More details: <BR>\n----";
571 foreach my $line (@msg_array) {
572 chomp($line);
573 next unless $line =~/\w+\:\:/;
574 $out_string .= "----" .$line . "<BR>\n";
575 }
576 }
577
578 $Global::WARNINGS .="* " . join("<BR>",@input) . "<BR>\n" . $out_string .
579 "<BR>\n--------------------------------------<BR>\n<BR>\n";
580 $Global::background_plain_url = $Global::background_warn_url;
581 $Global::bg_color = '#FF99CC'; #for warnings -- this change may come too late
582 }
583
584 $SIG{__WARN__}=\&PG_warnings_handler;
585
586 $SIG{__DIE__} = sub {
587 my $message = longmess(@_);
588 $message =~ s/\n/<BR>\n/;
589 my ($package, $filename, $line) = caller();
590 # use standard die for errors eminating from XML::Parser::Expat
591 # it uses a trapped eval which sometimes fails -- apparently on purpose
592 # and the error is handled by Expat itself. We don't want
593 # to interfer with that.
594
595 if ($package eq 'XML::Parser::Expat') {
596 die @_;
597 }
598 #print "$package $filename $line \n";
599 print
600 "Content-type: text/html\r\n\r\n <h4>Software error</h4> <p>\n\n$message\n<p>\n
601 Please inform the webwork meister.<p>\n
602 In addition to the error message above the following warnings were detected:
603 <HR>
604 $Global::WARNINGS;
605 <HR>
606 It's sometimes hard to tell exactly what has gone wrong since the
607 full error message may have been sent to
608 standard error instead of to standard out.
609 <p> To debug you can
610 <ul>
611 <li> guess what went wrong and try to fix it.
612 <li> call the offending script directly from the command line
613 of unix
614 <li> enable the debugging features by redefining
615 \$cgiURL in Global.pm and checking the redirection scripts in
616 system/cgi. This will force the standard error to be placed
617 in the standard out pipe as well.
618 <li> Run tail -f error_log <br>
619 from the unix command line to see error messages from the webserver.
620 The standard error output is being placed in the error_log file for the apache
621 web server. To run this command you have to be in the directory containing the
622 error_log or enter the full path name of the error_log. <p>
623 In a standard apache installation, this file is at /usr/local/apache/logs/error_log<p>
624 In a RedHat Linux installation, this file is at /var/log/httpd/error_log<p>
625 At Rochester this file is at /ww/logs/error_log.
626 </ul>
627 Good luck.<p>\n" ;
628 };
629
630
631
632}
633
1861; 6341;

Legend:
Removed from v.391  
changed lines
  Added in v.392

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9