[system] / trunk / webwork-modperl / lib / WeBWorK / PG.pm Repository:
ViewVC logotype

Diff of /trunk/webwork-modperl/lib/WeBWorK/PG.pm

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

Revision 1239 Revision 2217
1################################################################################ 1################################################################################
2# WeBWorK mod_perl (c) 2000-2002 WeBWorK Project 2# WeBWorK Online Homework Delivery System
3# $Id$ 3# Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
4# $CVSHeader: webwork-modperl/lib/WeBWorK/PG.pm,v 1.51 2004/05/24 02:01:25 dpvc Exp $
5#
6# This program is free software; you can redistribute it and/or modify it under
7# the terms of either: (a) the GNU General Public License as published by the
8# Free Software Foundation; either version 2, or (at your option) any later
9# version, or (b) the "Artistic License" which comes with this package.
10#
11# This program is distributed in the hope that it will be useful, but WITHOUT
12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
14# Artistic License for more details.
4################################################################################ 15################################################################################
5 16
6package WeBWorK::PG; 17package WeBWorK::PG;
7 18
8=head1 NAME 19=head1 NAME
9 20
10WeBWorK::PG - Wrap the action of the PG Translator in an easy-to-use API. 21WeBWorK::PG - Invoke one of several PG rendering methods using an easy-to-use
22API.
11 23
12=cut 24=cut
13 25
14use strict; 26use strict;
15use warnings; 27use warnings;
16use File::Path qw(rmtree);
17use WeBWorK::PG::ImageGenerator; 28use WeBWorK::PG::ImageGenerator;
18use WeBWorK::PG::Translator;
19use WeBWorK::Utils qw(readFile formatDateTime writeTimingLogEntry makeTempDirectory); 29use WeBWorK::Utils qw(runtime_use formatDateTime makeTempDirectory);
30
31use constant DISPLAY_MODES => {
32 # display name # mode name
33 tex => "TeX",
34 plainText => "HTML",
35 formattedText => "HTML_tth",
36 images => "HTML_dpng",
37 jsMath => "HTML_jsMath",
38 asciimath => "HTML_asciimath",
39};
40
41use constant DISPLAY_MODE_FAILOVER => {
42 TeX => [],
43 HTML => [],
44 HTML_tth => [ "HTML", ],
45 HTML_dpng => [ "HTML_tth", "HTML", ],
46 HTML_jsMath => [ "HTML_dpng", "HTML_tth", "HTML", ],
47 HTML_asciimath => [ "HTML_dpng", "HTML_tth", "HTML", ],
48 # legacy modes -- these are not supported, but some problems might try to
49 # set the display mode to one of these values manually and some macros may
50 # provide rendered versions for these modes but not the one we want.
51 Latex2HTML => [ "TeX", "HTML", ],
52 HTML_img => [ "HTML_dpng", "HTML_tth", "HTML", ],
53};
20 54
21sub new { 55sub new {
22 my $invocant = shift; 56 shift; # throw away invocant -- we don't need it
23 my $class = ref($invocant) || $invocant; 57 my ($ce, $user, $key, $set, $problem, $psvn, $formFields,
24 my (
25 $ce,
26 $user,
27 $key,
28 $set,
29 $problem,
30 $psvn,
31 $formFields, # in CGI::Vars format
32 $translationOptions, # hashref containing options for the
33 # translator, such as whether to show
34 # hints and the display mode to use
35 ) = @_;
36
37 # write timing log entry
38 writeTimingLogEntry($ce, "WeBWorK::PG::new",
39 "user=".$user->user_id.",problem=".$ce->{courseName}."/".$set->set_id."/".$problem->problem_id.",mode=".$translationOptions->{displayMode},
40 "begin");
41
42 # install a local warn handler to collect warnings
43 my $warnings = "";
44 local $SIG{__WARN__} = sub { $warnings .= shift }
45 if $ce->{pg}->{options}->{catchWarnings};
46
47 # create a Translator
48 #warn "PG: creating a Translator\n";
49 my $translator = WeBWorK::PG::Translator->new;
50
51 # set the directory hash
52 #warn "PG: setting the directory hash\n";
53 $translator->rh_directories({
54 courseScriptsDirectory => $ce->{pg}->{directories}->{macros},
55 macroDirectory => $ce->{courseDirs}->{macros},
56 templateDirectory => $ce->{courseDirs}->{templates},
57 tempDirectory => $ce->{courseDirs}->{html_temp},
58 });
59
60 # evaluate modules and "extra packages"
61 #warn "PG: evaluating modules and \"extra packages\"\n";
62 my @modules = @{ $ce->{pg}->{modules} };
63 foreach my $module_packages_ref (@modules) {
64 my ($module, @extra_packages) = @$module_packages_ref;
65 # the first item is the main package
66 $translator->evaluate_modules($module);
67 # the remaining items are "extra" packages
68 $translator->load_extra_packages(@extra_packages);
69 }
70
71 # set the environment (from defineProblemEnvir)
72 #warn "PG: setting the environment (from defineProblemEnvir)\n";
73 my $envir = defineProblemEnvir(
74 $ce,
75 $user,
76 $key,
77 $set,
78 $problem,
79 $psvn,
80 $formFields,
81 $translationOptions, 58 $translationOptions) = @_;
82 );
83 $translator->environment($envir);
84 59
85 # initialize the Translator 60 my $renderer = $ce->{pg}->{renderer};
86 #warn "PG: initializing the Translator\n";
87 $translator->initialize();
88 61
89 # load IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load 62 runtime_use $renderer;
90 # i'd like to change this at some point to have the same sort of interface to global.conf
91 # that the module loading does -- have a list of macros to load unrestrictedly.
92 #warn "PG: loading IO.pl, PG.pl, and dangerousMacros.pl using unrestricted_load\n";
93 foreach (qw(IO.pl PG.pl dangerousMacros.pl)) {
94 my $macroPath = $ce->{pg}->{directories}->{macros} . "/$_";
95 my $err = $translator->unrestricted_load($macroPath);
96 warn "Error while loading $macroPath: $err" if $err;
97 }
98 63
99 # set the opcode mask (using default values) 64 return $renderer->new(@_);
100 #warn "PG: setting the opcode mask (using default values)\n";
101 $translator->set_mask();
102
103 # store the problem source
104 #warn "PG: storing the problem source\n";
105 my $sourceFile = $problem->source_file;
106 $sourceFile = $ce->{courseDirs}->{templates}."/".$sourceFile
107 unless ($sourceFile =~ /^\//);
108 eval { $translator->source_string(readFile($sourceFile)) };
109 if ($@) {
110 # well, we couldn't get the problem source, for some reason.
111 return bless {
112 translator => $translator,
113 head_text => "",
114 body_text => <<EOF,
115WeBWorK::Utils::readFile($sourceFile) says:
116$@
117EOF
118 answers => {},
119 result => {},
120 state => {},
121 errors => "Failed to read the problem source file.",
122 warnings => $warnings,
123 flags => {error_flag => 1},
124 }, $class;
125 }
126
127 # install a safety filter (&safetyFilter)
128 #warn "PG: installing a safety filter\n";
129 $translator->rf_safety_filter(\&safetyFilter);
130
131 # write timing log entry -- the translator is now all set up
132 writeTimingLogEntry($ce, "WeBWorK::PG::new",
133 "initialized",
134 "intermediate");
135
136 # translate the PG source into text
137 #warn "PG: translating the PG source into text\n";
138 $translator->translate();
139
140 # after we're done translating, we may have to clean up after the
141 # translator:
142
143 # for example, HTML_img mode uses a tempdir for dvipng's temp files.\
144 # We have to remove it.
145 if ($envir->{dvipngTempDir}) {
146 rmtree($envir->{dvipngTempDir}, 0, 0);
147 }
148
149 # HTML_dpng, on the other hand, uses an ImageGenerator. We have to
150 # render the queued equations.
151 if ($envir->{imagegen}) {
152 my $sourceFile = $ce->{courseDirs}->{templates} . "/" . $problem->source_file;
153 my %mtimeOption = -e $sourceFile
154 ? (mtime => (stat $sourceFile)[9])
155 : ();
156
157 $envir->{imagegen}->render(
158 refresh => $translationOptions->{refreshMath2img},
159 %mtimeOption,
160 );
161 }
162
163 my ($result, $state); # we'll need these on the other side of the if block!
164 if ($translationOptions->{processAnswers}) {
165
166 # process student answers
167 #warn "PG: processing student answers\n";
168 $translator->process_answers($formFields);
169
170 # retrieve the problem state and give it to the translator
171 #warn "PG: retrieving the problem state and giving it to the translator\n";
172 $translator->rh_problem_state({
173 recorded_score => $problem->status,
174 num_of_correct_ans => $problem->num_correct,
175 num_of_incorrect_ans => $problem->num_incorrect,
176 });
177
178 # determine an entry order -- the ANSWER_ENTRY_ORDER flag is built by
179 # the PG macro package (PG.pl)
180 #warn "PG: determining an entry order\n";
181 my @answerOrder =
182 $translator->rh_flags->{ANSWER_ENTRY_ORDER}
183 ? @{ $translator->rh_flags->{ANSWER_ENTRY_ORDER} }
184 : keys %{ $translator->rh_evaluated_answers };
185
186 # install a grader -- use the one specified in the problem,
187 # or fall back on the default from the course environment.
188 # (two magic strings are accepted, to avoid having to
189 # reference code when it would be difficult.)
190 #warn "PG: installing a grader\n";
191 my $grader = $translator->rh_flags->{PROBLEM_GRADER_TO_USE}
192 || $ce->{pg}->{options}->{grader};
193 $grader = $translator->rf_std_problem_grader
194 if $grader eq "std_problem_grader";
195 $grader = $translator->rf_avg_problem_grader
196 if $grader eq "avg_problem_grader";
197 die "Problem grader $grader is not a CODE reference."
198 unless ref $grader eq "CODE";
199 $translator->rf_problem_grader($grader);
200
201 # grade the problem
202 #warn "PG: grading the problem\n";
203 ($result, $state) = $translator->grade_problem(
204 answers_submitted => $translationOptions->{processAnswers},
205 ANSWER_ENTRY_ORDER => \@answerOrder,
206 );
207
208 }
209
210 # write timing log entry
211 writeTimingLogEntry($ce, "WeBWorK::PG::new", "", "end");
212
213 # return an object which contains the translator and the results of
214 # the translation process. this is DIFFERENT from the "format expected
215 # by Webwork.pm (and I believe processProblem8, but check.)"
216 return bless {
217 translator => $translator,
218 head_text => ${ $translator->r_header },
219 body_text => ${ $translator->r_text },
220 answers => $translator->rh_evaluated_answers,
221 result => $result,
222 state => $state,
223 errors => $translator->errors,
224 warnings => $warnings,
225 flags => $translator->rh_flags,
226 }, $class;
227} 65}
228
229# -----
230 66
231sub defineProblemEnvir { 67sub defineProblemEnvir {
232 my ( 68 my (
69 $self,
233 $ce, 70 $ce,
234 $user, 71 $user,
235 $key, 72 $key,
236 $set, 73 $set,
237 $problem, 74 $problem,
247 # PG environment variables 84 # PG environment variables
248 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002 85 # from docs/pglanguage/pgreference/environmentvariables as of 06/25/2002
249 # any changes are noted by "ADDED:" or "REMOVED:" 86 # any changes are noted by "ADDED:" or "REMOVED:"
250 87
251 # Vital state information 88 # Vital state information
252 # ADDED: displayHintsQ, displaySolutionsQ, refreshMath2img, 89 # ADDED: displayModeFailover, displayHintsQ, displaySolutionsQ,
253 # texDisposition 90 # refreshMath2img, texDisposition
254 91
255 $envir{psvn} = $set->psvn; 92 $envir{psvn} = $set->psvn;
256 $envir{psvnNumber} = $envir{psvn}; 93 $envir{psvnNumber} = $envir{psvn};
257 $envir{probNum} = $problem->problem_id; 94 $envir{probNum} = $problem->problem_id;
258 $envir{questionNumber} = $envir{probNum}; 95 $envir{questionNumber} = $envir{probNum};
259 $envir{fileName} = $problem->source_file; 96 $envir{fileName} = $problem->source_file;
260 $envir{probFileName} = $envir{fileName}; 97 $envir{probFileName} = $envir{fileName};
261 $envir{problemSeed} = $problem->problem_seed; 98 $envir{problemSeed} = $problem->problem_seed;
262 $envir{displayMode} = translateDisplayModeNames($options->{displayMode}); 99 $envir{displayMode} = translateDisplayModeNames($options->{displayMode});
263 $envir{languageMode} = $envir{displayMode}; 100 $envir{languageMode} = $envir{displayMode};
264 $envir{outputMode} = $envir{displayMode}; 101 $envir{outputMode} = $envir{displayMode};
102 $envir{displayModeFailover} = DISPLAY_MODE_FAILOVER();
265 $envir{displayHintsQ} = $options->{showHints}; 103 $envir{displayHintsQ} = $options->{showHints};
266 $envir{displaySolutionsQ} = $options->{showSolutions}; 104 $envir{displaySolutionsQ} = $options->{showSolutions};
267 # FIXME: this is HTML_img specific
268 #$envir{refreshMath2img} = $options->{refreshMath2img};
269 $envir{texDisposition} = "pdf"; # in webwork-modperl, we use pdflatex 105 $envir{texDisposition} = "pdf"; # in webwork2, we use pdflatex
270 106
271 # Problem Information 107 # Problem Information
272 # ADDED: courseName, formatedDueDate 108 # ADDED: courseName, formatedDueDate
273 109
274 $envir{openDate} = $set->open_date; 110 $envir{openDate} = $set->open_date;
312 $envir{externalGif2PngPath} = $ce->{externalPrograms}->{gif2png}; 148 $envir{externalGif2PngPath} = $ce->{externalPrograms}->{gif2png};
313 149
314 # Directories and URLs 150 # Directories and URLs
315 # REMOVED: courseName 151 # REMOVED: courseName
316 # ADDED: dvipngTempDir 152 # ADDED: dvipngTempDir
153 # ADDED: jsMathURL
154 # ADDED: asciimathURL
317 155
318 $envir{cgiDirectory} = undef; 156 $envir{cgiDirectory} = undef;
319 $envir{cgiURL} = undef; 157 $envir{cgiURL} = undef;
320 $envir{classDirectory} = undef; 158 $envir{classDirectory} = undef;
321 $envir{courseScriptsDirectory} = $ce->{pg}->{directories}->{macros}."/"; 159 $envir{courseScriptsDirectory} = $ce->{pg}->{directories}->{macros}."/";
325 $envir{templateDirectory} = $ce->{courseDirs}->{templates}."/"; 163 $envir{templateDirectory} = $ce->{courseDirs}->{templates}."/";
326 $envir{tempDirectory} = $ce->{courseDirs}->{html_temp}."/"; 164 $envir{tempDirectory} = $ce->{courseDirs}->{html_temp}."/";
327 $envir{tempURL} = $ce->{courseURLs}->{html_temp}."/"; 165 $envir{tempURL} = $ce->{courseURLs}->{html_temp}."/";
328 $envir{scriptDirectory} = undef; 166 $envir{scriptDirectory} = undef;
329 $envir{webworkDocsURL} = $ce->{webworkURLs}->{docs}."/"; 167 $envir{webworkDocsURL} = $ce->{webworkURLs}->{docs}."/";
330 # FIXME: this is HTML_img mode-specific 168 $envir{localHelpURL} = $ce->{webworkURLs}->{local_help}."/";
331 #$envir{dvipngTempDir} = $options->{displayMode} eq 'images' 169 $envir{jsMathURL} = $ce->{webworkURLs}->{jsMath};
332 # ? makeTempDirectory($envir{tempDirectory}, "webwork-dvipng") 170 $envir{asciimathURL} = $ce->{webworkURLs}->{asciimath};
333 # : undef;
334 171
335 # Information for sending mail 172 # Information for sending mail
336 173
337 $envir{mailSmtpServer} = $ce->{mail}->{smtpServer}; 174 $envir{mailSmtpServer} = $ce->{mail}->{smtpServer};
338 $envir{mailSmtpSender} = $ce->{mail}->{smtpSender}; 175 $envir{mailSmtpSender} = $ce->{mail}->{smtpSender};
349 $basename .= ".$envir{problemSeed}" if $envir{problemSeed}; 186 $basename .= ".$envir{problemSeed}" if $envir{problemSeed};
350 187
351 # Object for generating equation images 188 # Object for generating equation images
352 $envir{imagegen} = WeBWorK::PG::ImageGenerator->new( 189 $envir{imagegen} = WeBWorK::PG::ImageGenerator->new(
353 tempDir => $ce->{webworkDirs}->{tmp}, # global temp dir 190 tempDir => $ce->{webworkDirs}->{tmp}, # global temp dir
354 dir => $envir{tempDirectory},
355 url => $envir{tempURL},
356 basename => $basename,
357 latex => $envir{externalLaTeXPath}, 191 latex => $envir{externalLaTeXPath},
358 dvipng => $envir{externalDvipngPath}, 192 dvipng => $envir{externalDvipngPath},
193 useCache => 1,
194 cacheDir => $ce->{webworkDirs}->{equationCache},
195 cacheURL => $ce->{webworkURLs}->{equationCache},
196 cacheDB => $ce->{webworkFiles}->{equationCacheDB},
359 ); 197 );
360 198
361 # Other things... 199 # Other things...
362 $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes 200 $envir{QUIZ_PREFIX} = $options->{QUIZ_PREFIX}; # used by quizzes
363 $envir{PROBLEM_GRADER_TO_USE} = $ce->{pg}->{options}->{grader}; 201 $envir{PROBLEM_GRADER_TO_USE} = $ce->{pg}->{options}->{grader};
364 $envir{PRINT_FILE_NAMES_FOR} = $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR}; 202 $envir{PRINT_FILE_NAMES_FOR} = $ce->{pg}->{specialPGEnvironmentVars}->{PRINT_FILE_NAMES_FOR};
365 203
366 # variables for interpreting capa problems. 204 # variables for interpreting capa problems and other things to be
367 $envir{CAPA_Tools} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_Tools}; 205 # seen in a pg file
368 $envir{CAPA_MCTools} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_MCTools}; 206 my $specialPGEnvironmentVarHash = $ce->{pg}->{specialPGEnvironmentVars};
369 $envir{CAPA_Graphics_URL} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_Graphics_URL}; 207 for my $SPGEV (keys %{$specialPGEnvironmentVarHash}) {
370 $envir{CAPA_GraphicsDirectory} = $ce->{pg}->{specialPGEnvironmentVars}->{CAPA_GraphicsDirectory}; 208 $envir{$SPGEV} = $specialPGEnvironmentVarHash->{$SPGEV};
209 }
371 210
372 return \%envir; 211 return \%envir;
373} 212}
374 213
375sub translateDisplayModeNames($) { 214sub translateDisplayModeNames($) {
376 my $name = shift; 215 my $name = shift;
377 return { 216 return DISPLAY_MODES()->{$name};
378 tex => "TeX",
379 plainText => "HTML",
380 formattedText => "HTML_tth",
381 images => "HTML_dpng", # "HTML_img",
382 }->{$name};
383} 217}
384 218
385sub safetyFilter { 219sub oldSafetyFilter {
386 my $answer = shift; # accepts one answer and checks it 220 my $answer = shift; # accepts one answer and checks it
387 my $submittedAnswer = $answer; 221 my $submittedAnswer = $answer;
388 $answer = '' unless defined $answer; 222 $answer = '' unless defined $answer;
389 my ($errorno); 223 my ($errorno);
390 $answer =~ tr/\000-\037/ /; 224 $answer =~ tr/\000-\037/ /;
404 } 238 }
405 $errorno = 0; 239 $errorno = 0;
406 return($answer, $errorno); 240 return($answer, $errorno);
407} 241}
408 242
243sub nullSafetyFilter {
244 return shift, 0; # no errors
245}
246
4091; 2471;
410 248
411__END__ 249__END__
412 250
413=head1 SYNOPSIS 251=head1 SYNOPSIS
439 $warnings = $pg->{warnings}; # text string 277 $warnings = $pg->{warnings}; # text string
440 $flags = $pg->{flags}; # hash reference 278 $flags = $pg->{flags}; # hash reference
441 279
442=head1 DESCRIPTION 280=head1 DESCRIPTION
443 281
444WeBWorK::PG encapsulates the PG translation process, making multiple calls to 282WeBWorK::PG is a factory for modules which use the WeBWorK::PG API. Notable
445WeBWorK::PG::Translator. Much of the flexibility of the Translator is hidden, 283modules which use this API (and exist) are WeBWorK::PG::Local and
446instead making choices that are appropriate for the webwork-modperl system. 284WeBWorK::PG::Remote. The course environment key $pg{renderer} is consulted to
285determine which render to use.
447 286
448=head1 CONSTRUCTION 287=head1 THE WEBWORK::PG API
288
289Modules which support this API must implement the following method:
449 290
450=over 291=over
451 292
452=item new (ENVIRONMENT, USER, KEY, SET, PROBLEM, PSVN, FIELDS, OPTIONS) 293=item new ENVIRONMENT, USER, KEY, SET, PROBLEM, PSVN, FIELDS, OPTIONS
453 294
454The C<new> method creates a translator, initializes it using the parameters 295The C<new> method creates a translator, initializes it using the parameters
455specified, translates a PG file, and processes answers. It returns a reference 296specified, translates a PG file, and processes answers. It returns a reference
456to a blessed hash containing the results of the translation process. 297to a blessed hash containing the results of the translation process.
457 298
513boolean, render solutions 354boolean, render solutions
514 355
515=item refreshMath2img 356=item refreshMath2img
516 357
517boolean, force images created by math2img (in "images" mode) to be recreated, 358boolean, force images created by math2img (in "images" mode) to be recreated,
518even if the PG source has not been updated. FIXME: change the name of this 359even if the PG source has not been updated. FIXME: remove this option.
519option to "refreshEquations" and update the docs accordingly.
520 360
521=item processAnswers 361=item processAnswers
522 362
523boolean, call answer evaluators and graders 363boolean, call answer evaluators and graders
524 364
572 412
573A hash containing PG_flags (see the Translator docs). 413A hash containing PG_flags (see the Translator docs).
574 414
575=back 415=back
576 416
577=head1 OPERATION 417=head1 METHODS PROVIDED BY THE BASE CLASS
578 418
579WeBWorK::PG goes through the following operations when constructed: 419The following methods are provided for use by subclasses of WeBWorK::PG.
580 420
581=over 421=over
582 422
583=item Get database information 423=item defineProblemEnvir ENVIRONMENT, USER, KEY, SET, PROBLEM, PSVN, FIELDS, OPTIONS
584 424
585Retrieve information about the current user, set, and problem from the 425Generate a problem environment hash to pass to the renderer.
586database.
587 426
588=item Create a translator 427=item translateDisplayModeNames NAME
589 428
590Instantiate a WeBWorK::PG::Translator object. 429NAME contains
591
592=item Set the directory hash
593
594Set the translator's directory hash (courseScripts, macros, templates, and temp
595directories) from the course environment.
596
597=item Evaluate PG modules
598
599Using the module list from the course environment (pg->modules), perform a
600"use"-like operation to evaluate modules at runtime.
601
602=item Set the problem environment
603
604Use data from the user, set, and problem, as well as the course environemnt and
605translation options, to set the problem environment.
606
607=item Initialize the translator
608
609Call &WeBWorK::PG::Translator::initialize. What more do you want?
610
611=item Load PG.pl and dangerousMacros.pl
612
613These macros must be loaded without opcode masking, so they are loaded here.
614
615=item Set the opcode mask
616
617Set the opcode mask to the default specified by WeBWorK::PG::Translator.
618
619=item Load the problem source
620
621Give the problem source to the translator.
622
623=item Install a safety filter
624
625The safety filter is used to preprocess student input before evaluation. The
626default safety filter, &WeBWorK::PG::safetyFilter, is used.
627
628=item Translate the problem source
629
630Call &WeBWorK::PG::Translator::translate to render the problem source into the
631format given by the display mode.
632
633=item Process student answers
634
635Use form field inputs to evaluate student answers.
636
637=item Load the problem state
638
639Use values from the database to initialize the problem state, so that the
640grader will have a point of reference.
641
642=item Determine an entry order
643
644Use the ANSWER_ENTRY_ORDER flag to determine the order of answers in the
645problem. This is important for problems with dependancies among parts.
646
647=item Install a grader
648
649Use the PROBLEM_GRADER_TO_USE flag, or a default from the course environment,
650to install a grader.
651
652=item Grade the problem
653
654Use the selected grader to grade the problem.
655 430
656=back 431=back
657 432
658=head1 AUTHOR 433=head1 AUTHOR
659 434

Legend:
Removed from v.1239  
changed lines
  Added in v.2217

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9