| 1 | #!/usr/bin/perl -w |
1 | #!/usr/bin/perl -w |
| 2 | |
2 | |
| 3 | =pod |
3 | ################################################################################ |
|
|
4 | # WeBWorK Online Homework Delivery System |
|
|
5 | # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/ |
|
|
6 | # $CVSHeader: webwork2/lib/WeBWorK/ContentGenerator/ProblemRenderer.pm,v 1.1 2008/04/29 19:27:34 sh002i Exp $ |
|
|
7 | # |
|
|
8 | # This program is free software; you can redistribute it and/or modify it under |
|
|
9 | # the terms of either: (a) the GNU General Public License as published by the |
|
|
10 | # Free Software Foundation; either version 2, or (at your option) any later |
|
|
11 | # version, or (b) the "Artistic License" which comes with this package. |
|
|
12 | # |
|
|
13 | # This program is distributed in the hope that it will be useful, but WITHOUT |
|
|
14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
|
15 | # FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the |
|
|
16 | # Artistic License for more details. |
|
|
17 | ################################################################################ |
|
|
18 | |
|
|
19 | =head1 NAME |
|
|
20 | |
|
|
21 | webwork2/clients/renderProblem.pl |
| 4 | |
22 | |
| 5 | This script will take a file and send it to a WeBWorK daemon webservice |
23 | This script will take a file and send it to a WeBWorK daemon webservice |
| 6 | to have it rendered. The result is split into the basic HTML rendering |
24 | to have it rendered. The result is split into the basic HTML rendering |
| 7 | and evaluation of answers and then passed to Safari for printing. |
25 | and evaluation of answers and then passed to a browser for printing. |
| 8 | |
26 | |
| 9 | The formatting allows the Safari presentation to be interactive with the |
27 | The formatting allows the browser presentation to be interactive with the |
| 10 | daemon running on webhost.math.rochester.edu |
28 | daemon running the script webwork2/lib/renderViaXMLRPC.pm |
| 11 | |
29 | |
| 12 | |
30 | |
| 13 | |
31 | |
| 14 | =cut |
32 | =cut |
| 15 | |
33 | |
|
|
34 | use strict; |
|
|
35 | use warnings; |
|
|
36 | |
|
|
37 | package WeBWorK::ContentGenerator::renderViaXMLRPC_client; |
|
|
38 | use Crypt::SSLeay; # needed for https |
| 16 | use XMLRPC::Lite; |
39 | use XMLRPC::Lite; |
| 17 | use MIME::Base64 qw( encode_base64 decode_base64); |
40 | use MIME::Base64 qw( encode_base64 decode_base64); |
| 18 | #require "webwork_xmlrpc_inc.pl"; |
|
|
| 19 | |
41 | |
|
|
42 | ################################################## |
| 20 | # configuration section |
43 | # configuration section for client |
|
|
44 | ################################################## |
| 21 | use constant PROTOCOL => 'https'; # or 'http'; |
45 | # use constant PROTOCOL => 'http'; |
| 22 | use constant HOSTURL => 'webwork.rochester.edu'; |
46 | # use constant HOSTNAME => 'localhost'; |
| 23 | use constant HOSTPORT => 443; |
47 | # use constant HOSTPORT => 80; |
|
|
48 | # our $FORM_ACTION_URL ='http://localhost/webwork2/html2xml'; |
|
|
49 | |
|
|
50 | |
|
|
51 | use constant PROTOCOL => 'https'; # or 'http'; |
|
|
52 | use constant HOSTNAME => 'hosted2.webwork.rochester.edu'; # 'localhost'; |
|
|
53 | use constant HOSTPORT => 443; #( for secure https) # 80; |
|
|
54 | our $FULL_URL = PROTOCOL."://".HOSTNAME; # .":".HOSTPORT; |
|
|
55 | our $FORM_ACTION_URL = "$FULL_URL/webwork2/html2xml"; # server parameter |
|
|
56 | |
| 24 | use constant TRANSPORT_METHOD => 'XMLRPC::Lite'; |
57 | use constant TRANSPORT_METHOD => 'XMLRPC::Lite'; |
| 25 | use constant REQUEST_CLASS => 'WebworkXMLRPC'; # WebworkXMLRPC is used for soap also!! |
58 | use constant REQUEST_CLASS => 'WebworkXMLRPC'; # WebworkXMLRPC is used for soap also!! |
| 26 | use constant REQUEST_URI => 'mod_xmlrpc'; |
59 | use constant REQUEST_URI => 'mod_xmlrpc'; |
| 27 | use constant TEMPOUTPUTFILE => '/Users/gage/Desktop/renderProblemOutput.html'; |
60 | use constant TEMPOUTPUTFILE => '/Users/gage/Desktop/renderProblemOutput.html'; # client only |
| 28 | use constant DISPLAY_COMMAND => 'open -a safari '; |
61 | use constant DISPLAY_COMMAND => 'open -a firefox '; # client only |
|
|
62 | |
|
|
63 | use constant XML_PASSWORD => 'xmlwebwork'; |
| 29 | use constant COURSE => 'daemon2_course'; |
64 | use constant XML_COURSE => 'daemon_course'; |
| 30 | |
65 | |
| 31 | |
66 | |
| 32 | |
67 | |
| 33 | # $pg{displayModes} = [ |
68 | |
| 34 | # "plainText", # display raw TeX for math expressions |
|
|
| 35 | # "formattedText", # format math expressions using TtH |
|
|
| 36 | # "images", # display math expressions as images generated by dvipng |
|
|
| 37 | # "jsMath", # render TeX math expressions on the client side using jsMath |
|
|
| 38 | # "asciimath", # render TeX math expressions on the client side using ASCIIMathML |
|
|
| 39 | # ]; |
|
|
| 40 | use constant DISPLAYMODE => 'images'; # tex and jsMath are other possibilities. |
69 | use constant DISPLAYMODE => 'images'; # tex and jsMath are other possibilities. |
| 41 | |
70 | |
| 42 | |
71 | |
| 43 | my @COMMANDS = qw( listLibraries renderProblem ); #listLib readFile tex2pdf |
72 | our @COMMANDS = qw( listLibraries renderProblem ); #listLib readFile tex2pdf |
| 44 | |
73 | |
|
|
74 | |
|
|
75 | ################################################## |
| 45 | # end configuration section |
76 | # end configuration section |
|
|
77 | ################################################## |
| 46 | |
78 | |
|
|
79 | sub new { |
|
|
80 | my $self = { |
|
|
81 | output => '', |
|
|
82 | encodedSource => '', |
|
|
83 | self => '', |
|
|
84 | inputs_ref => { AnSwEr0001 => '', |
|
|
85 | AnSwEr0002 => '', |
|
|
86 | AnSwEr0003 => '', |
|
|
87 | },, |
|
|
88 | }; |
| 47 | |
89 | |
|
|
90 | bless $self; |
|
|
91 | } |
|
|
92 | our $xmlrpc_client = new WeBWorK::ContentGenerator::renderViaXMLRPC_client; |
| 48 | |
93 | |
| 49 | #print STDERR "inputs are ", join (" | ", @ARGV), "\n"; |
94 | ################################################## |
|
|
95 | # input/output section |
|
|
96 | ################################################## |
|
|
97 | |
|
|
98 | |
| 50 | our $source; |
99 | our $source; |
| 51 | our $encodedSource; |
|
|
| 52 | our $rh_result; |
100 | our $rh_result; |
| 53 | # filter mode main code |
101 | # filter mode main code |
| 54 | |
102 | |
| 55 | undef $/; |
103 | undef $/; |
| 56 | $source = <>; #slurp input |
104 | $source = <>; #slurp input |
| 57 | $encodedSource = encodeSource($source); |
105 | $xmlrpc_client->{encodedSource} = encodeSource($source); |
| 58 | $/ =1; |
106 | $/ =1; |
| 59 | xmlrpcCall('renderProblem'); |
107 | #xmlrpcCall('renderProblem'); |
|
|
108 | $xmlrpc_client->xmlrpcCall('renderProblem'); |
| 60 | |
109 | |
| 61 | # end filter main code |
110 | |
|
|
111 | local(*FH); |
|
|
112 | open(FH, '>'.TEMPOUTPUTFILE) or die "Can't open file ".TEMPOUTPUTFILE()." for writing"; |
|
|
113 | print FH $xmlrpc_client->{output} ; |
|
|
114 | close(FH); |
|
|
115 | |
|
|
116 | system(DISPLAY_COMMAND().TEMPOUTPUTFILE()); |
|
|
117 | |
|
|
118 | ################################################## |
|
|
119 | # end input/output section |
|
|
120 | ################################################## |
|
|
121 | |
|
|
122 | |
|
|
123 | our $result; |
|
|
124 | |
|
|
125 | ################################################## |
|
|
126 | # Utilities -- |
|
|
127 | # this code is identical between renderProblem.pl and renderViaXMLRPC.pm |
|
|
128 | ################################################## |
| 62 | |
129 | |
| 63 | sub xmlrpcCall { |
130 | sub xmlrpcCall { |
|
|
131 | my $self = shift; |
| 64 | my $command = shift; |
132 | my $command = shift; |
| 65 | $command = 'listLibraries' unless $command; |
133 | $command = 'listLibraries' unless $command; |
| 66 | |
134 | |
| 67 | my $requestResult = TRANSPORT_METHOD |
135 | my $requestResult = TRANSPORT_METHOD |
| 68 | #->uri('http://'.HOSTURL.':'.HOSTPORT.'/'.REQUEST_CLASS) |
136 | #->uri('http://'.HOSTNAME.':'.HOSTPORT.'/'.REQUEST_CLASS) |
| 69 | -> proxy(PROTOCOL.'://'.HOSTURL.':'.HOSTPORT.'/'.REQUEST_URI); |
137 | -> proxy($FULL_URL.'/'.REQUEST_URI); |
| 70 | |
138 | |
| 71 | my $test = [3,4,5,6]; |
|
|
| 72 | my $input = setInputTable(); |
139 | my $input = $self->setInputTable(); |
| 73 | #print "displayMode=",$input->{envir}->{displayMode},"\n"; |
|
|
| 74 | local( $result); |
140 | local( $result); |
| 75 | # use eval to catch errors |
141 | # use eval to catch errors |
| 76 | eval { $result = $requestResult->call(REQUEST_CLASS.'.'.$command,$input) }; |
142 | eval { $result = $requestResult->call(REQUEST_CLASS.'.'.$command,$input) }; |
| 77 | print STDERR "There were a lot of errors\n" if $@; |
143 | print STDERR "There were a lot of errors\n" if $@; |
| 78 | print "Errors: \n $@\n End Errors\n" if $@; |
144 | print STDERR "Errors: \n $@\n End Errors\n" if $@; |
| 79 | |
|
|
| 80 | #print "result is|", ref($result),"|"; |
|
|
| 81 | |
|
|
| 82 | unless (ref($result) and $result->fault) { |
|
|
| 83 | |
145 | |
| 84 | |
146 | |
|
|
147 | |
|
|
148 | |
|
|
149 | unless (ref($result) and $result->fault) { |
| 85 | $rh_result = $result->result(); |
150 | my $rh_result = $result->result(); |
| 86 | |
151 | #print STDERR pretty_print_rh($rh_result); |
| 87 | # look at output |
152 | $self->{output} = $self->formatRenderedProblem($rh_result); |
| 88 | |
153 | |
| 89 | local(*FH); |
|
|
| 90 | open(FH, '>'.TEMPOUTPUTFILE) or die "Can't open file ".TEMPOUTPUTFILE()." for writing"; |
|
|
| 91 | print FH formatRenderedProblem($rh_result); |
|
|
| 92 | close(FH); |
|
|
| 93 | |
|
|
| 94 | system(DISPLAY_COMMAND().TEMPOUTPUTFILE()); |
|
|
| 95 | #print pretty_print_rh($result->result()),"\n"; #$result->result() |
|
|
| 96 | } else { |
154 | } else { |
| 97 | print 'oops ', join ', ', |
155 | $self->{output} = 'Error from server: ', join( ",\n ", |
| 98 | $result->faultcode, |
156 | $result->faultcode, |
| 99 | $result->faultstring; |
157 | $result->faultstring); |
| 100 | } |
158 | } |
| 101 | } |
159 | } |
| 102 | |
160 | |
| 103 | sub encodeSource { |
161 | sub encodeSource { |
|
|
162 | my $source = shift; |
| 104 | encode_base64($source); |
163 | encode_base64($source); |
| 105 | } |
164 | } |
|
|
165 | |
|
|
166 | |
| 106 | sub pretty_print_rh { |
167 | sub pretty_print_rh { |
| 107 | shift if UNIVERSAL::isa($_[0] => __PACKAGE__); |
168 | shift if UNIVERSAL::isa($_[0] => __PACKAGE__); |
| 108 | my $rh = shift; |
169 | my $rh = shift; |
| 109 | my $indent = shift || 0; |
170 | my $indent = shift || 0; |
| 110 | my $out = ""; |
171 | my $out = ""; |
| … | |
… | |
| 143 | |
204 | |
| 144 | return $out." "; |
205 | return $out." "; |
| 145 | } |
206 | } |
| 146 | |
207 | |
| 147 | sub setInputTable_for_listLib { |
208 | sub setInputTable_for_listLib { |
|
|
209 | my $self = shift; |
| 148 | $out = { |
210 | my $out = { |
| 149 | #password => 'geometry', |
211 | pw => XML_PASSWORD(), |
| 150 | pw => 'geometry', |
|
|
| 151 | set => 'set0', |
212 | set => 'set0', |
| 152 | library_name => 'rochesterLibrary', |
213 | library_name => 'Library', |
| 153 | command => 'all', |
214 | command => 'all', |
| 154 | }; |
215 | }; |
| 155 | |
216 | |
| 156 | $out; |
217 | $out; |
| 157 | } |
218 | } |
| 158 | sub setInputTable { |
219 | sub setInputTable { |
|
|
220 | my $self = shift; |
| 159 | $out = { |
221 | my $out = { |
| 160 | #password => 'geometry', |
222 | pw => XML_PASSWORD(), |
| 161 | pw => 'geometry', |
|
|
| 162 | set => 'set0', |
|
|
| 163 | library_name => 'rochesterLibrary', |
223 | library_name => 'Library', |
| 164 | command => 'all', |
224 | command => 'renderProblem', |
| 165 | answer_form_submitted => 1, |
225 | answer_form_submitted => 1, |
| 166 | course => COURSE(), |
226 | course => XML_COURSE(), |
| 167 | extra_packages_to_load => [qw( AlgParserWithImplicitExpand Expr |
227 | extra_packages_to_load => [qw( AlgParserWithImplicitExpand Expr |
| 168 | ExprWithImplicitExpand AnswerEvaluator |
228 | ExprWithImplicitExpand AnswerEvaluator |
| 169 | AnswerEvaluatorMaker |
229 | AnswerEvaluatorMaker |
| 170 | )], |
230 | )], |
| 171 | mode => DISPLAMODE(), |
231 | mode => DISPLAYMODE(), |
| 172 | modules_to_evaluate => [ qw( |
232 | modules_to_evaluate => [ qw( |
| 173 | Exporter |
233 | Exporter |
| 174 | DynaLoader |
234 | DynaLoader |
| 175 | GD |
235 | GD |
| 176 | WWPlot |
236 | WWPlot |
| … | |
… | |
| 193 | MatrixReal1 Matrix |
253 | MatrixReal1 Matrix |
| 194 | Distributions |
254 | Distributions |
| 195 | Regression |
255 | Regression |
| 196 | |
256 | |
| 197 | )], |
257 | )], |
| 198 | envir => environment(), |
258 | envir => $self->environment(), |
| 199 | problem_state => { |
259 | problem_state => { |
| 200 | |
260 | |
| 201 | num_of_correct_ans => 2, |
261 | num_of_correct_ans => 2, |
| 202 | num_of_incorrect_ans => 4, |
262 | num_of_incorrect_ans => 4, |
| 203 | recorded_score => 1.0, |
263 | recorded_score => 1.0, |
| 204 | }, |
264 | }, |
| 205 | source => $encodedSource, #base64 encoded |
265 | source => $self->{encodedSource}, #base64 encoded |
| 206 | |
266 | |
| 207 | |
267 | |
| 208 | |
268 | |
| 209 | }; |
269 | }; |
| 210 | |
270 | |
| 211 | $out; |
271 | $out; |
| 212 | } |
272 | } |
| 213 | |
273 | |
| 214 | sub environment { |
274 | sub environment { |
|
|
275 | my $self = shift; |
| 215 | my $envir = { |
276 | my $envir = { |
| 216 | answerDate => '4014438528', |
277 | answerDate => '4014438528', |
| 217 | CAPA_Graphics_URL=>'http://webwork-db.math.rochester.edu/capa_graphics/', |
278 | CAPA_Graphics_URL=>"not defined", |
| 218 | CAPA_GraphicsDirectory =>'/ww/webwork/CAPA/CAPA_Graphics/', |
279 | CAPA_GraphicsDirectory =>"not defined", |
| 219 | CAPA_MCTools=>'/ww/webwork/CAPA/CAPA_MCTools/', |
280 | CAPA_MCTools=>"not defined", |
| 220 | CAPA_Tools=>'/ww/webwork/CAPA/CAPA_Tools/', |
281 | CAPA_Tools=>'not defined', |
| 221 | cgiDirectory=>'Not defined', |
282 | cgiDirectory=>'Not defined', |
| 222 | cgiURL => 'Not defined', |
283 | cgiURL => 'Not defined', |
| 223 | classDirectory=> 'Not defined', |
284 | classDirectory=> 'Not defined', |
| 224 | courseName=>'Not defined', |
285 | courseName=>'Not defined', |
| 225 | courseScriptsDirectory=>'/ww/webwork/system/courseScripts/', |
286 | courseScriptsDirectory=>'not defined', |
| 226 | displayMode=>DISPLAYMODE, |
287 | displayMode=>DISPLAYMODE, |
| 227 | dueDate=> '4014438528', |
288 | dueDate=> '4014438528', |
| 228 | externalGif2EpsPath=>'not defined', |
289 | externalGif2EpsPath=>'not defined', |
| 229 | externalPng2EpsPath=>'not defined', |
290 | externalPng2EpsPath=>'not defined', |
| 230 | externalTTHPath=>'/usr/local/bin/tth', |
291 | externalTTHPath=>'/usr/local/bin/tth', |
| … | |
… | |
| 239 | functRelPercentTolDefault=> 0.000001, |
300 | functRelPercentTolDefault=> 0.000001, |
| 240 | functULimitDefault=>1, |
301 | functULimitDefault=>1, |
| 241 | functVarDefault=> 'x', |
302 | functVarDefault=> 'x', |
| 242 | functZeroLevelDefault=> 0.000001, |
303 | functZeroLevelDefault=> 0.000001, |
| 243 | functZeroLevelTolDefault=>0.000001, |
304 | functZeroLevelTolDefault=>0.000001, |
| 244 | htmlDirectory =>'/ww/webwork/courses/gage_course/html/', |
305 | htmlDirectory =>'not defined', |
| 245 | htmlURL =>'http://webwork-db.math.rochester.edu/gage_course/', |
306 | htmlURL =>'not defined', |
| 246 | inputs_ref => { |
307 | inputs_ref => $self->{inputs_ref}, |
| 247 | AnSwEr1 => '', |
308 | macroDirectory=>'not defined', |
| 248 | AnSwEr2 => '', |
|
|
| 249 | AnSwEr3 => '', |
|
|
| 250 | }, |
|
|
| 251 | macroDirectory=>'/ww/webwork/courses/gage_course/templates/macros/', |
|
|
| 252 | numAbsTolDefault=>0.0000001, |
309 | numAbsTolDefault=>0.0000001, |
| 253 | numFormatDefault=>'%0.13g', |
310 | numFormatDefault=>'%0.13g', |
| 254 | numOfAttempts=> 0, |
311 | numOfAttempts=> 0, |
| 255 | numRelPercentTolDefault => 0.0001, |
312 | numRelPercentTolDefault => 0.0001, |
| 256 | numZeroLevelDefault =>0.000001, |
313 | numZeroLevelDefault =>0.000001, |
| … | |
… | |
| 266 | questionNumber => 1, |
323 | questionNumber => 1, |
| 267 | scriptDirectory => 'Not defined', |
324 | scriptDirectory => 'Not defined', |
| 268 | sectionName => 'Gage', |
325 | sectionName => 'Gage', |
| 269 | sectionNumber => 1, |
326 | sectionNumber => 1, |
| 270 | sessionKey=> 'Not defined', |
327 | sessionKey=> 'Not defined', |
| 271 | setNumber =>'MAAtutorial', |
328 | setNumber =>'not defined', |
| 272 | studentLogin =>'gage', |
329 | studentLogin =>'gage', |
| 273 | studentName => 'Mike Gage', |
330 | studentName => 'Mike Gage', |
| 274 | tempDirectory => '/ww/htdocs/tmp/gage_course/', |
331 | tempDirectory => 'not defined', |
| 275 | templateDirectory=>'/ww/webwork/courses/gage_course/templates/', |
332 | templateDirectory=>'not defined', |
| 276 | tempURL=>'http://webwork-db.math.rochester.edu/tmp/gage_course/', |
333 | tempURL=>'not defined', |
| 277 | webworkDocsURL => 'http://webwork.math.rochester.edu/webwork_gage_system_html', |
334 | webworkDocsURL => 'not defined', |
| 278 | }; |
335 | }; |
| 279 | $envir; |
336 | $envir; |
| 280 | }; |
337 | }; |
| 281 | |
338 | |
| 282 | sub formatAnswerRow { |
339 | sub formatAnswerRow { |
|
|
340 | my $self = shift; |
| 283 | my $rh_answer = shift; |
341 | my $rh_answer = shift; |
| 284 | my $problemNumber = shift; |
342 | my $problemNumber = shift; |
| 285 | my $answerString = $rh_answer->{original_student_ans}||' '; |
343 | my $answerString = $rh_answer->{original_student_ans}||' '; |
| 286 | my $correctAnswer = $rh_answer->{correct_ans}; |
344 | my $correctAnswer = $rh_answer->{correct_ans}||''; |
|
|
345 | my $ans_message = $rh_answer->{ans_message}; |
| 287 | my $score = ($rh_answer->{score}) ? 'Correct' : 'Incorrect'; |
346 | my $score = ($rh_answer->{score}) ? 'Correct' : 'Incorrect'; |
| 288 | my $row = qq{ |
347 | my $row = qq{ |
| 289 | <tr> |
348 | <tr> |
| 290 | <td> |
349 | <td> |
| 291 | $problemNumber |
350 | Prob: $problemNumber |
| 292 | </td> |
351 | </td> |
| 293 | <td> |
352 | <td> |
| 294 | $answerString |
353 | $answerString |
| 295 | </td> |
354 | </td> |
| 296 | <td> |
355 | <td> |
| … | |
… | |
| 298 | </td> |
357 | </td> |
| 299 | <td> |
358 | <td> |
| 300 | Correct answer is $correctAnswer |
359 | Correct answer is $correctAnswer |
| 301 | </td> |
360 | </td> |
| 302 | <td> |
361 | <td> |
| 303 | <i></i> |
362 | <i>$ans_message</i> |
| 304 | </td> |
363 | </td> |
| 305 | </tr>\n |
364 | </tr>\n |
| 306 | }; |
365 | }; |
| 307 | $row; |
366 | $row; |
| 308 | } |
367 | } |
| 309 | |
368 | |
| 310 | sub formatRenderedProblem { |
369 | sub formatRenderedProblem { |
|
|
370 | my $self = shift; |
| 311 | my $rh_result = shift; # wrap problem in formats |
371 | my $rh_result = shift; # wrap problem in formats |
| 312 | my $problemText = decode_base64($rh_result->{text}); |
372 | my $problemText = decode_base64($rh_result->{text}); |
| 313 | my $rh_answers = $rh_result->{answers}; |
373 | my $rh_answers = $rh_result->{answers}; |
| 314 | |
374 | my $encodedSource = $self->{encodedSource}||'foobar'; |
| 315 | my $warnings = ''; |
375 | my $warnings = ''; |
| 316 | if ( defined ($rh_result->{WARNINGS}) and $rh_result->{WARNINGS} ){ |
376 | if ( defined ($rh_result->{WARNINGS}) and $rh_result->{WARNINGS} ){ |
| 317 | $warnings = "<div style=\"background-color:pink\"> |
377 | $warnings = "<div style=\"background-color:pink\"> |
| 318 | <p >WARNINGS</p><p>".decode_base64($rh_result->{WARNINGS})."</p></div>"; |
378 | <p >WARNINGS</p><p>".decode_base64($rh_result->{WARNINGS})."</p></div>"; |
| 319 | } |
379 | } |
| … | |
… | |
| 321 | ; |
381 | ; |
| 322 | # collect answers |
382 | # collect answers |
| 323 | my $answerTemplate = q{<hr>ANSWERS <table border="3" align="center">}; |
383 | my $answerTemplate = q{<hr>ANSWERS <table border="3" align="center">}; |
| 324 | my $problemNumber = 1; |
384 | my $problemNumber = 1; |
| 325 | foreach my $key (sort keys %{$rh_answers}) { |
385 | foreach my $key (sort keys %{$rh_answers}) { |
| 326 | $answerTemplate .= formatAnswerRow($rh_answers->{$key}, $problemNumber++); |
386 | $answerTemplate .= $self->formatAnswerRow($rh_answers->{$key}, $problemNumber++); |
| 327 | } |
387 | } |
| 328 | $answerTemplate .= q{</table> <hr>}; |
388 | $answerTemplate .= q{</table> <hr>}; |
| 329 | |
389 | |
| 330 | |
390 | |
| 331 | |
391 | |
| 332 | my $problemTemplate = <<ENDPROBLEMTEMPLATE; |
392 | my $problemTemplate = <<ENDPROBLEMTEMPLATE; |
| 333 | |
393 | <html> |
|
|
394 | <head> |
|
|
395 | <title>WeBWorK Editor</title> |
|
|
396 | </head> |
|
|
397 | <body> |
| 334 | $answerTemplate |
398 | $answerTemplate |
| 335 | $warnings |
399 | $warnings |
| 336 | <form action="http://webhost.math.rochester.edu/webworkdocs/ww/render" method="post"> |
400 | <form action="$FORM_ACTION_URL" method="post"> |
| 337 | $problemText |
401 | $problemText |
| 338 | <input type="hidden" name="answersSubmitted" value="1"> |
402 | <input type="hidden" name="answersSubmitted" value="1"> |
| 339 | <input type="hidden" name="problemAddress" value="probSource"> |
403 | <input type="hidden" name="problemAddress" value="probSource"> |
| 340 | <input type="hidden" name="problemSource" value="$encodedSource"> |
404 | <input type="hidden" name="problemSource" value="$encodedSource"> |
| 341 | <input type="hidden" name="problemSeed" value="1234"> |
405 | <input type="hidden" name="problemSeed" value="1234"> |
| 342 | <input type="hidden" name="pathToProblemFile" value="foobar"> |
406 | <input type="hidden" name="pathToProblemFile" value="foobar"> |
| 343 | <p><input type="submit" name="submit" value="submit answers"></p> |
407 | <p><input type="submit" name="submit" value="submit answers"></p> |
| 344 | </form> |
408 | </form> |
| 345 | |
409 | </body> |
|
|
410 | </html> |
| 346 | |
411 | |
| 347 | ENDPROBLEMTEMPLATE |
412 | ENDPROBLEMTEMPLATE |
| 348 | |
413 | |
| 349 | |
414 | |
| 350 | |
415 | |
| 351 | $problemTemplate; |
416 | $problemTemplate; |
| 352 | } |
417 | } |
|
|
418 | |
|
|
419 | |
|
|
420 | 1; |