[system] / trunk / webwork / system / system_webwork_setup.pl Repository:
ViewVC logotype

View of /trunk/webwork/system/system_webwork_setup.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 224 - (download) (as text) (annotate)
Sat Sep 29 13:01:54 2001 UTC (18 years, 2 months ago) by apizer
File size: 20472 byte(s)
make error_log world writable
make access_log group writable

    1 #!/usr/local/bin/perl
    2 
    3 ################################################################################
    4 # WeBWorK
    5 #
    6 # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester
    7 # All rights reserved
    8 #
    9 # $Id$
   10 ################################################################################
   11 
   12 #################### initialization
   13 
   14 require 5.000;
   15 use Cwd;
   16 use File::Copy;
   17 
   18 # define built-in defaults
   19 my $DEFAULT_PERL_PATH = '/usr/local/bin/perl';
   20 my $DEFAULT_CGI_URL = '/cgi-bin/webwork/system/';
   21 my $DEFAULT_HTML_URL = '/webwork_system_html/';
   22 my $DEFAULT_ADMIN_GROUP = 'wwadmin';
   23 
   24 # define code strings
   25 my $CGI_DEBUG_TAG = 'WeBWorKCGIDebugURL';
   26 my $CGI_NODEBUG_TAG = 'WeBWorKCGINoDebugURL';
   27 my $LIB_INIT_LINE_TAG = 'WeBWorKInitLine';
   28 
   29 # scope and undefine setup variables
   30 $no_prompts              = undef;
   31 $system_setup_mode       = undef;
   32 $mainDir                 = undef;
   33 $perlPath                = undef;
   34 $cgiURL                  = undef;
   35 $htmlURL                 = undef;
   36 $groupName               = undef;
   37 $update_stuff_in_courses = undef;
   38 $chgrp_files_and_dirs    = undef;
   39 $chmod_files_and_dirs    = undef;
   40 $local_preprocessor      = undef;
   41 $local_postprocessor     = undef;
   42 
   43 # read defaults in from defaults file
   44 my $DEFAULTS_FILE;
   45 if($ARGV[0] and $ARGV[0] eq '-d') {
   46   if($ARGV[1]) { $DEFAULTS_FILE = $ARGV[1]; }
   47   else { $DEFAULTS_FILE = ((getpwuid $<)[7]) . '/system_webwork_setup.defaults'; }
   48   if(-e $DEFAULTS_FILE) {
   49     print "Reading defaults file...";
   50     require $DEFAULTS_FILE;
   51     print " done.\n";
   52   }
   53 }
   54 
   55 #################### text strings
   56 
   57 my $INTRO_TEXT = q{
   58 +----------------------+
   59 | System Webwork Setup |
   60 +----------------------+
   61 
   62 This script is used to setup the main WeBWorK system. It will create
   63 initialization files, set groups and permissions for files and directories,
   64 and modify files. A "demo" or "working" version of the system can be setup.
   65 
   66 You will need the following information:
   67 
   68 1) The location of your WeBWorK system directory.
   69    Example: /usr/local/webwork/system/
   70    Example: /var/www/webwork/system/
   71 
   72 2) The path to perl on your system.
   73    Example: /usr/bin/perl
   74    Example: /usr/local/bin/perl
   75 
   76 3) The group containing the users who have the authority to modify the
   77    webwork system files. Who ever runs this script must be a member of
   78    this group. (Note: This is not required for the demo mode.)
   79    Example: wwadmin
   80 
   81 4) The URL to the WeBWorK CGI scripts.
   82    Example: /cgi-bin/webwork/system/ (preferred)
   83 
   84 5) The URL to the static system_html files.
   85    Example: /webwork_system_html/
   86 
   87 };
   88 
   89 my $MODE_TEXT = q{
   90 
   91 You can set up a "working" or a "demo" WeBWorK system.  A "demo" system
   92 should only be used as a sample system, never for a system that will be used
   93 with actual courses with real students.  The main difference between a
   94 "working" version and a "demo" version is that in a "working" version you
   95 will be promped to enter a group (e.g. wwadmin) where as in a "demo"
   96 version, the group will be set yo your own default group (e.g. fac). Anyone
   97 in the group will have permission to modify all webwork files. You can set
   98 up "working" and "demo" courses under either a "working" or a "demo" system,
   99 but normally you would not set up a "working" course under a "demo" system.
  100 
  101 };
  102 
  103 my $MAIN_DIR_TEXT = q{
  104 
  105 The directory containing the WeBWorK system files (as well as this
  106 script) is known as the system directory. In order to modify system
  107 files, I need to know the location of the system directory for this
  108 installation.
  109 
  110 };
  111 
  112 my $PERL_TEXT = q{
  113 
  114 WeBWorK needs to know the path of your perl binary, so that this
  115 information can be used in the headers of cgi scripts. Please make sure
  116 that the version of perl you specify is 5.004 or later.
  117 
  118 };
  119 
  120 my $CGI_URL_TEXT = q{
  121 
  122 In order for generated HTML to be able to invoke CGI scripts, WeBWorK
  123 needs to know the URL which points to the main WeBWorK system cgi
  124 subdirectory. If both static HTML and CGIs reside on the same host
  125 (which is true in most cases), you can omit the http://hostname section
  126 of the URL, but make sure the leading slash is present.
  127 
  128 };
  129 
  130 my $HTML_URL_TEXT = q{
  131 
  132 WeBWorK also needs to know the URL of the main HTML directory, the
  133 system_html subdirectory. If both static HTML and CGIs reside on the
  134 same host (which is true in most cases), you can omit the
  135 http://hostname section of the URL, but make sure the leading slash is
  136 present.
  137 
  138 };
  139 
  140 my $GROUP_TEXT = q{
  141 
  142 WeBWorK needs to know what the admin group is. This group should have been
  143 set up by your system administrator and must contain at least your user ID.
  144 All files and directories created will have this as their group.
  145 
  146 };
  147 
  148 my $COURSE_PERMS_TEXT = q{
  149 
  150 You have the option to set permissions for the courses directory. If this is
  151 an inital setup, you should probably do so. If this is not an initial setup,
  152 the courses directory is already set up, or the courses directory is shared
  153 between WeBWorK installations, your probably shouldn't.
  154 
  155 };
  156 
  157 my $CHGRP_TEXT = q{
  158 
  159 You have to option to set the group for all system files and directories. If
  160 this is an initial setup, you should probably do this. If this is not an
  161 initial setup, or you have customized the way system files should be
  162 grouped, you probably shoudn't.
  163 
  164 };
  165 
  166 my $CHMOD_TEXT = q{
  167 
  168 You have to option to set the permissions for all system files and
  169 directories. If this is an initial setup, you should probably do this. If
  170 this is not an initial setup, or you have customized the permissions for the
  171 system files, you probably shoudn't.
  172 
  173 };
  174 
  175 my $CONFIRM_TEXT = q{
  176 
  177 Now that I have the necessary information, I can begin modifying the WeBWorK
  178 system files.
  179 
  180 };
  181 
  182 my $DONE_TEXT = q{
  183 
  184 The system setup script is done. Please read the above messages
  185 carefully to determine if there have been any errors. If so, correct the
  186 problem (usually a permissions problem) and run this script again.
  187 
  188 };
  189 
  190 
  191 
  192 
  193 
  194 ################################################################################
  195 ########## Ask some questions, perform some logic. #############################
  196 ################################################################################
  197 
  198 
  199 
  200 
  201 
  202 #################### introduction
  203 
  204 my $temp;
  205 
  206 unless($no_prompts) {
  207   page($INTRO_TEXT);
  208   $temp = questionChar("Do you want to continue with setup?", 'y', 'y', 'n');
  209   exit unless $temp eq 'y';
  210 }
  211 print "Okay, here we go...\n";
  212 
  213 #################### working or demo?
  214 
  215 unless(defined $system_setup_mode) {
  216   page($MODE_TEXT);
  217   $temp = questionChar("Shall we set up a working version or a demo version?", 'w', 'w', 'd');
  218   $system_setup_mode = "working" if $temp eq 'w';
  219   $system_setup_mode = "demo" if $temp eq 'd';
  220 }
  221 print "System setup mode is: $system_setup_mode\n";
  222 
  223 #################### main directory
  224 
  225 unless(defined $mainDir) {
  226   page($MAIN_DIR_TEXT);
  227   $mainDir = questionString("Where is the WeBWorK system directory?", cwd());
  228   $mainDir .= '/' unless $mainDir =~ m|/$|;  # ensure trailing slash
  229 }
  230 print "We'll use $mainDir as WeBWorK's system directory.\n";
  231 
  232 #################### perl path
  233 
  234 unless(defined $perlPath) {
  235   page($PERL_TEXT);
  236   $perlPath = questionString("What is the full path to PERL?", $DEFAULT_PERL_PATH);
  237 }
  238 print "Path to PERL binary is: $perlPath\n";
  239 
  240 #################### CGI URL
  241 
  242 unless(defined $cgiURL) {
  243   page($CGI_URL_TEXT);
  244   while (1) {
  245     $cgiURL = questionString("What is the CGI URL?", $DEFAULT_CGI_URL);
  246     if( ($cgiURL =~ m|^/|) or ($cgiURL =~ m|^http://|) ) {
  247       last;
  248     } else {
  249       $temp = questionChar("That doesn't look like a valid URL. Would you like to use it anyway?", 'n', 'y', 'n');
  250       last if $temp eq 'y';
  251     }
  252   }
  253   $cgiURL .= "/" unless $cgiURL =~ m"/$"; # ensure trailing slash
  254 }
  255 print "CGI URL is: $cgiURL\n";
  256 
  257 #################### HTML URL
  258 
  259 unless(defined $htmlURL) {
  260   page($HTML_URL_TEXT);
  261   while (1) {
  262     $htmlURL = questionString("What is the HTML URL?", $DEFAULT_HTML_URL);
  263     if( ($htmlURL =~ m|^/|) or ($htmlURL =~ m|^http://|) ) {
  264       last;
  265     } else {
  266       $temp = questionChar("That doesn't look like a valid URL. Would you like to use it anyway?", 'n', 'y', 'n');
  267       last if $temp eq 'y';
  268     }
  269   }
  270   $htmlURL .= "/" unless $htmlURL =~ m"/$" ;
  271 }
  272 print "HTML URL is: $htmlURL\n";
  273 
  274 #################### admin group
  275 
  276 unless(defined $groupName) {
  277   my ($userName, $userGID) = (getpwuid $<)[0,3];
  278   my $userGroupName = (getgrgid $userGID)[0];
  279 
  280   if ($system_setup_mode eq 'demo')  {
  281     # in demo mode, the group is set to the user's primary group
  282     $groupName = $userGroupName;
  283   } else {
  284     # in working mode, we get to chose
  285     page($GROUP_TEXT);
  286     my $validGroup = 0;
  287     while(1) {
  288       $groupName = questionString("What is the admin group name?", $DEFAULT_ADMIN_GROUP);
  289       my @members = split / /, (getgrnam $groupName)[3];
  290       if($groupName eq $userGroupName) {
  291         print "$groupName is ${userName}'s primary group. Good.\n";
  292       } elsif(grep /$userName/, @members) {
  293         print "$userName is a member of $groupName. Good.\n";
  294         last;
  295       } elsif($< == 0) { # we're root!
  296         print "$userName isn't a member of $groupName, but you're root, so who cares?\n";
  297         last;
  298       } else {
  299         print "That group is not valid. Please make sure the group exists and you are a member.\n";
  300       }
  301     }
  302   }
  303 }
  304 print "Admin group is: $groupName\n";
  305 
  306 #################### chmod courses directory
  307 
  308 unless(defined $update_stuff_in_courses) {
  309   page($COURSE_PERMS_TEXT);
  310   $temp = questionChar("Do you want to set default $system_setup_mode permissions for the courses directory?", 'y', 'y', 'n');
  311   $update_stuff_in_courses = ($temp eq 'y');
  312 }
  313 print "Permissions ", ($update_stuff_in_courses ? "will" : "will not"), " be set for the courses directory.\n";
  314 
  315 
  316 #################### chgrp files/directories
  317 
  318 $system_setup_mode eq "demo" and $chgrp_files_and_dirs = 1;
  319 unless(defined $chgrp_files_and_dirs) {
  320   page($CHGRP_TEXT);
  321   $temp = questionChar("Do you want to set the group for system files and directories?", 'y', 'y', 'n');
  322   $chgrp_files_and_dirs = ($temp eq 'y');
  323 }
  324 print "Group ", ($chgrp_files_and_dirs ? "will" : "will not"), " be set for system files and directories.\n";
  325 
  326 #################### chmod files/directories
  327 
  328 $system_setup_mode eq "demo" and $chmod_files_and_dirs = 1;
  329 unless(defined $chmod_files_and_dirs) {
  330   page($CHMOD_TEXT);
  331   $temp = questionChar("Do you want to set the permissions for system files and directories?", 'y', 'y', 'n');
  332   $chmod_files_and_dirs = ($temp eq 'y');
  333 }
  334 print "Permissions ", ($chmod_files_and_dirs ? "will" : "will not"), " be set for system files and directories.\n";
  335 
  336 #################### make sure we want to actually do this
  337 
  338 unless($no_prompts) {
  339   print $CONFIRM_TEXT;
  340   $temp = questionChar("Do you want to continue with setup?", 'y', 'y', 'n');
  341   exit unless $temp eq 'y';
  342 }
  343 print "\Going to make changes now...\n\n";
  344 
  345 
  346 
  347 
  348 
  349 ################################################################################
  350 ########## Now we start changing things... #####################################
  351 ################################################################################
  352 
  353 
  354 
  355 
  356 
  357 #################### run local preprocessor
  358 
  359 if(defined $local_preprocessor) {
  360   print "Executing local preprocessor...\n";
  361   &$local_preprocessor;
  362   print "Done with local preprocessor.\n";
  363 }
  364 
  365 #################### update #! and use lines
  366 # uses: $mainDir, $perlPath
  367 
  368 print "Fixing #! lines...\n";
  369 
  370 foreach my $dir ("${mainDir}cgi/cgi-scripts", "${mainDir}scripts", "${mainDir}courseScripts") {
  371   foreach my $file (<${dir}/*.pl>) {
  372     fixFile($file);
  373   }
  374 }
  375 
  376 sub fixFile
  377 {
  378   my ($file) = @_;
  379 
  380   # read the file
  381   open FILE, $file || die "Couldn't open $file for reading.";
  382   my @lines = <FILE>;
  383   close FILE || die "Couldn't close $file after reading.";
  384 
  385   # fix perl path
  386   $lines[0] =~ m/^#!(\S*)/;
  387   if($1 ne $perlPath) {
  388     $lines[0] =~ s/^#!\S*/#!$perlPath/;
  389     open FILE, ">$file" || die "Couldn't open $file for writing.";
  390     print FILE @lines;
  391     close FILE || die "Couldn't close $file for writing.";
  392   }
  393 }
  394 
  395 print "done fixing #! and \"use\" lines.\n\n";
  396 
  397 #################### write webworkConfig.pm file
  398 # uses: $mainDir, $cgiURL, $htmlURL
  399 
  400 print "Writing lib/webworkConfig.pm file...\n";
  401 open CONFIG_FILE, ">${mainDir}lib/webworkConfig.pm";
  402 print CONFIG_FILE<<END_OF_CONFIG_FILE;
  403 package Global;
  404 
  405 ################################################################################
  406 # WeBWorK
  407 #
  408 # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester
  409 # All rights reserved
  410 ################################################################################
  411 
  412 # $cgiDebugMode, if enabled, will call the debug wrapper scripts instead of the
  413 # cgi scripts themselves, allowing for header output, etc. In addition to
  414 # setting $cgiDebugMode =1, you will also need to enable debugging in the
  415 # wrapper scripts that you wish to debug, by setting $debug = 1. Wrapper
  416 # scripts are found in the directory referred to by $cgiWebworkURL, which is
  417 # usually webwork/system/cgi.
  418 \$cgiDebugMode = 0;
  419 
  420 \$mainDirectory = "$mainDir";
  421 \$htmlWebworkURL = "$htmlURL";
  422 \$cgiWebworkURL = "$cgiURL";
  423 \$cgiWebworkURL .= "cgi-scripts/" unless \$cgiDebugMode;
  424 
  425 1;
  426 END_OF_CONFIG_FILE
  427 close CONFIG_FILE;
  428 print "Done writing lib/webworkConfig.pm file.\n\n";
  429 
  430 #################### write webworkInit.pm files
  431 # uses: $mainDir
  432 
  433 print "Writing webworkInit.pm files...\n";
  434 foreach my $dir ('cgi/', 'cgi/cgi-scripts/', 'scripts/', 'courseScripts/') {
  435   open INIT_FILE, ">$mainDir${dir}webworkInit.pm";
  436   print INIT_FILE<<END_OF_INIT_FILE;
  437 ################################################################################
  438 # WeBWorK
  439 #
  440 # Copyright (c) 1995-2001 WeBWorK Team, University of Rochester
  441 # All rights reserved
  442 ################################################################################
  443 
  444 use lib '${mainDir}lib/';
  445 
  446 1;
  447 END_OF_INIT_FILE
  448   close INIT_FILE;
  449 }
  450 print "Done writing webworkInit.pm files.\n\n";
  451 
  452 #################### chgrp system stuff
  453 # uses: $chgrp_files_and_dirs, $groupName
  454 
  455 if($chgrp_files_and_dirs) {
  456   print "Setting group on system files and directories...\n";
  457   system "chgrp -R $groupName $mainDir";
  458   system "chgrp -R $groupName $mainDir/../system_html";
  459   print "Done setting group.\n\n";
  460 }
  461 
  462 #################### chmod system stuff
  463 # uses: $chmod_files_and_dirs
  464 
  465 if($chmod_files_and_dirs) {
  466   print "Setting permissions on system files and directories for $system_setup_mode mode...\n";
  467   if ($system_setup_mode eq "demo") {
  468     # get some general permissions for files and directories
  469     system "find $mainDir $mainDir/../system_html -type d -print0 | xargs -0 chmod 0755";
  470     system "find $mainDir $mainDir/../system_html -type f -print0 | xargs -0 chmod 0644";
  471     # add executable privs to scripts
  472     system "find ${mainDir}cgi ${mainDir}scripts -type f -print0 | xargs -0 chmod 0755";
  473   } else {
  474     # get some general permissions for files and directories
  475     system "find $mainDir $mainDir/../system_html -type d -print0 | xargs -0 chmod 0775";
  476     system "find $mainDir $mainDir/../system_html -type f -print0 | xargs -0 chmod 0664";
  477     # add executable privs to scripts
  478     system "find ${mainDir}cgi ${mainDir}scripts -type f -print0 | xargs -0 chmod 0775";
  479   }
  480   # make the error_log file world writable
  481   system "find $mainDir/logs/error_log  -print0 | xargs -0 chmod 0666";
  482   # make the access_log file group writable
  483   system "find $mainDir/logs/access_log  -print0 | xargs -0 chmod 0664";
  484 
  485   print "done setting permissions.\n\n";
  486 }
  487 
  488 #################### update couses stuff
  489 # uses: $update_stuff_in_courses
  490 
  491 if($update_stuff_in_courses) {
  492   print "Setting permissions for ../courses directory...\n";
  493   if ($system_setup_mode eq "demo") {
  494     chmod(0755, "$mainDir/../courses") or warn "Warning: I can't set permissions for ../courses directory. It's possible that the directory doesn't exist or you don't have permission to change it.\n";
  495   } else {
  496     chmod(0775, "$mainDir/../courses") or warn "Warning: I can't set permissions for ../courses directory. It's possible that the directory doesn't exist or you don't have permission to change it.\n";
  497   }
  498   print "done permissions.\n\n";
  499 }
  500 
  501 #################### run local postprocessor
  502 
  503 if(defined $local_postprocessor) {
  504   print "Executing local postprocessor...\n";
  505   &$local_postprocessor;
  506   print "Done with local postprocessor.\n";
  507 }
  508 
  509 #################### finish up
  510 
  511 page($DONE_TEXT);
  512 
  513 ################################################################################
  514 
  515 sub page
  516 {
  517   my @string_lines = split /^/, shift; #/
  518   # not really optimal, but we're going to assume a constant screen height.
  519   my $SCREEN_HEIGHT = 20;
  520   while(@string_lines) {
  521     print join "", @string_lines[0..($SCREEN_HEIGHT>scalar @string_lines ? (scalar @string_lines)-1 : $SCREEN_HEIGHT-1)];
  522     if(scalar @string_lines >= $SCREEN_HEIGHT) {
  523       print "\n[Press ENTER to continues...]";
  524       <STDIN>;
  525       print "\n";
  526     }
  527       @string_lines = @string_lines[$SCREEN_HEIGHT..$#string_lines];
  528   }
  529 }
  530 
  531 sub questionChar
  532 {
  533   my ($question, $default, @valid) = @_;
  534   my $answer;
  535   do {
  536     print $question, " ";
  537     foreach (@valid) {
  538       $_ eq $default and print "[";
  539       print $_;
  540       $_ eq $default and print "]";
  541     }
  542     print " ";
  543     $answer = <STDIN>;
  544     $answer =~ s/^\s*//;
  545     $answer = substr $answer, 0, 1;
  546     $answer = lc $answer;
  547     $answer or $answer = $default;
  548   } while (not grep(/$answer/, @valid));
  549   return $answer;
  550 }
  551 
  552 sub questionString
  553 {
  554   my ($question, $default, $emptyOK) = @_;
  555   my $answer;
  556   print $question, " [", $default, "] ";
  557   $answer = <STDIN>;
  558   chomp $answer;
  559   $answer =~ s/^\s*//;
  560   $answer or $answer = $default;
  561   return $answer;
  562 }
  563 
  564 __END__
  565 
  566 =head1 NAME
  567 
  568 system_webwork_setup.pl - set up the WeBWorK system
  569 
  570 =head1 SYNOPSIS
  571 
  572 system_webwork_setup.pl [B<-d> [defaults-file]]
  573 
  574 =head1 DESCRIPTION
  575 
  576 B<system_webwork_setup.pl> gathers the information necessary for configuration of the WeBWorK system. It then edits several WeBWorK system files, and creates F<webworkInit.pm> modules and the F<webworkConfig.pm> module based on the information gathered. It can optionally read defaults from a file specified on the command line or from the file F<$HOME/system_webwork_setup.defaults>.
  577 
  578 =head1 OPTIONS
  579 
  580 =over 4
  581 
  582 =item B<-d>
  583 
  584 enables defaults-file processing. If no defaults-file is specified, the file F<$HOME/system_webwork_setup.defaults> will be used.
  585 
  586 =head1 DEFAULTS
  587 
  588 The F<system_webwork_setup.defaults> file is intended to be used in a situation where B<system_webwork_setup.pl> must be executed frequently, such as in the case of use with CVS, in which the it must be executed after a checkout and some updates. The defaults file is a perl script that will be require'd by B<system_webwork_setup.pl>. It can set any of the following variables in the usual way:
  589 
  590 =over 4
  591 
  592 =item $no_prompts
  593 
  594 Refrain from prompting at the beginning of the script and before making changes. Also supresses the introductory text.
  595 
  596 =item $system_setup_mode
  597 
  598 Can be set to "working" or "demo". This affects how system file permissions and group ownership are set. In "working" mode, system files are group owned by a webwork admin group (see I<$groupName>) and group writeable while in "demo" mode files are group owned by the current user's default group and are not group writeable.
  599 
  600 =item $mainDir
  601 
  602 Specify WeBWorK's main directory, which should contain the directories cgi/ scripts/ courseScripts/ and lib/.
  603 
  604 =item $perlPath
  605 
  606 Specify the path to the perl interpreter which should be used. This is used to set the shebang line in cgi-scripts and scripts.
  607 
  608 =item $cgiURL
  609 
  610 Specify the externally visible URL to the CGI directory (typically cgi/cgi-scripts/). This will be used when scripts call other scripts.
  611 
  612 =item $htmlURL
  613 
  614 Specify the externally visible URL to the HTML directory (typically system_html/). This will be used when scripts refer to static graphics and text.
  615 
  616 =item $groupName
  617 
  618 When in "working" mode, I<$groupName> is the name of the WeBWorK admin group, members of which should have write access to the system files. (The web server should not be in this group!)
  619 
  620 =item $update_stuff_in_courses
  621 
  622 If true, B<system_webwork_setup.pl> will set permissions in the courses directory and prepare the B<course_webwork_setup.pl> script for execution.
  623 
  624 =item $chgrp_files_and_dirs, $chmod_files_and_dirs
  625 
  626 If true, the group and/or permissions on system files will be set according to I<$system_setup_mode>.
  627 
  628 =item $local_preprocessor, $local_postprocessor
  629 
  630 If set, these variables will be called as subroutine references. I<$local_preprocessor> is called before any changes take place, while I<$local_postprocessor> is called after all changes have taken place.
  631 
  632 =back
  633 
  634 =head1 FILES
  635 
  636 $HOME/system_webwork_setup.defaults
  637 
  638 =head1 AUTHOR
  639 
  640 Samuel Hathaway <sh002i@math.rochester.edu>

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9