| 1 | package WeBWorK::ContentGenerator::Problem; |
1 | package WeBWorK::ContentGenerator::Problem; |
| 2 | our @ISA = qw(WeBWorK::ContentGenerator); |
2 | use base qw(WeBWorK::ContentGenerator); |
| 3 | |
3 | |
| 4 | use strict; |
4 | use strict; |
| 5 | use warnings; |
5 | use warnings; |
| 6 | use lib '/home/malsyned/xmlrpc/daemon'; |
6 | use Apache::Constants qw(:common); |
| 7 | use lib '/Users/gage/webwork-modperl/lib'; |
|
|
| 8 | use PGtranslator5; |
|
|
| 9 | use WeBWorK::ContentGenerator; |
7 | use WeBWorK::ContentGenerator; |
| 10 | use Apache::Constants qw(:common); |
8 | use WeBWorK::PG; |
| 11 | |
9 | |
| 12 | ############################################################################### |
10 | # "Classic" form fields from processProblem8.pl |
| 13 | # Configuration |
11 | # |
| 14 | ############################################################################### |
12 | # user - user ID |
| 15 | my $USER_DIRECTORY = '/Users/gage'; |
13 | # key - session key |
| 16 | my $COURSE_SCRIPTS_DIRECTORY = "$USER_DIRECTORY/webwork/system/courseScripts/"; |
14 | # course - course name |
| 17 | my $MACRO_DIRECTORY = "$USER_DIRECTORY/webwork-modperl/courses/demoCourse/templates/macros/"; |
15 | # probSetKey - USUALLY known as the PSVN |
| 18 | my $TEMPLATE_DIRECTORY = "$USER_DIRECTORY/rochester_problib/"; |
16 | # probNum - problem number a.k.a. ID a.k.a. name |
| 19 | my $TEMP_URL = "http://127.0.0.1/~gage/rochester_problibtmp/"; |
17 | # |
| 20 | ##my $HTML_DIRECTORY = "/Users/gage/Sites/rochester_problib/" #already obtained from courseEnvironment |
18 | # Mode - display mode (HTML, HTML_tth, or typeset or whatever it's called) |
| 21 | my $HTML_URL = "http://127.0.0.1/~gage/rochester_problib/"; |
19 | # show_old_answers - whether or not student's old answers should be filled in |
| 22 | my $TEMP_DIRECTORY = ""; # has to be here... for now |
20 | # ShowAns - asks for correct answer to be shown -- only available for instructors |
| 23 | |
21 | # answer$i - student answers |
| 24 | ############################################################################### |
22 | # showEdit - checks if the ShowEditor button should be shown and clicked |
| 25 | # End configuration |
23 | # showSol - checks if the solution button ishould be shown and clicked |
| 26 | ############################################################################### |
24 | # |
|
|
25 | # source - contains modified problem source when called from the web-based problem editor |
|
|
26 | # seed - contains problem seed when called from the web-based problem editor |
|
|
27 | # readSourceFromHTMLQ - if true, problem is read from 'source' instead of file |
|
|
28 | # action - submit button clicked to invoke script (alledgedly) |
|
|
29 | # 'Save updated version' |
|
|
30 | # 'Read problem from disk' |
|
|
31 | # 'Submit Answers' |
|
|
32 | # 'Preview Answers' |
|
|
33 | # 'Preview Again' |
|
|
34 | # probFileName - name of the PG file being edited |
|
|
35 | # languageType - afaik, always set to 'pg' |
| 27 | |
36 | |
| 28 | sub title { |
37 | sub title { |
| 29 | my ($self, $problem_set, $problem) = @_; |
38 | my ($self, $problem_set, $problem) = @_; |
| 30 | my $r = $self->{r}; |
39 | my $r = $self->{r}; |
| 31 | my $user = $r->param('user'); |
40 | my $user = $r->param('user'); |
| 32 | return "Problem $problem of problem set $problem_set for $user"; |
41 | return "Problem $problem of problem set $problem_set for $user"; |
| 33 | } |
42 | } |
| 34 | |
43 | |
| 35 | ############################################################################### |
|
|
| 36 | # |
|
|
| 37 | # INITIALIZATION |
|
|
| 38 | # |
|
|
| 39 | # The following code initializes an instantiation of PGtranslator5 in the |
|
|
| 40 | # parent process. This initialized object is then share with each of the |
|
|
| 41 | # children forked from this parent process by the daemon. |
|
|
| 42 | # |
|
|
| 43 | # As far as I can tell, the child processes don't share any variable values even |
|
|
| 44 | # though their namespaces are the same. |
|
|
| 45 | ############################################################################### |
|
|
| 46 | # First some dummy values to use for testing. |
|
|
| 47 | # These should be available from the problemEnvironment(it might be ok to assume that PG and dangerousMacros |
|
|
| 48 | # live in the courseScripts (system level macros) directory. |
|
|
| 49 | |
|
|
| 50 | #print STDERR "Begin intitalization\n"; |
|
|
| 51 | my $dummy_envir = { courseScriptsDirectory => $COURSE_SCRIPTS_DIRECTORY, |
|
|
| 52 | displayMode => 'HTML_tth', |
|
|
| 53 | macroDirectory => $MACRO_DIRECTORY, |
|
|
| 54 | cgiURL => 'foo_cgiURL'}; |
|
|
| 55 | |
|
|
| 56 | |
|
|
| 57 | my $PG_PL = "${COURSE_SCRIPTS_DIRECTORY}PG.pl"; |
|
|
| 58 | my $DANGEROUS_MACROS_PL = "${COURSE_SCRIPTS_DIRECTORY}dangerousMacros.pl"; |
|
|
| 59 | my @MODULE_LIST = ( "Exporter", "DynaLoader", "GD", "WWPlot", "Fun", |
|
|
| 60 | "Circle", "Label", "PGrandom", "Units", "Hermite", |
|
|
| 61 | "List", "Match","Multiple", "Select", "AlgParser", |
|
|
| 62 | "AnswerHash", "Fraction", "VectorField", "Complex1", |
|
|
| 63 | "Complex", "MatrixReal1", "Matrix","Distributions", |
|
|
| 64 | "Regression" |
|
|
| 65 | ); |
|
|
| 66 | my @EXTRA_PACKAGES = ( "AlgParserWithImplicitExpand", "Expr", |
|
|
| 67 | "ExprWithImplicitExpand", "AnswerEvaluator", |
|
|
| 68 | |
|
|
| 69 | ); |
|
|
| 70 | my $INITIAL_MACRO_PACKAGES = <<END_OF_TEXT; |
|
|
| 71 | DOCUMENT(); |
|
|
| 72 | loadMacros( |
|
|
| 73 | "PGbasicmacros.pl", |
|
|
| 74 | "PGchoicemacros.pl", |
|
|
| 75 | "PGanswermacros.pl", |
|
|
| 76 | "PGnumericalmacros.pl", |
|
|
| 77 | "PGgraphmacros.pl", |
|
|
| 78 | "PGauxiliaryFunctions.pl", |
|
|
| 79 | "PGmatrixmacros.pl", |
|
|
| 80 | "PGcomplexmacros.pl", |
|
|
| 81 | "PGstatisticsmacros.pl" |
|
|
| 82 | |
|
|
| 83 | ); |
|
|
| 84 | |
|
|
| 85 | TEXT("Hello world"); |
|
|
| 86 | |
|
|
| 87 | ENDDOCUMENT(); |
|
|
| 88 | |
|
|
| 89 | END_OF_TEXT |
|
|
| 90 | |
|
|
| 91 | #These here documents have their drawbacks. KEEP END_OF_TEXT left justified!!!!!! |
|
|
| 92 | |
|
|
| 93 | ############################################################################### |
|
|
| 94 | # Now to define the body subroutine which does the hard work. |
|
|
| 95 | ############################################################################### |
|
|
| 96 | |
|
|
| 97 | |
|
|
| 98 | #my $SOURCE1 = $INITIAL_MACRO_PACKAGES; |
|
|
| 99 | |
|
|
| 100 | sub body { |
44 | sub body { |
| 101 | my ($self, $problem_set, $problem) = @_; |
45 | my ($self, $problem_set, $problem) = @_; |
| 102 | my $r = $self->{r}; |
|
|
| 103 | my $courseEnvironment = $self->{courseEnvironment}; |
|
|
| 104 | my $user = $r->param('user'); |
|
|
| 105 | |
46 | |
| 106 | my $rh = {}; # this needs to be set to a hash containing CGI params |
47 | # we have to call init_translator like this: |
|
|
48 | my $pt = WeBWorK::PG->new($courseEnv, $userName, $setName, $problemNumber, $formData); |
| 107 | |
49 | |
| 108 | |
|
|
| 109 | my $SOURCE1 = readFile("$problem_set/$problem.pg"); |
|
|
| 110 | print STDERR "SOURCEFILE: \n$SOURCE1\n\n"; |
|
|
| 111 | |
|
|
| 112 | ########################################################################### |
|
|
| 113 | # The pg problem class should have a method for installing it's problemEnvironment |
|
|
| 114 | ########################################################################### |
|
|
| 115 | |
|
|
| 116 | my $problemEnvir_rh = defineProblemEnvir($self); |
|
|
| 117 | |
|
|
| 118 | |
|
|
| 119 | ################################################################################## |
|
|
| 120 | # Prime the PGtranslator object and set it loose |
|
|
| 121 | ################################################################################## |
|
|
| 122 | |
|
|
| 123 | |
|
|
| 124 | ############################################################################### |
|
|
| 125 | |
|
|
| 126 | ############################################################################### |
|
|
| 127 | #Create the PG translator. |
|
|
| 128 | ############################################################################### |
|
|
| 129 | |
|
|
| 130 | my $pt = new PGtranslator5; #pt stands for problem translator; |
|
|
| 131 | |
|
|
| 132 | |
|
|
| 133 | # All of these hard coded directories need to be drawn from courseEnvironment. |
|
|
| 134 | # In addition I don't think that PGtranslator uses this stack internally yet. |
|
|
| 135 | # Passing these directories through the problemEnvironment variable is what |
|
|
| 136 | # is currently being done, but I don't think it is quite right, at least for most |
|
|
| 137 | # of them. |
|
|
| 138 | |
|
|
| 139 | |
|
|
| 140 | $pt ->rh_directories( { courseScriptsDirectory => $COURSE_SCRIPTS_DIRECTORY, |
|
|
| 141 | macroDirectory => $MACRO_DIRECTORY, |
|
|
| 142 | , |
|
|
| 143 | templateDirectory => $TEMPLATE_DIRECTORY, |
|
|
| 144 | tempDirectory => $TEMP_DIRECTORY, |
|
|
| 145 | } |
|
|
| 146 | ); |
|
|
| 147 | |
|
|
| 148 | ############################################################################### |
|
|
| 149 | # First we load the modules from courseScripts directory. |
|
|
| 150 | # These do the "heavy lifting" in terms of formatting, creating graphs, and |
|
|
| 151 | # performing other heavy duty algorithms. |
|
|
| 152 | # |
50 | # |
| 153 | ############################################################################### |
|
|
| 154 | |
51 | |
| 155 | $pt -> evaluate_modules( @MODULE_LIST); |
52 | # ----- this is not a place of honor ----- |
| 156 | $pt -> load_extra_packages( @EXTRA_PACKAGES ); |
|
|
| 157 | |
53 | |
| 158 | ############################################################################### |
|
|
| 159 | # Load the environment constants. Some are used by the PGtranslator object but |
|
|
| 160 | # most of them are installed inside the Safe compartment where the problem |
|
|
| 161 | # runs. |
|
|
| 162 | ############################################################################### |
|
|
| 163 | #$pt -> environment($dummy_envir); |
|
|
| 164 | $pt -> environment($problemEnvir_rh); |
|
|
| 165 | |
|
|
| 166 | |
|
|
| 167 | # I've forgotten what this does exactly :-) |
|
|
| 168 | $pt->initialize(); |
|
|
| 169 | |
|
|
| 170 | ############################################################################### |
|
|
| 171 | # PG.pl contains the basic code which defines the problem interface, input and output. |
|
|
| 172 | # dangerousMacros.pl contains subroutines which have access to the hard drive and |
|
|
| 173 | # and the directory structure. All use of external resources by the problem is supposed |
|
|
| 174 | # to go through these subroutines. The idea is to put the potentially dangerous |
|
|
| 175 | # algorithms in on place so they can be watched closely. |
|
|
| 176 | # These two files are evaluated in the Safe compartment without any restrictions. |
|
|
| 177 | # They have full use of the perl commands. |
|
|
| 178 | ############################################################################### |
|
|
| 179 | my $loadErrors = $pt -> unrestricted_load($PG_PL ); |
|
|
| 180 | print STDERR "$loadErrors\n" if ($loadErrors); |
|
|
| 181 | $loadErrors = $pt -> unrestricted_load($DANGEROUS_MACROS_PL); |
|
|
| 182 | print STDERR "$loadErrors\n" if ($loadErrors); |
|
|
| 183 | |
|
|
| 184 | ############################################################################### |
|
|
| 185 | # Now set the mask to restrict the operations which can be performed within |
|
|
| 186 | # a problem or a macro file. |
|
|
| 187 | ############################################################################### |
|
|
| 188 | $pt-> set_mask(); |
|
|
| 189 | |
|
|
| 190 | # print "\nPG.pl: $PG_PL<br>\n"; |
|
|
| 191 | # print "DANGEROUS_MACROS_PL: $DANGEROUS_MACROS_PL<br>\n"; |
|
|
| 192 | # print "Print dummy environment<br>\n"; |
|
|
| 193 | # print pretty_print_rh($dummy_envir), "<p>\n\n"; |
|
|
| 194 | |
|
|
| 195 | # Read in the source code for the problem |
|
|
| 196 | |
|
|
| 197 | #$INITIAL_MACRO_PACKAGES =~ tr /\r/\n/; # change everything to unix line endings. |
|
|
| 198 | $SOURCE1 =~ tr /\r/\n/; |
|
|
| 199 | #print STDERR "Source again \n $SOURCE1"; |
|
|
| 200 | $pt->source_string( $SOURCE1 ); |
|
|
| 201 | |
|
|
| 202 | ############################################################################### |
|
|
| 203 | # Install a safety filter for screening student answers. The default is now the blank |
|
|
| 204 | # filter since the answer evaluators do a pretty good job of recompiling and screening |
|
|
| 205 | # student's answers. Still, you could prohibit back ticks, or something of the kind. |
|
|
| 206 | ############################################################################### |
|
|
| 207 | |
|
|
| 208 | $pt ->rf_safety_filter( \&safetyFilter); # install blank safety filter |
|
|
| 209 | |
|
|
| 210 | |
|
|
| 211 | print STDERR "New PGtranslator object inititialization completed.<br>\n"; |
|
|
| 212 | ################################################################################ |
|
|
| 213 | ## This ends the initialization of the PGtranslator object |
|
|
| 214 | ################################################################################ |
|
|
| 215 | |
|
|
| 216 | |
|
|
| 217 | ################################################################################ |
|
|
| 218 | # Run the problem (output the html text) but also store it within the object. |
54 | # Run the problem (output the html text) but also store it within the object. |
| 219 | # The correct answers are also calculated and stored within the object |
55 | # The correct answers are also calculated and stored within the object |
| 220 | ################################################################################ |
|
|
| 221 | $pt ->translate(); |
56 | $pt ->translate(); |
| 222 | |
57 | |
| 223 | #print problem output |
58 | # print problem output |
| 224 | print "Problem goes here<p>\n"; |
59 | print "Problem goes here<p>\n"; |
| 225 | print "Problem output <br>\n"; |
60 | print "Problem output <br>\n"; |
| 226 | print "################################################################################<br><br>"; |
61 | print "<HR>"; |
| 227 | print ${$pt->r_text()}; |
62 | print ${$pt->r_text()}; |
| 228 | print "<br><br>################################################################################<br>"; |
63 | print "<HR>"; |
| 229 | print "<p>End of problem output<br>"; |
64 | print "<p>End of problem output<br>"; |
| 230 | |
65 | |
| 231 | |
66 | |
| 232 | #print source code |
67 | # print source code |
| 233 | print "Source code<pre>\n"; |
68 | print "Source code<pre>\n"; |
| 234 | print $SOURCE1; |
69 | print $SOURCE1; |
| 235 | print "</pre>End source code<p>"; |
70 | print "</pre>End source code<p>"; |
| 236 | ################################################################################ |
71 | |
| 237 | # The format for the output is described here. We'll need a local variable |
72 | # The format for the output is described here. We'll need a local variable |
| 238 | # to handle the warnings. From within the problem the warning command |
73 | # to handle the warnings. From within the problem the warning command |
| 239 | # has been slaved to the __WARNINGS__ routine which is defined in Global. |
74 | # has been slaved to the __WARNINGS__ routine which is defined in Global. |
| 240 | # We'll need to provide an alternate mechanism. |
75 | # We'll need to provide an alternate mechanism. |
| 241 | # The base64 encoding is only needed for xml transmission. |
76 | # The base64 encoding is only needed for xml transmission. |
| 242 | ################################################################################ |
77 | print "<hr>"; |
| 243 | print "################################################################################<br>"; |
|
|
| 244 | print "Warnings output<br>"; |
78 | print "Warnings output<br>"; |
| 245 | my $WARNINGS = "Let this be a warning:"; |
79 | my $WARNINGS = "Let this be a warning:"; |
| 246 | |
80 | |
| 247 | print $WARNINGS; |
81 | print $WARNINGS; |
| 248 | |
82 | |
| 249 | ################################################################################ |
|
|
| 250 | # Install the standard problem grader. See gage/xmlrpc/daemon.pm or processProblem8 for detailed |
83 | # Install the standard problem grader. See gage/xmlrpc/daemon.pm or processProblem8 for detailed |
| 251 | # code on how to choose which problem grader to install, depending on courseEnvironment and problem data. |
84 | # code on how to choose which problem grader to install, depending on courseEnvironment and problem data. |
| 252 | # See also PG.pl which provides for problem by problem overrides. |
85 | # See also PG.pl which provides for problem by problem overrides. |
| 253 | ################################################################################ |
|
|
| 254 | |
|
|
| 255 | $pt->rf_problem_grader($pt->rf_std_problem_grader); |
86 | $pt->rf_problem_grader($pt->rf_std_problem_grader); |
| 256 | |
87 | |
| 257 | ################################################################################ |
|
|
| 258 | # creates and stores a hash of answer results inside the object: $rh_answer_results |
88 | # creates and stores a hash of answer results inside the object: $rh_answer_results |
| 259 | ################################################################################ |
|
|
| 260 | $pt -> process_answers($rh->{envir}->{inputs_ref}); |
89 | $pt -> process_answers($rh->{envir}->{inputs_ref}); |
| 261 | |
90 | |
| 262 | |
91 | |
| 263 | # THE UPDATE AND GRADING LOGIC COULD USE AN OVERHAUL. IT WAS SOMEWHAT CONSTRAINED |
92 | # THE UPDATE AND GRADING LOGIC COULD USE AN OVERHAUL. IT WAS SOMEWHAT CONSTRAINED |
| 264 | # BY LEGACY CONDITIONS IN THE ORIGINAL PROCESSPROBLEM8. IT'S NOT BAD |
93 | # BY LEGACY CONDITIONS IN THE ORIGINAL PROCESSPROBLEM8. IT'S NOT BAD |
| 265 | # BUT IT COULD PROBABLY BE MADE A LITTLE MORE STRAIGHT FORWARD. |
94 | # BUT IT COULD PROBABLY BE MADE A LITTLE MORE STRAIGHT FORWARD. |
| 266 | ################################################################################ |
95 | # |
| 267 | # updates the problem state stored by the translator object from the problemEnvironment data |
96 | # updates the problem state stored by the translator object from the problemEnvironment data |
| 268 | ################################################################################ |
|
|
| 269 | |
97 | |
| 270 | # $pt->rh_problem_state({ recorded_score => $rh->{problem_state}->{recorded_score}, |
98 | # $pt->rh_problem_state({ recorded_score => $rh->{problem_state}->{recorded_score}, |
| 271 | # num_of_correct_ans => $rh->{problem_state}->{num_of_correct_ans} , |
99 | # num_of_correct_ans => $rh->{problem_state}->{num_of_correct_ans} , |
| 272 | # num_of_incorrect_ans => $rh->{problem_state}->{num_of_incorrect_ans} |
100 | # num_of_incorrect_ans => $rh->{problem_state}->{num_of_incorrect_ans} |
| 273 | # } ); |
101 | # } ); |
| 274 | ################################################################################ |
102 | |
| 275 | # grade the problem (and update the problem state again.) |
103 | # grade the problem (and update the problem state again.) |
| 276 | ################################################################################ |
104 | # |
| 277 | |
|
|
| 278 | # Define an entry order -- the default is the order they are received from the browser. |
105 | # Define an entry order -- the default is the order they are received from the browser. |
| 279 | # (Which as I understand it is NOT guaranteed to be the Left->Right Up-> Down order we're |
106 | # (Which as I understand it is NOT guaranteed to be the Left->Right Up-> Down order we're |
| 280 | # used to in the West. |
107 | # used to in the West. |
| 281 | |
108 | |
| 282 | my %PG_FLAGS = $pt->h_flags; |
109 | my %PG_FLAGS = $pt->h_flags; |
| … | |
… | |
| 299 | WARNINGS => $WARNINGS, #encode_base64($WARNINGS ), |
126 | WARNINGS => $WARNINGS, #encode_base64($WARNINGS ), |
| 300 | problem_result => $rh_problem_result, |
127 | problem_result => $rh_problem_result, |
| 301 | problem_state => $rh_problem_state, |
128 | problem_state => $rh_problem_state, |
| 302 | PG_flag => \%PG_FLAGS |
129 | PG_flag => \%PG_FLAGS |
| 303 | }; |
130 | }; |
| 304 | ########################################################################################## |
131 | |
| 305 | # Debugging printout of environment tables |
132 | # Debugging printout of environment tables |
| 306 | ########################################################################################## |
|
|
| 307 | |
|
|
| 308 | print "<P>Request item<P>\n\n"; |
133 | print "<P>Request item<P>\n\n"; |
| 309 | print "<TABLE border=\"3\">"; |
134 | print "<TABLE border=\"3\">"; |
| 310 | print $self->print_form_data('<tr><td>','</td><td>','</td></tr>'); |
135 | print $self->print_form_data('<tr><td>','</td><td>','</td></tr>'); |
| 311 | print "</table>\n"; |
136 | print "</table>\n"; |
| 312 | print "path info <br>\n"; |
137 | print "path info <br>\n"; |
| … | |
… | |
| 314 | print "<P>\n\ncourseEnvironment<P>\n\n"; |
139 | print "<P>\n\ncourseEnvironment<P>\n\n"; |
| 315 | print pretty_print_rh($courseEnvironment); |
140 | print pretty_print_rh($courseEnvironment); |
| 316 | print "<P>\n\nproblemEnvironment<P>\n\n"; |
141 | print "<P>\n\nproblemEnvironment<P>\n\n"; |
| 317 | print pretty_print_rh($problemEnvir_rh); |
142 | print pretty_print_rh($problemEnvir_rh); |
| 318 | |
143 | |
| 319 | ########################################################################################## |
|
|
| 320 | # End |
|
|
| 321 | ########################################################################################## |
|
|
| 322 | ""; |
144 | ""; |
| 323 | } |
145 | } |
| 324 | # End the"body" routine for the Problem object. |
|
|
| 325 | |
146 | |
| 326 | |
|
|
| 327 | sub safetyFilter { |
|
|
| 328 | my $answer = shift; # accepts one answer and checks it |
|
|
| 329 | my $submittedAnswer = $answer; |
|
|
| 330 | $answer = '' unless defined $answer; |
|
|
| 331 | my ($errorno); |
|
|
| 332 | $answer =~ tr/\000-\037/ /; |
|
|
| 333 | #### Return if answer field is empty ######## |
|
|
| 334 | unless ($answer =~ /\S/) { |
|
|
| 335 | # $errorno = "<BR>No answer was submitted."; |
|
|
| 336 | $errorno = 0; ## don't report blank answer as error |
|
|
| 337 | |
|
|
| 338 | return ($answer,$errorno); |
|
|
| 339 | } |
|
|
| 340 | ######### replace ^ with ** (for exponentiation) |
|
|
| 341 | # $answer =~ s/\^/**/g; |
|
|
| 342 | ######### Return if forbidden characters are found |
|
|
| 343 | unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)]+$/ ) { |
|
|
| 344 | $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)/#/c; |
|
|
| 345 | $errorno = "<BR>There are forbidden characters in your answer: $submittedAnswer<BR>"; |
|
|
| 346 | |
|
|
| 347 | return ($answer,$errorno); |
|
|
| 348 | } |
|
|
| 349 | |
|
|
| 350 | $errorno = 0; |
|
|
| 351 | return($answer, $errorno); |
|
|
| 352 | } |
|
|
| 353 | |
|
|
| 354 | |
|
|
| 355 | |
|
|
| 356 | |
|
|
| 357 | ######################################################################################## |
|
|
| 358 | # This is the problemEnvironment structure that needs to be filled out in order to provide |
|
|
| 359 | # information to PGtranslator which in turn supports the problem environment |
|
|
| 360 | ######################################################################################## |
|
|
| 361 | |
|
|
| 362 | sub defineProblemEnvir { |
|
|
| 363 | my $self = shift; |
|
|
| 364 | my $r = $self->{r}; |
|
|
| 365 | my $courseEnvironment = $self->{courseEnvironment}; |
|
|
| 366 | my %envir=(); |
|
|
| 367 | # $envir{'refSubmittedAnswers'} = $refSubmittedAnswers if defined($refSubmittedAnswers); |
|
|
| 368 | $envir{'psvnNumber'} = 123456789; |
|
|
| 369 | $envir{'psvn'} = 123456789; |
|
|
| 370 | $envir{'studentName'} = 'Jane Doe'; |
|
|
| 371 | $envir{'studentLogin'} = 'jd001m'; |
|
|
| 372 | $envir{'studentID'} = 'xxx-xx-4321'; |
|
|
| 373 | $envir{'sectionName'} = 'gage'; |
|
|
| 374 | $envir{'sectionNumber'} = '111foobar'; |
|
|
| 375 | $envir{'recitationName'} = 'gage_recitation'; |
|
|
| 376 | $envir{'recitationNumber'} = '11_foobar recitation'; |
|
|
| 377 | $envir{'setNumber'} = 'setAlgebraicGeometry'; |
|
|
| 378 | $envir{'questionNumber'} = 43; |
|
|
| 379 | $envir{'probNum'} = 43; |
|
|
| 380 | $envir{'openDate'} = 3014438528; |
|
|
| 381 | $envir{'formattedOpenDate'} = '3/4/02'; |
|
|
| 382 | $envir{'dueDate'} = 4014438528; |
|
|
| 383 | $envir{'formattedDueDate'} = '10/4/04'; |
|
|
| 384 | $envir{'answerDate'} = 4014438528; |
|
|
| 385 | $envir{'formattedAnswerDate'} = '10/4/04'; |
|
|
| 386 | $envir{'problemValue'} = 1; |
|
|
| 387 | $envir{'fileName'} = 'problem1'; |
|
|
| 388 | $envir{'probFileName'} = 'problem1'; |
|
|
| 389 | $envir{'languageMode'} = 'HTML_tth'; |
|
|
| 390 | $envir{'displayMode'} = 'HTML_tth'; |
|
|
| 391 | $envir{'outputMode'} = 'HTML_tth'; |
|
|
| 392 | $envir{'courseName'} = $courseEnvironment ->{courseName}; |
|
|
| 393 | $envir{'sessionKey'} = 'asdf'; |
|
|
| 394 | |
|
|
| 395 | # initialize constants for PGanswermacros.pl |
|
|
| 396 | $envir{'numRelPercentTolDefault'} = .1; |
|
|
| 397 | $envir{'numZeroLevelDefault'} = 1E-14; |
|
|
| 398 | $envir{'numZeroLevelTolDefault'} = 1E-12; |
|
|
| 399 | $envir{'numAbsTolDefault'} = .001; |
|
|
| 400 | $envir{'numFormatDefault'} = ''; |
|
|
| 401 | $envir{'functRelPercentTolDefault'} = .1; |
|
|
| 402 | $envir{'functZeroLevelDefault'} = 1E-14; |
|
|
| 403 | $envir{'functZeroLevelTolDefault'} = 1E-12; |
|
|
| 404 | $envir{'functAbsTolDefault'} = .001; |
|
|
| 405 | $envir{'functNumOfPoints'} = 3; |
|
|
| 406 | $envir{'functVarDefault'} = 'x'; |
|
|
| 407 | $envir{'functLLimitDefault'} = .0000001; |
|
|
| 408 | $envir{'functULimitDefault'} = .9999999; |
|
|
| 409 | $envir{'functMaxConstantOfIntegration'} = 1E8; |
|
|
| 410 | # kludge check definition of number of attempts again. The +1 is because this is used before the current answer is evaluated. |
|
|
| 411 | $envir{'numOfAttempts'} = 2; #&getProblemNumOfCorrectAns($probNum,$psvn) |
|
|
| 412 | # &getProblemNumOfIncorrectAns($probNum,$psvn)+1; |
|
|
| 413 | |
|
|
| 414 | # |
|
|
| 415 | # |
|
|
| 416 | # defining directorys and URLs |
|
|
| 417 | $envir{'templateDirectory'} = $courseEnvironment ->{courseDirs}->{templates}; |
|
|
| 418 | ############ $envir{'classDirectory'} = $Global::classDirectory; |
|
|
| 419 | # $envir{'cgiDirectory'} = $Global::cgiDirectory; |
|
|
| 420 | # $envir{'cgiURL'} = getWebworkCgiURL(); |
|
|
| 421 | |
|
|
| 422 | # $envir{'scriptDirectory'} = $Global::scriptDirectory;##omit |
|
|
| 423 | $envir{'webworkDocsURL'} = 'http://webwork.math.rochester.edu'; |
|
|
| 424 | $envir{'externalTTHPath'} = '/usr/local/bin/tth'; |
|
|
| 425 | |
|
|
| 426 | |
|
|
| 427 | # |
|
|
| 428 | $envir{'inputs_ref'} = $r->param; |
|
|
| 429 | $envir{'problemSeed'} = 3245; |
|
|
| 430 | $envir{'displaySolutionsQ'} = 1; |
|
|
| 431 | $envir{'displayHintsQ'} = 1; |
|
|
| 432 | |
|
|
| 433 | # Directory values -- do we really need them here? |
|
|
| 434 | $envir{courseScriptsDirectory} = $COURSE_SCRIPTS_DIRECTORY; |
|
|
| 435 | $envir{macroDirectory} = $MACRO_DIRECTORY; |
|
|
| 436 | $envir{templateDirectory} = $TEMPLATE_DIRECTORY; |
|
|
| 437 | $envir{tempDirectory} = $TEMP_DIRECTORY; |
|
|
| 438 | $envir{tempURL} = $TEMP_URL; |
|
|
| 439 | $envir{htmlURL} = $HTML_URL; |
|
|
| 440 | $envir{'htmlDirectory'} = $courseEnvironment ->{courseDirectory}->{html}; |
|
|
| 441 | # here is a way to pass environment variables defined in webworkCourse.ph |
|
|
| 442 | # my $k; |
|
|
| 443 | # foreach $k (keys %Global::PG_environment ) { |
|
|
| 444 | # $envir{$k} = $Global::PG_environment{$k}; |
|
|
| 445 | # } |
|
|
| 446 | \%envir; |
|
|
| 447 | } |
|
|
| 448 | |
|
|
| 449 | ######################################################################################## |
|
|
| 450 | # This recursive pretty_print function will print a hash and its sub hashes. |
|
|
| 451 | ######################################################################################## |
|
|
| 452 | sub pretty_print_rh { |
147 | sub pretty_print_rh { |
| 453 | my $r_input = shift; |
148 | my $r_input = shift; |
| 454 | my $out = ''; |
149 | my $out = ''; |
| 455 | if ( not ref($r_input) ) { |
150 | if ( not ref($r_input) ) { |
| 456 | $out = $r_input; # not a reference |
151 | $out = $r_input; # not a reference |
| … | |
… | |
| 495 | $@=''; |
190 | $@=''; |
| 496 | $SIG{__DIE__} = $save_SIG_die_trap; |
191 | $SIG{__DIE__} = $save_SIG_die_trap; |
| 497 | $out; |
192 | $out; |
| 498 | } |
193 | } |
| 499 | |
194 | |
| 500 | ###### |
195 | 1; |
| 501 | # Utility for slurping souce files |
|
|
| 502 | ####### |
|
|
| 503 | |
196 | |
| 504 | sub readFile { |
197 | __END__ |
| 505 | my $input = shift; # The set and problem: 'set0/prob1.pg' |
|
|
| 506 | my $filePath =$TEMPLATE_DIRECTORY .$input; |
|
|
| 507 | print STDERR "Reading problem from file $filePath \n"; |
|
|
| 508 | print STDERR "<br>Reading problem from file $filePath <br>\n"; |
|
|
| 509 | my $out; |
|
|
| 510 | print "The file is readable = ", -r $filePath, "\n"; |
|
|
| 511 | if (-r $filePath) { |
|
|
| 512 | open IN, "<$filePath" or print STDERR "Hey, this file was supposed to be readable\n"; |
|
|
| 513 | local($/)=undef; |
|
|
| 514 | $out = <IN>; |
|
|
| 515 | close(IN); |
|
|
| 516 | } else { |
|
|
| 517 | print "Could not read file at |$filePath|"; |
|
|
| 518 | print STDERR "Could not read file at |$filePath|"; |
|
|
| 519 | } |
|
|
| 520 | return($out); |
|
|
| 521 | } |
|
|
| 522 | |
198 | |
| 523 | my $foo =0; |
199 | my $foo =0; |
| 524 | |
200 | |
| 525 | # The warning mechanism. This needs to be turned into an object of its own |
201 | # The warning mechanism. This needs to be turned into an object of its own |
| 526 | ############### |
202 | ############### |
| … | |
… | |
| 660 | }; |
336 | }; |
| 661 | |
337 | |
| 662 | |
338 | |
| 663 | |
339 | |
| 664 | } |
340 | } |
| 665 | |
|
|
| 666 | 1; |
|
|