[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 3553 - (download) (as text) (annotate)
Tue Aug 23 22:56:50 2005 UTC (14 years, 3 months ago) by jj
File size: 20444 byte(s)
This adds wiring to the pg side for special bits of html to be included before/after the body of a problem.  You also need to update global.conf (and probably want to update Tasks.pm).

A commented out example in global.conf.dist shows how to use this to produce boxed problems a la the Union College server.  In this approach, the added parts are not used for problems rendered in the Library Browser or Problem Set Detail.

This addresses bug 817.  This solution may not be suitable for inclusion of needed bits for modes such as asciimath or tth because the those bits of html are probably needed for display in the Library Browser.  It is hard to distinguish bits which are always wanted, and those which are only wanted for use by Problem.

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9