[system] / trunk / pg / macros / PG.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/PG.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4997 - (download) (as text) (annotate)
Mon Jun 11 18:16:40 2007 UTC (12 years, 7 months ago) by gage
File size: 20686 byte(s)
Fixing docementation so that it can be read from the web.

    1 
    2 # This file provided the fundamental macros for the pg language
    3 # These macros define the interface between the problems written by
    4 # the professor and the processing which occurs in the script
    5 # processProblem.pl
    6 
    7 
    8 BEGIN {
    9   be_strict();
   10 }
   11 
   12 sub _PG_init{
   13 
   14 }
   15 
   16 #package PG;
   17 
   18 
   19 =head1 NAME
   20 
   21   PG.pl --- located in the courseScripts directory.
   22   Defines the Program Generating language at the most basic level.
   23 
   24 =head1 SYNPOSIS
   25 
   26   The basic PG problem structure:
   27 
   28   DOCUMENT();          # should be the first statment in the problem
   29   loadMacros(.....);   # (optional) load other macro files if needed.
   30                        # (loadMacros is defined in F<dangerousMacros.pl>)
   31 
   32   HEADER_TEXT(...);    # (optional) used only for inserting javaScript into problems.
   33 
   34   #            #  insert text of problems
   35   TEXT("Problem text to be",
   36        "displayed. Enter 1 in this blank:",
   37        ANS_RULE(1,30)  #  ANS_RULE() defines an answer blank 30 characters long.
   38                        #  It is defined in F<PGbasicmacros.pl>
   39        );
   40 
   41 
   42   ANS( answer_evalutors);  # see F<PGanswermacros.pl> for examples of answer evaluatiors.
   43 
   44   ENDDOCUMENT()        # must be the last statement in the problem
   45 
   46 
   47 
   48 =head1 DESCRIPTION
   49 
   50 As described in the synopsis, this file and the macros C<DOCUMENT()> and C<ENDDOCUMENT()> determine
   51 the interface between problems written in the PG language and the rest of B<WeBWorK>, in particular
   52 the subroutine C<createPGtext(()> in the file F<translate.pl>.
   53 
   54 C<DOCUMENT()> must be the first statement in each problem template.
   55 It  initializes variables,
   56 in particular all of the contents of the
   57 environment variable  become defined in the problem enviroment.
   58 (See
   59 L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>)
   60 
   61 ENDDOCUMENT() must the last executable statement in any problem template.  It returns
   62 the rendered problem, answer evaluators and other flags to the rest of B<WeBWorK>, specificially
   63 to the routine C<createPGtext()> defined in F<translate.pl>
   64 
   65 
   66 The C<HEADER_TEXT()>, C<TEXT()>, and C<ANS()> functions load the
   67 header text string, the problem text string.
   68 and the answer evaulator queue respectively.
   69 
   70 
   71 =cut
   72 
   73 
   74 #  Private variables for the PG.pl file.
   75 
   76 my ($STRINGforOUTPUT, $STRINGforHEADER_TEXT, @PG_ANSWERS, @PG_UNLABELED_ANSWERS);
   77 my %PG_ANSWERS_HASH ;
   78 our $PG_STOP_FLAG;
   79 
   80 # my variables are unreliable if two DOCUMENTS were to be called before an ENDDOCUMENT
   81 # there could be conflicts.  As I understand the behavior of the Apache child
   82 # this cannot occur -- a child finishes with one request before obtaining the next
   83 
   84 #   DOCUMENT must come early in every .pg file, before any answers or text are
   85 # defined.  It initializes the variables.
   86 # It can appear only once.
   87 
   88 =head2 DOCUMENT()
   89 
   90 C<DOCUMENT()> must be the first statement in each problem template.  It can
   91 only be used once in each problem.
   92 
   93 C<DOCUMENT()> initializes some empty variables and via C<INITIALIZE_PG()> unpacks the
   94 variables in the C<%envir> variable which is implicitly passed to the problem. It must
   95 be the first statement in any problem template. It
   96 also unpacks any answers submitted and places them in the C<@submittedAnswer> list,
   97 saves the problem seed in C<$PG_original_problemSeed> in case you need it later, and
   98 initializes the pseudo random number generator object in C<$PG_random_generator>.
   99 
  100 You can reset the standard number generator using the command:
  101 
  102   $PG_random_generator->srand($new_seed_value);
  103 
  104 (See also C<SRAND> in the L<PGbasicmacros.pl> file.)
  105 
  106 The
  107 environment variable contents is defined in
  108 L</webwork_system_html/docs/techdescription/pglanguage/PGenvironment.html>
  109 
  110 
  111 =cut
  112 
  113 sub DOCUMENT {
  114 
  115   $STRINGforOUTPUT ="";
  116     $STRINGforHEADER_TEXT ="";
  117   @PG_ANSWERS=();
  118   $PG_STOP_FLAG=0;
  119   @PG_UNLABELED_ANSWERS = ();
  120   %PG_ANSWERS_HASH = ();
  121   # FIXME:  We are initializing these variables into both Safe::Root1 (the cached safe compartment)
  122   # and Safe::Root2 (the current one)
  123   # There is a good chance they won't be properly updated in one or the other of these compartments.
  124 
  125 #   @main::PG_ANSWER_ENTRY_ORDER = ();
  126 #   $main::ANSWER_PREFIX = 'AnSwEr';
  127 #   %main::PG_FLAGS=();  #global flags
  128 #   $main::showPartialCorrectAnswers = 0 unless defined($main::showPartialCorrectAnswers );
  129 #   $main::showHint = 1 unless defined($main::showHint);
  130 #   $main::solutionExists =0;
  131 #   $main::hintExists =0;
  132 #   %main::gifs_created = ();
  133   eval(q!
  134   @main::PG_ANSWER_ENTRY_ORDER = ();
  135   $main::ANSWER_PREFIX = 'AnSwEr';
  136   %main::PG_FLAGS=();  #global flags
  137   $main::showPartialCorrectAnswers = 0 unless defined($main::showPartialCorrectAnswers );
  138   $main::showHint = 1 unless defined($main::showHint);
  139   $main::solutionExists =0;
  140   $main::hintExists =0;
  141   $main::pgComment = '';
  142   %main::gifs_created = ();
  143 
  144     !);
  145 #    warn eval(q! "PG.pl:  The envir variable $main::{envir} is".join(" ",%main::envir)!);
  146     my $rh_envir = eval(q!\%main::envir!);
  147     my %envir    = %$rh_envir;
  148 
  149     # Save the file name for use in error messages
  150     my ($callpkg,$callfile) = caller(0);
  151     $envir{__files__}{$callfile} = $envir{templateDirectory}.$envir{fileName};
  152 
  153     #no strict;
  154     foreach  my  $var (keys %envir) {
  155       eval(q!$main::!.$var.q! = $main::envir{!.$var.q!}! );  #whew!! makes sure $var is interpolated but $main:: is evaluated at run time.
  156     #    warn eval(q! "var $var is defined ". $main::!.$var);
  157         warn "Problem defining ", q{\$main::}.$var, " while initializing the PG problem: $@" if $@;
  158     }
  159     #use strict;
  160     #FIXME these strict pragmas don't seem to be needed and they cause trouble in perl 5.6.0
  161 
  162 
  163 
  164     eval(q!
  165   @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers);
  166   $main::PG_original_problemSeed = $main::problemSeed;
  167   $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator.";
  168   $main::ans_rule_count = 0;  # counts questions
  169 
  170     # end unpacking of environment variables.
  171     $main::QUIZ_PREFIX = '' unless defined($main::QUIZ_PREFIX)
  172 
  173   !);
  174 #   @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers);
  175 #   $main::PG_original_problemSeed = $main::problemSeed;
  176 #   $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator.";
  177 #   $main::ans_rule_count = 0;  # counts questions
  178 
  179     # end unpacking of environment variables.
  180 #   $main::QUIZ_PREFIX = '' unless defined($main::QUIZ_PREFIX)
  181 
  182   if ($main::envir{displayMode} eq 'HTML_jsMath') {
  183     my $prefix = "";
  184     if (!$main::envir{jsMath}{reportMissingFonts}) {
  185       $prefix .= '<SCRIPT>noFontMessage = 1</SCRIPT>'."\n";
  186     } elsif ($main::envir{jsMath}{missingFontMessage}) {
  187       $prefix .= '<SCRIPT>missingFontMessage = "'.$main::envir{jsMath}{missingFontMessage}.'"</SCRIPT>'."\n";
  188     }
  189     $prefix .= '<SCRIPT>processDoubleClicks = '.($main::envir{jsMath}{processDoubleClicks}?'1':'0')."</SCRIPT>\n";
  190     $STRINGforOUTPUT =
  191       $prefix .
  192       '<SCRIPT SRC="'.$main::envir{jsMathURL}.'"></SCRIPT>' . "\n" .
  193       '<NOSCRIPT><CENTER><FONT COLOR="#CC0000">' .
  194       '<B>Warning: the mathematics on this page requires JavaScript.<BR>' .
  195       'If your browser supports it, be sure it is enabled.</B>'.
  196       '</FONT></CENTER><p></NOSCRIPT>' .
  197       $STRINGforOUTPUT;
  198     $STRINGforOUTPUT .=
  199       '<SCRIPT>jsMath.Setup.Script("plugins/noImageFonts.js")</SCRIPT>'
  200         if ($main::envir{jsMath}{noImageFonts});
  201   }
  202 
  203   $STRINGforOUTPUT = '<SCRIPT SRC="'.$main::envir{asciimathURL}.'"></SCRIPT>' . "\n" .
  204                            '<SCRIPT>mathcolor = "black"</SCRIPT>' . $STRINGforOUTPUT
  205     if ($main::envir{displayMode} eq 'HTML_asciimath');
  206 
  207   $STRINGforOUTPUT = '<SCRIPT SRC="'.$main::envir{LaTeXMathMLURL}.'"></SCRIPT>'."\n" . $STRINGforOUTPUT
  208     if ($main::envir{displayMode} eq 'HTML_LaTeXMathML');
  209 
  210 }
  211 
  212 sub inc_ans_rule_count {
  213   eval(q!++$main::ans_rule_count!); # evalute at runtime to get correct main::
  214 }
  215 # HEADER_TEXT is for material which is destined to be placed in the header of the html problem -- such
  216 #   as javaScript code.
  217 
  218 =head2 HEADER_TEXT()
  219 
  220 
  221   HEADER_TEXT("string1", "string2", "string3");
  222 
  223 The C<HEADER_TEXT()>
  224 function concatenates its arguments and places them in the output
  225 header text string.  It is used for material which is destined to be placed in
  226 the header of the html problem -- such as javaScript code.
  227  It can be used more than once in a file.
  228 
  229 
  230 =cut
  231 
  232 sub HEADER_TEXT {
  233   my @in = @_;
  234   $STRINGforHEADER_TEXT .= join(" ",@in);
  235   }
  236 
  237 # TEXT is the function which defines text which will appear in the problem.
  238 # All text must be an argument to this function.  Any other statements
  239 #   are calculations (done in perl) which will not directly appear in the
  240 # output.  Think of this as the "print" function for the .pg language.
  241 # It can be used more than once in a file.
  242 
  243 =head2 TEXT()
  244 
  245   TEXT("string1", "string2", "string3");
  246 
  247 The C<TEXT()> function concatenates its arguments and places them in the output
  248 text string. C<TEXT()> is the function which defines text which will appear in the problem.
  249 All text must be an argument to this function.  Any other statements
  250 are calculations (done in perl) which will not directly appear in the
  251 output.  Think of this as the "print" function for the .pg language.
  252 It can be used more than once in a file.
  253 
  254 =cut
  255 
  256 sub TEXT {
  257   return "" if $PG_STOP_FLAG;
  258   my @in = @_;
  259   $STRINGforOUTPUT .= join(" ",@in);
  260 }
  261 
  262 =head2 STOP_RENDERING()
  263 
  264   STOP_RENDERING() unless all_answers_are_correct;
  265 
  266 No text is printed and no answer blanks or answer evaluators are stored or processed until
  267 RESUME_RENDERING() is executed.
  268 
  269 =cut
  270 
  271 sub STOP_RENDERING {
  272   $PG_STOP_FLAG=1;
  273   "";
  274 }
  275 
  276 =head2 RESUME_RENDERING()
  277 
  278   RESUME_RENDERING();
  279 
  280 Resumes processing of text,  answer blanks,  and
  281 answer evaluators.
  282 
  283 =cut
  284 
  285 sub RESUME_RENDERING {
  286   $PG_STOP_FLAG=0;
  287   "";
  288 }
  289 
  290 =head2 ANS()
  291 
  292   ANS(answer_evaluator1, answer_evaluator2, answer_evaluator3,...)
  293 
  294 Places the answer evaluators in the unlabeled answer_evaluator queue.  They will be paired
  295 with unlabeled answer rules (answer entry blanks) in the order entered.  This is the standard
  296 method for entering answers.
  297 
  298   LABELED_ANS(answer_evaluater_name1, answer_evaluator1, answer_evaluater_name2,answer_evaluator2,...)
  299 
  300 Places the answer evaluators in the labeled answer_evaluator hash.  This allows pairing of
  301 labeled answer evaluators and labeled answer rules which may not have been entered in the same
  302 order.
  303 
  304 =cut
  305 
  306 sub ANS{             # store answer evaluators which have not been explicitly labeled
  307   return "" if $PG_STOP_FLAG;
  308   my @in = @_;
  309   while (@in ) {
  310          warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to
  311                       subroutines<BR>")
  312       unless ref($in[0]);
  313       push(@PG_ANSWERS, shift @in );
  314   }
  315 }
  316 sub LABELED_ANS {  #a better alias for NAMED_ANS
  317   &NAMED_ANS;
  318 }
  319 
  320 sub NAMED_ANS{     # store answer evaluators which have been explicitly labeled (submitted in a hash)
  321   return "" if $PG_STOP_FLAG;
  322   my @in = @_;
  323   while (@in ) {
  324     my $label = shift @in;
  325     $label = eval(q!$main::QUIZ_PREFIX.$label!);
  326     my $ans_eval = shift @in;
  327     TEXT("<BR><B>Error in NAMED_ANS:$in[0]</B>
  328           -- inputs must be references to subroutines<BR>")
  329       unless ref($ans_eval);
  330     $PG_ANSWERS_HASH{$label}= $ans_eval;
  331   }
  332 }
  333 sub RECORD_ANS_NAME {     # this maintains the order in which the answer rules are printed.
  334     return "" if $PG_STOP_FLAG;
  335   my $label = shift;
  336   eval(q!push(@main::PG_ANSWER_ENTRY_ORDER, $label)!);
  337   $label;
  338 }
  339 
  340 sub NEW_ANS_NAME {        # this keeps track of the answers which are entered implicitly,
  341                           # rather than with a specific label
  342         return "" if $PG_STOP_FLAG;
  343     my $number=shift;
  344     my $prefix = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!);
  345     my $label = $prefix.$number;
  346     push(@PG_UNLABELED_ANSWERS,$label);
  347     $label;
  348 }
  349 sub ANS_NUM_TO_NAME {     # This converts a number to an answer label for use in
  350                           # radio button and check box answers. No new answer
  351                           # name is recorded.
  352     my $number=shift;
  353     my $label = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!).$number;
  354     $label;
  355 }
  356 
  357 my $vecnum;
  358 
  359 sub RECORD_FORM_LABEL  {             # this stores form data (such as sticky answers), but does nothing more
  360                                      # it's a bit of hack since we are storing these in the KEPT_EXTRA_ANSWERS queue even if they aren't answers per se.
  361   return "" if $PG_STOP_FLAG;
  362   my $label   = shift;             # the label of the input box or textarea
  363     eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes
  364     $label;
  365 }
  366 sub NEW_ANS_ARRAY_NAME {        # this keeps track of the answers which are entered implicitly,
  367                           # rather than with a specific label
  368         return "" if $PG_STOP_FLAG;
  369     my $number=shift;
  370     $vecnum = 0;
  371     my $row = shift;
  372     my $col = shift;
  373 #   my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
  374     my $label = eval(q!$main::QUIZ_PREFIX."ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__"!);
  375     push(@PG_UNLABELED_ANSWERS,$label);
  376     $label;
  377 }
  378 
  379 sub NEW_ANS_ARRAY_NAME_EXTENSION {        # this keeps track of the answers which are entered implicitly,
  380                                           # rather than with a specific label
  381         return "" if $PG_STOP_FLAG;
  382     my $number=shift;
  383     my $row = shift;
  384     my $col = shift;
  385     if( $row == 0 && $col == 0 ){
  386       $vecnum += 1;
  387     }
  388     #FIXME   change made to conform to HTML 4.01 standards.  "Name" attributes can only contain
  389     # alphanumeric characters,   _ : and .
  390     # Also need to make corresponding changes in PGmorematrixmacros.  grep for ArRaY.
  391     #my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
  392     my $label = eval(q!$main::QUIZ_PREFIX."ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__"!);
  393     eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!);#put the labels into the hash to be caught later for recording purposes
  394     $label;
  395 }
  396 
  397 
  398 sub get_PG_ANSWERS_HASH {
  399   # update the PG_ANSWWERS_HASH, then report the result.
  400   # This is used in writing sequential problems
  401   # if there is an input, use that as a key into the answer hash
  402   my $key = shift;
  403   my (%pg_answers_hash, @pg_unlabeled_answers);
  404   %pg_answers_hash= %PG_ANSWERS_HASH;
  405   #warn "order ", eval(q!@main::PG_ANSWER_ENTRY_ORDER!);
  406   #warn "pg answers", %PG_ANSWERS_HASH;
  407   #warn "unlabeled", @PG_UNLABELED_ANSWERS;
  408     my $index=0;
  409     foreach my $label (@PG_UNLABELED_ANSWERS) {
  410         if ( defined($PG_ANSWERS[$index]) ) {
  411         $pg_answers_hash{"$label"}= $PG_ANSWERS[$index];
  412       #warn "recording answer label = $label";
  413       } else {
  414         warn "No answer provided by instructor for answer $label";
  415       }
  416       $index++;
  417     }
  418     if ($key) {
  419       return $pg_answers_hash{$key};
  420     } else {
  421       return %pg_answers_hash;
  422     }
  423 }
  424 # ENDDOCUMENT must come at the end of every .pg file.
  425 #   It exports the resulting text of the problem, the text to be used in HTML header material
  426 #   (for javaScript), the list of answer evaluators and any other flags.  It can appear only once and
  427 #   it MUST be the last statement in the problem.
  428 
  429 =head2 ENDDOCUMENT()
  430 
  431 ENDDOCUMENT() must the last executable statement in any problem template.  It can
  432 only appear once.  It returns
  433 an array consisting of
  434 
  435   A reference to a string containing the rendered text of the problem.
  436   A reference to a string containing text to be placed in the header
  437                (for javaScript)
  438   A reference to the array containing the answer evaluators.
  439                (May be changed to a hash soon.)
  440   A reference to an associative array (hash) containing various flags.
  441 
  442   The following flags are set by ENDDOCUMENT:
  443   (1) showPartialCorrectAnswers  -- determines whether students are told which
  444       of their answers in a problem are wrong.
  445   (2) recordSubmittedAnswers  -- determines whether students submitted answers
  446       are saved.
  447   (3) refreshCachedImages  -- determines whether the cached image of the problem
  448       in typeset mode is always refreshed (i.e. setting this to 1 means cached
  449       images are not used).
  450   (4) solutionExits   -- indicates the existence of a solution.
  451   (5) hintExits   -- indicates the existence of a hint.
  452   (6) comment   -- contents of COMMENT commands if any.
  453   (7) showHintLimit -- determines the number of attempts after which hint(s) will be shown
  454 
  455   (8) PROBLEM_GRADER_TO_USE -- chooses the problem grader to be used in this order
  456     (a) A problem grader specified by the problem using:
  457         install_problem_grader(\&grader);
  458     (b) One of the standard problem graders defined in PGanswermacros.pl when set to
  459         'std_problem_grader' or 'avg_problem_grader' by the environment variable
  460         $PG_environment{PROBLEM_GRADER_TO_USE}
  461     (c) A subroutine referenced by $PG_environment{PROBLEM_GRADER_TO_USE}
  462     (d) The default &std_problem_grader defined in PGanswermacros.pl
  463 
  464 
  465 =cut
  466 
  467 sub ENDDOCUMENT {
  468 
  469     my $index=0;
  470     foreach my $label (@PG_UNLABELED_ANSWERS) {
  471         if ( defined($PG_ANSWERS[$index]) ) {
  472         $PG_ANSWERS_HASH{"$label"}= $PG_ANSWERS[$index];
  473       #warn "recording answer label = $label";
  474       } else {
  475         warn "No answer provided by instructor for answer $label";
  476       }
  477       $index++;
  478     }
  479 
  480     $STRINGforOUTPUT .="\n";
  481    eval q{  #make sure that "main" points to the current safe compartment by evaluating these lines.
  482     $main::PG_FLAGS{'showPartialCorrectAnswers'} = $main::showPartialCorrectAnswers;
  483     $main::PG_FLAGS{'recordSubmittedAnswers'} = $main::recordSubmittedAnswers;
  484     $main::PG_FLAGS{'refreshCachedImages'} = $main::refreshCachedImages;
  485     $main::PG_FLAGS{'comment'} = $main::pgComment;
  486     $main::PG_FLAGS{'hintExists'} = $main::hintExists;
  487     $main::PG_FLAGS{'showHintLimit'} = $main::showHint;
  488     $main::PG_FLAGS{'solutionExists'} = $main::solutionExists;
  489     $main::PG_FLAGS{ANSWER_ENTRY_ORDER} = \@main::PG_ANSWER_ENTRY_ORDER;
  490     $main::PG_FLAGS{KEPT_EXTRA_ANSWERS} = \@main::KEPT_EXTRA_ANSWERS;##need to keep array labels that don't call "RECORD_ANS_NAME"
  491     $main::PG_FLAGS{ANSWER_PREFIX} = $main::ANSWER_PREFIX;
  492     # install problem grader
  493     if (defined($main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) ) {
  494       # problem grader defined within problem -- no further action needed
  495     } elsif ( defined( $main::envir{PROBLEM_GRADER_TO_USE} ) ) {
  496       if (ref($main::envir{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) {         # user defined grader
  497         $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = $main::envir{PROBLEM_GRADER_TO_USE};
  498       } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) {
  499         if (defined(&std_problem_grader) ){
  500           $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  501         } # std_problem_grader is the default in any case so don't give a warning.
  502       } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) {
  503         if (defined(&avg_problem_grader) ){
  504           $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl
  505         }
  506         #else { # avg_problem_grader will be installed by PGtranslator so there is no need for a warning.
  507         # warn "The problem grader 'avg_problem_grader' has not been defined.  Has PGanswermacros.pl been loaded?";
  508         #}
  509       } else {
  510         warn "Error:  $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} is not a known program grader.";
  511       }
  512     } elsif (defined(&std_problem_grader)) {
  513       $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  514     } else {
  515       # PGtranslator will install its default problem grader
  516     }
  517 
  518     warn "ERROR: The problem grader is not a subroutine" unless ref( $main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) eq 'CODE'
  519                      or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'std_problem_grader'
  520                      or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'avg_problem_grader';
  521      # return results
  522     };
  523 
  524     $STRINGforOUTPUT .= '<SCRIPT> jsMath.wwProcess() </SCRIPT>'
  525       if ($main::envir{displayMode} eq 'HTML_jsMath');
  526 
  527     if ($main::envir{displayMode} eq 'HTML_asciimath') {
  528       $STRINGforOUTPUT .= '<SCRIPT> translate() </SCRIPT>';
  529       $STRINGforHEADER_TEXT .=
  530         '<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n" .
  531         '</object><?import namespace="mml" implementation="#mathplayer"?>'
  532   unless ($STRINGforHEADER_TEXT =~ m/mathplayer/);
  533     }
  534   $STRINGforOUTPUT .= MODES(%{PG_restricted_eval('$main::problemPostamble')});
  535 
  536   (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,eval(q!\%main::PG_FLAGS!));
  537 }
  538 
  539 
  540 
  541 =head2 INITIALIZE_PG()
  542 
  543 This is executed each C<DOCUMENT()> is called.  For backward compatibility
  544 C<loadMacros> also checks whether the C<macroDirectory> has been defined
  545 and if not, it runs C<INITIALIZE_PG()> and issues a warning.
  546 
  547 =cut
  548 
  549 
  550 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9