[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 3385 - (download) (as text) (annotate)
Sat Jul 16 21:59:35 2005 UTC (14 years, 6 months ago) by gage
File size: 19806 byte(s)
Added support for sequentialProblems.

    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::gifs_created = ();
  141 
  142     !);
  143 #    warn eval(q! "PG.pl:  The envir variable $main::{envir} is".join(" ",%main::envir)!);
  144     my $rh_envir = eval(q!\%main::envir!);
  145     my %envir    = %$rh_envir;
  146 
  147     # Save the file name for use in error messages
  148     my ($callpkg,$callfile) = caller(0);
  149     $envir{__files__}{$callfile} = $envir{templateDirectory}.$envir{fileName};
  150 
  151     #no strict;
  152     foreach  my  $var (keys %envir) {
  153       eval(q!$main::!.$var.q! = $main::envir{!.$var.q!}! );  #whew!! makes sure $var is interpolated but $main:: is evaluated at run time.
  154     #    warn eval(q! "var $var is defined ". $main::!.$var);
  155         warn "Problem defining ", q{\$main::}.$var, " while initializing the PG problem: $@" if $@;
  156     }
  157     #use strict;
  158     #FIXME these strict pragmas don't seem to be needed and they cause trouble in perl 5.6.0
  159 
  160 
  161 
  162     eval(q!
  163   @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers);
  164   $main::PG_original_problemSeed = $main::problemSeed;
  165   $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator.";
  166   $main::ans_rule_count = 0;  # counts questions
  167 
  168     # end unpacking of environment variables.
  169     $main::QUIZ_PREFIX = '' unless defined($main::QUIZ_PREFIX)
  170 
  171   !);
  172 #   @main::submittedAnswers = @{$main::refSubmittedAnswers} if defined($main::refSubmittedAnswers);
  173 #   $main::PG_original_problemSeed = $main::problemSeed;
  174 #   $main::PG_random_generator = new PGrandom($main::problemSeed) || die "Can't create random number generator.";
  175 #   $main::ans_rule_count = 0;  # counts questions
  176 
  177     # end unpacking of environment variables.
  178 #   $main::QUIZ_PREFIX = '' unless defined($main::QUIZ_PREFIX)
  179 
  180   if ($main::envir{displayMode} eq 'HTML_jsMath') {
  181     my $prefix = "";
  182     if (!$main::envir{jsMath}{reportMissingFonts}) {
  183       $prefix .= '<SCRIPT>function NoFontMessage() {}</SCRIPT>';
  184     } elsif ($main::envir{jsMath}{missingFontMessage}) {
  185       $prefix .=
  186         '<SCRIPT>'.
  187         '  function NoFontMessage() {'.
  188         '    document.writeln(\'<DIV CLASS="noFontMessage">'.
  189           $main::envir{jsMath}{missingFontMessage}.'</DIV>\');'.
  190         '  }' .
  191         '</SCRIPT>';
  192     }
  193     $STRINGforOUTPUT =
  194       $prefix .
  195       '<SCRIPT SRC="'.$main::envir{jsMathURL}.'"></SCRIPT>' . "\n" .
  196       '<NOSCRIPT><CENTER><FONT COLOR="#CC0000">' .
  197       '<B>Warning: the mathematics on this page requires JavaScript.<BR>' .
  198       'If your browser supports it, be sure it is enabled.</B>'.
  199       '</FONT></CENTER><p></NOSCRIPT>' .
  200       $STRINGforOUTPUT;
  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 }
  208 
  209 sub inc_ans_rule_count {
  210   eval(q!++$main::ans_rule_count!); # evalute at runtime to get correct main::
  211 }
  212 # HEADER_TEXT is for material which is destined to be placed in the header of the html problem -- such
  213 #   as javaScript code.
  214 
  215 =head2 HEADER_TEXT()
  216 
  217 
  218   HEADER_TEXT("string1", "string2", "string3");
  219 
  220 The C<HEADER_TEXT()>
  221 function concatenates its arguments and places them in the output
  222 header text string.  It is used for material which is destined to be placed in
  223 the header of the html problem -- such as javaScript code.
  224  It can be used more than once in a file.
  225 
  226 
  227 =cut
  228 
  229 sub HEADER_TEXT {
  230   my @in = @_;
  231   $STRINGforHEADER_TEXT .= join(" ",@in);
  232   }
  233 
  234 # TEXT is the function which defines text which will appear in the problem.
  235 # All text must be an argument to this function.  Any other statements
  236 #   are calculations (done in perl) which will not directly appear in the
  237 # output.  Think of this as the "print" function for the .pg language.
  238 # It can be used more than once in a file.
  239 
  240 =head2 TEXT()
  241 
  242   TEXT("string1", "string2", "string3");
  243 
  244 The C<TEXT()> function concatenates its arguments and places them in the output
  245 text string. C<TEXT()> is the function which defines text which will appear in the problem.
  246 All text must be an argument to this function.  Any other statements
  247 are calculations (done in perl) which will not directly appear in the
  248 output.  Think of this as the "print" function for the .pg language.
  249 It can be used more than once in a file.
  250 
  251 =cut
  252 
  253 sub TEXT {
  254   return "" if $PG_STOP_FLAG;
  255   my @in = @_;
  256   $STRINGforOUTPUT .= join(" ",@in);
  257 }
  258 sub STOP_RENDERING {
  259   $PG_STOP_FLAG=1;
  260   "";
  261 }
  262 sub RESUME_RENDERING {
  263   $PG_STOP_FLAG=0;
  264   "";
  265 }
  266 
  267 =head2 ANS()
  268 
  269   ANS(answer_evaluator1, answer_evaluator2, answer_evaluator3,...)
  270 
  271 Places the answer evaluators in the unlabeled answer_evaluator queue.  They will be paired
  272 with unlabeled answer rules (answer entry blanks) in the order entered.  This is the standard
  273 method for entering answers.
  274 
  275   LABELED_ANS(answer_evaluater_name1, answer_evaluator1, answer_evaluater_name2,answer_evaluator2,...)
  276 
  277 Places the answer evaluators in the labeled answer_evaluator hash.  This allows pairing of
  278 labeled answer evaluators and labeled answer rules which may not have been entered in the same
  279 order.
  280 
  281 =cut
  282 
  283 sub ANS{             # store answer evaluators which have not been explicitly labeled
  284   return "" if $PG_STOP_FLAG;
  285   my @in = @_;
  286   while (@in ) {
  287          warn("<BR><B>Error in ANS:$in[0]</B> -- inputs must be references to
  288                       subroutines<BR>")
  289       unless ref($in[0]);
  290       push(@PG_ANSWERS, shift @in );
  291   }
  292 }
  293 sub LABELED_ANS {  #a better alias for NAMED_ANS
  294   &NAMED_ANS;
  295 }
  296 
  297 sub NAMED_ANS{     # store answer evaluators which have been explicitly labeled (submitted in a hash)
  298   return "" if $PG_STOP_FLAG;
  299   my @in = @_;
  300   while (@in ) {
  301     my $label = shift @in;
  302     $label = eval(q!$main::QUIZ_PREFIX.$label!);
  303     my $ans_eval = shift @in;
  304     TEXT("<BR><B>Error in NAMED_ANS:$in[0]</B>
  305           -- inputs must be references to subroutines<BR>")
  306       unless ref($ans_eval);
  307     $PG_ANSWERS_HASH{$label}= $ans_eval;
  308   }
  309 }
  310 sub RECORD_ANS_NAME {     # this maintains the order in which the answer rules are printed.
  311     return "" if $PG_STOP_FLAG;
  312   my $label = shift;
  313   eval(q!push(@main::PG_ANSWER_ENTRY_ORDER, $label)!);
  314   $label;
  315 }
  316 
  317 sub NEW_ANS_NAME {        # this keeps track of the answers which are entered implicitly,
  318                           # rather than with a specific label
  319         return "" if $PG_STOP_FLAG;
  320     my $number=shift;
  321     my $prefix = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!);
  322     my $label = $prefix.$number;
  323     push(@PG_UNLABELED_ANSWERS,$label);
  324     $label;
  325 }
  326 sub ANS_NUM_TO_NAME {     # This converts a number to an answer label for use in
  327                           # radio button and check box answers. No new answer
  328                           # name is recorded.
  329     my $number=shift;
  330     my $label = eval(q!$main::QUIZ_PREFIX.$main::ANSWER_PREFIX!).$number;
  331     $label;
  332 }
  333 
  334 my $vecnum;
  335 
  336 sub RECORD_FORM_LABEL  {             # this stores form data (such as sticky answers), but does nothing more
  337                                      # 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.
  338   return "" if $PG_STOP_FLAG;
  339   my $label   = shift;             # the label of the input box or textarea
  340     eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!); #put the labels into the hash to be caught later for recording purposes
  341     $label;
  342 }
  343 sub NEW_ANS_ARRAY_NAME {        # this keeps track of the answers which are entered implicitly,
  344                           # rather than with a specific label
  345         return "" if $PG_STOP_FLAG;
  346     my $number=shift;
  347     $vecnum = 0;
  348     my $row = shift;
  349     my $col = shift;
  350 #   my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
  351     my $label = "ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__";
  352     push(@PG_UNLABELED_ANSWERS,$label);
  353     $label;
  354 }
  355 
  356 sub NEW_ANS_ARRAY_NAME_EXTENSION {        # this keeps track of the answers which are entered implicitly,
  357                                           # rather than with a specific label
  358         return "" if $PG_STOP_FLAG;
  359     my $number=shift;
  360     my $row = shift;
  361     my $col = shift;
  362     if( $row == 0 && $col == 0 ){
  363       $vecnum += 1;
  364     }
  365     #FIXME   change made to conform to HTML 4.01 standards.  "Name" attributes can only contain
  366     # alphanumeric characters,   _ : and .
  367     # Also need to make corresponding changes in PGmorematrixmacros.  grep for ArRaY.
  368     #my $label = "ArRaY"."$number"."["."$vecnum".","."$row".","."$col"."]";
  369     my $label = "ArRaY"."$number"."__"."$vecnum".":"."$row".":"."$col"."__";
  370     eval(q!push(@main::KEPT_EXTRA_ANSWERS, $label)!);#put the labels into the hash to be caught later for recording purposes
  371     $label;
  372 }
  373 
  374 
  375 sub get_PG_ANSWERS_HASH {
  376   # update the PG_ANSWWERS_HASH, then report the result.
  377   # This is used in writing sequential problems
  378   # if there is an input, use that as a key into the answer hash
  379   my $key = shift;
  380   my (%pg_answers_hash, @pg_unlabeled_answers);
  381   %pg_answers_hash= %PG_ANSWERS_HASH;
  382   #warn "order ", eval(q!@main::PG_ANSWER_ENTRY_ORDER!);
  383   #warn "pg answers", %PG_ANSWERS_HASH;
  384   #warn "unlabeled", @PG_UNLABELED_ANSWERS;
  385     my $index=0;
  386     foreach my $label (@PG_UNLABELED_ANSWERS) {
  387         if ( defined($PG_ANSWERS[$index]) ) {
  388         $pg_answers_hash{"$label"}= $PG_ANSWERS[$index];
  389       #warn "recording answer label = $label";
  390       } else {
  391         warn "No answer provided by instructor for answer $label";
  392       }
  393       $index++;
  394     }
  395     if ($key) {
  396       return $pg_answers_hash{$key};
  397     } else {
  398       return %pg_answers_hash;
  399     }
  400 }
  401 # ENDDOCUMENT must come at the end of every .pg file.
  402 #   It exports the resulting text of the problem, the text to be used in HTML header material
  403 #   (for javaScript), the list of answer evaluators and any other flags.  It can appear only once and
  404 #   it MUST be the last statement in the problem.
  405 
  406 =head2 ENDDOCUMENT()
  407 
  408 ENDDOCUMENT() must the last executable statement in any problem template.  It can
  409 only appear once.  It returns
  410 an array consisting of
  411 
  412   A reference to a string containing the rendered text of the problem.
  413   A reference to a string containing text to be placed in the header
  414                (for javaScript)
  415   A reference to the array containing the answer evaluators.
  416                (May be changed to a hash soon.)
  417   A reference to an associative array (hash) containing various flags.
  418 
  419   The following flags are set by ENDDOCUMENT:
  420   (1) showPartialCorrectAnswers  -- determines whether students are told which
  421       of their answers in a problem are wrong.
  422   (2) recordSubmittedAnswers  -- determines whether students submitted answers
  423       are saved.
  424   (3) refreshCachedImages  -- determines whether the cached image of the problem
  425       in typeset mode is always refreshed (i.e. setting this to 1 means cached
  426       images are not used).
  427   (4) solutionExits   -- indicates the existence of a solution.
  428   (5) hintExits   -- indicates the existence of a hint.
  429   (6) showHintLimit -- determines the number of attempts after which hint(s) will be shown
  430 
  431   (7) PROBLEM_GRADER_TO_USE -- chooses the problem grader to be used in this order
  432     (a) A problem grader specified by the problem using:
  433         install_problem_grader(\&grader);
  434     (b) One of the standard problem graders defined in PGanswermacros.pl when set to
  435         'std_problem_grader' or 'avg_problem_grader' by the environment variable
  436         $PG_environment{PROBLEM_GRADER_TO_USE}
  437     (c) A subroutine referenced by $PG_environment{PROBLEM_GRADER_TO_USE}
  438     (d) The default &std_problem_grader defined in PGanswermacros.pl
  439 
  440 
  441 =cut
  442 
  443 sub ENDDOCUMENT {
  444 
  445     my $index=0;
  446     foreach my $label (@PG_UNLABELED_ANSWERS) {
  447         if ( defined($PG_ANSWERS[$index]) ) {
  448         $PG_ANSWERS_HASH{"$label"}= $PG_ANSWERS[$index];
  449       #warn "recording answer label = $label";
  450       } else {
  451         warn "No answer provided by instructor for answer $label";
  452       }
  453       $index++;
  454     }
  455 
  456     $STRINGforOUTPUT .="\n";
  457    eval q{  #make sure that "main" points to the current safe compartment by evaluating these lines.
  458     $main::PG_FLAGS{'showPartialCorrectAnswers'} = $main::showPartialCorrectAnswers;
  459     $main::PG_FLAGS{'recordSubmittedAnswers'} = $main::recordSubmittedAnswers;
  460     $main::PG_FLAGS{'refreshCachedImages'} = $main::refreshCachedImages;
  461     $main::PG_FLAGS{'hintExists'} = $main::hintExists;
  462     $main::PG_FLAGS{'showHintLimit'} = $main::showHint;
  463     $main::PG_FLAGS{'solutionExists'} = $main::solutionExists;
  464     $main::PG_FLAGS{ANSWER_ENTRY_ORDER} = \@main::PG_ANSWER_ENTRY_ORDER;
  465     $main::PG_FLAGS{KEPT_EXTRA_ANSWERS} = \@main::KEPT_EXTRA_ANSWERS;##need to keep array labels that don't call "RECORD_ANS_NAME"
  466     $main::PG_FLAGS{ANSWER_PREFIX} = $main::ANSWER_PREFIX;
  467     # install problem grader
  468     if (defined($main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) ) {
  469       # problem grader defined within problem -- no further action needed
  470     } elsif ( defined( $main::envir{PROBLEM_GRADER_TO_USE} ) ) {
  471       if (ref($main::envir{PROBLEM_GRADER_TO_USE}) eq 'CODE' ) {         # user defined grader
  472         $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = $main::envir{PROBLEM_GRADER_TO_USE};
  473       } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'std_problem_grader' ) {
  474         if (defined(&std_problem_grader) ){
  475           $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  476         } # std_problem_grader is the default in any case so don't give a warning.
  477       } elsif ($main::envir{PROBLEM_GRADER_TO_USE} eq 'avg_problem_grader' ) {
  478         if (defined(&avg_problem_grader) ){
  479           $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&avg_problem_grader; # defined in PGanswermacros.pl
  480         }
  481         #else { # avg_problem_grader will be installed by PGtranslator so there is no need for a warning.
  482         # warn "The problem grader 'avg_problem_grader' has not been defined.  Has PGanswermacros.pl been loaded?";
  483         #}
  484       } else {
  485         warn "Error:  $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} is not a known program grader.";
  486       }
  487     } elsif (defined(&std_problem_grader)) {
  488       $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = \&std_problem_grader; # defined in PGanswermacros.pl
  489     } else {
  490       # PGtranslator will install its default problem grader
  491     }
  492 
  493     warn "ERROR: The problem grader is not a subroutine" unless ref( $main::PG_FLAGS{PROBLEM_GRADER_TO_USE}) eq 'CODE'
  494                      or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'std_problem_grader'
  495                      or $main::PG_FLAGS{PROBLEM_GRADER_TO_USE} = 'avg_problem_grader';
  496      # return results
  497     };
  498 
  499     $STRINGforOUTPUT .= '<SCRIPT> jsMath.ProcessBeforeShowing() </SCRIPT>'
  500       if ($main::envir{displayMode} eq 'HTML_jsMath');
  501 
  502     if ($main::envir{displayMode} eq 'HTML_asciimath') {
  503       $STRINGforOUTPUT .= '<SCRIPT> translate() </SCRIPT>';
  504       $STRINGforHEADER_TEXT .=
  505         '<object id="mathplayer" classid="clsid:32F66A20-7614-11D4-BD11-00104BD3F987">' . "\n" .
  506         '</object><?import namespace="mml" implementation="#mathplayer"?>'
  507   unless ($STRINGforHEADER_TEXT =~ m/mathplayer/);
  508     }
  509 
  510   (\$STRINGforOUTPUT, \$STRINGforHEADER_TEXT,\%PG_ANSWERS_HASH,eval(q!\%main::PG_FLAGS!));
  511 }
  512 
  513 
  514 
  515 =head2 INITIALIZE_PG()
  516 
  517 This is executed each C<DOCUMENT()> is called.  For backward compatibility
  518 C<loadMacros> also checks whether the C<macroDirectory> has been defined
  519 and if not, it runs C<INITIALIZE_PG()> and issues a warning.
  520 
  521 =cut
  522 
  523 
  524 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9