[system] / trunk / webwork / system / cgi / cgi-scripts / processProblem8.pl Repository:
ViewVC logotype

View of /trunk/webwork/system/cgi/cgi-scripts/processProblem8.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1527 - (download) (as text) (annotate)
Thu Sep 25 01:28:23 2003 UTC (9 years, 7 months ago) by sh002i
File size: 68146 byte(s)
using new WeBWorK::PG::ImageGenerator

    1 #!/usr/local/bin/webwork-perl
    2 
    3 # This file is processProblem8.pl
    4 # This is a special version of processProblem.pl
    5 # made to be used as an editor
    6 
    7 # It is called from a form with inputs
    8 # 'user',
    9 # 'key'
   10 # 'course'
   11 # 'probSetKey' and
   12 # 'probNum'
   13 # and in addition
   14 # 'Mode'   (for either TeX mode or HTML mode or Latex2HTML mode)
   15 # 'show_old_answers'  (whether or not student's old answers should be filled in)
   16 # 'ShowAns'  (asks for answer to be shown -- only available for instructors)
   17 # 'answer$i'  (the answers -- if any --provided to the questions)
   18 # 'showEdit'  (checks if the ShowEditor button should be shown and clicked)
   19 # 'showSol'   (checks if the solution button ishould be shown and clicked)
   20 # as well as
   21 # 'source' when an edited source is provided by a web based editor
   22 # 'seed'   when a new seed is provided by a web based editor
   23 # 'readSourceFromHTMLQ'
   24 # 'action' which can be 'Save updated version' or 'Read problem from disk' or
   25 #    'Submit Answers' or 'Preview Answers' or 'Preview Again'
   26 # 'probFileName'
   27 # 'languageType'
   28 
   29 use strict;
   30 use lib '.'; use webworkInit; # WeBWorKInitLine
   31 
   32 use CGI qw(:standard);
   33 use Net::SMTP;
   34 use Global;
   35 use Auth;
   36 use Safe;
   37 use MIME::Base64 qw( encode_base64 decode_base64) ;
   38 use PGtranslator;
   39 use WeBWorK::PG::ImageGenerator;
   40 BEGIN {
   41   # set to 1 to enable timing_log
   42   # (contains debugging info about time taken by scripts to run)
   43   $main::logTimingData = 1;
   44 
   45   # begin Timing code
   46   if( $main::logTimingData == 1 ) {
   47     use Benchmark;
   48     $main::beginTime = new Benchmark;
   49   }
   50   # end Timing code
   51 
   52   $main::TIME_OUT_CONSTANT = 60;                   # one minute wait for on screen problems
   53   $SIG{'TERM'} = sub {die '[',scalar(localtime),"] Caught a SIGTERM, Error: $!   stopped at $0\n";};
   54   $SIG{'PIPE'} = sub {$main::SIGPIPE = 1, die '[',scalar(localtime),"] Caught a SIGPIPE, Error: $!   stopped at $0\n";  };
   55   $SIG{ALRM} = sub { $main::SIG_TIME_OUT = 1; exit(0) };
   56 
   57 # ## ATTENTION:  The handlers PG_floating_point_exception_handler and PG_warnings_handler
   58 # ## have to be installed after CGI::Carp is called since it also
   59 # ## modifes the die and warn labels. Finding the right warning mechanism using these two
   60 # ## methods bears further investigation
   61 # ## They are defined in Global.pm
   62    $SIG{'FPE'}  = \&Global::PG_floating_point_exception_handler;
   63    $SIG{__WARN__}=\&Global::PG_warnings_handler;
   64 
   65    alarm($main::TIME_OUT_CONSTANT);
   66 
   67 };
   68 
   69 
   70 
   71 use vars qw ( $questionNumber $STRINGforOUTPUT $languageMode  $ansCount $openDate $cgiURL
   72   $studentName $pinNumber $submittedAnswers $setNumber $answerDate $dueDate $studentLogin
   73   $problemValue $safeCompartment $psvnNumber $fileName
   74   $probNum $sectionName  $sectionNumber $recitationName $recitationNumber $sessionKey
   75   $courseName $modules_to_evaluate $extra_packages_to_be_loaded
   76   );
   77 
   78 eval {
   79 
   80 # This hardwires access to these modules/objects.
   81 
   82 
   83 ################################################
   84 
   85 #switched to object-oriented interface with CGI
   86 #DME 6/15/2000
   87 my $cgi = new CGI;
   88 
   89 if( $CGI::VERSION < 2.5 ) {
   90   die "This version of WeBWorK requires at least version 2.50 of the CGI.pm library";
   91 }
   92 my %inputs = $cgi -> Vars();
   93 
   94 
   95 # get information from CGI inputs  (see also below for additional information)
   96   my $Course    = $inputs{'course'};
   97   my $User    = $inputs{'user'};
   98   # define these for the timingLogInfo
   99   $main::Course   = $Course;
  100   $main::User   = $User;
  101   $main::Action     = $inputs{'action'};
  102 
  103 
  104   my $Session_key     = $inputs{'key'};
  105   my $randpsvn      = 22222; #int rand(1111,9999);
  106   my $psvn        = $inputs{'probSetKey'};  #psvn stands for Problem Set Version Number
  107   my $probNum       = 1;
  108      $probNum       = $inputs{'probNum'} if defined($inputs{'probNum'});
  109   my $nextProbNum     = $probNum +1 if defined($probNum);
  110   my $previousProbNum   = $probNum -1 if defined($probNum);
  111   my $mode        = "HTML";
  112        $mode        = $inputs{'Mode'} if defined( $inputs{'Mode'} );
  113        $main::display_mode  = $mode;  # this is only used for the timing messages.
  114     my $showEdit      = $inputs{'showEdit'};
  115     my $show_old_answers  = 0;
  116      $show_old_answers  = $inputs{'show_old_answers'} if defined($inputs{'show_old_answers'});
  117 
  118 # verify that information has been received
  119   unless($Course && $User && $Session_key && $psvn) {
  120       my $error_msg = $cgi -> remote_host() . '   ' .
  121         $cgi -> user_agent() . '   ' . $cgi -> query_string();
  122         &wwerror("$0, missing data",
  123           "The script did not receive the proper input data.
  124           Course is $Course, user is $User, session key is $Session_key, psvn is $psvn",'','',$error_msg
  125     );
  126   }
  127 
  128 
  129 # establish environment for this script
  130   &Global::getCourseEnvironment($Course);
  131   my $macroDirectory      = getCourseMacroDirectory();
  132   my $databaseDirectory     = getCourseDatabaseDirectory();
  133   my $htmlDirectory         = getCourseHtmlDirectory();
  134   my $htmlURL               = getCourseHtmlURL();
  135   my $scriptDirectory       = getWebworkScriptDirectory();
  136   my $templateDirectory     = getCourseTemplateDirectory();
  137     my $courseScriptsDirectory  = getCourseScriptsDirectory();
  138 
  139 
  140 
  141     require "${courseScriptsDirectory}$Global::displayMacros_pl";
  142   require "${scriptDirectory}$Global::DBglue_pl";
  143   require "${scriptDirectory}$Global::classlist_DBglue_pl";
  144   require "${scriptDirectory}$Global::HTMLglue_pl";
  145   require "${scriptDirectory}$Global::FILE_pl";
  146 
  147   my $permissionsFile = &Global::getCoursePermissionsFile($Course);
  148   my $permissions   = &get_permissions($User,$permissionsFile);
  149   my $keyFile     = &Global::getCourseKeyFile($Course);
  150 
  151 ####################################################################
  152 # load the modules to be used in PGtranslator
  153   require "${courseScriptsDirectory}PG_module_list.pl" or
  154     wwerror($0, "Can't read ${courseScriptsDirectory}PG_module_list.pl");
  155 ####################################################################
  156 
  157 # log access
  158   &Global::log_info('', $cgi -> query_string);
  159 
  160 unless ($User eq "practice666" ) {
  161   #verify session key
  162     &verify_key($User, $Session_key, "$keyFile", $Course, \%inputs);
  163 }
  164 
  165 
  166 ##right now $probNum cannot possibly be "", because its default is 1
  167 ##is that how it should be?
  168 ###Should problemBank2 be substituted by some Global variable???###
  169   if($probNum eq "" && ($Course ne "problemBank2") )
  170     {
  171     &selectionError;
  172     die "Content-type: text/html\n\n ERROR: in $Global::processProblem_CGI near &selectionError";
  173     }
  174 
  175 
  176 # get the rest of the information from the CGI script
  177     # get language type
  178     my $displayMode = defined($inputs{'languageType'}) ?$inputs{'languageType'}:'pg';
  179 
  180     # get answers
  181 
  182     # Decide whether answers have been submitted.
  183     my $answers_submitted =0;
  184     $answers_submitted = 1 if defined($inputs{answer_form_submitted}) and 1 == $inputs{answer_form_submitted};
  185     $answers_submitted = 0 if defined($inputs{'action'}) and
  186       ( $inputs{'action'} =~ /Paste Answer/ );
  187 
  188     # Decide whether preview_mode has been selected
  189     my $preview_mode =0;
  190     $preview_mode = 1 if defined($inputs{'action'}) and
  191       (( $inputs{'action'} =~ /Preview Answer/ ) or ( $inputs{'action'} =~ /Preview Again/ ));
  192 
  193 
  194     my $answersRequestedQ = 0;
  195   $answersRequestedQ=  $inputs{'ShowAns'} if defined($inputs{'ShowAns'});
  196 
  197   my $solutionsRequestedQ= 0;
  198     $solutionsRequestedQ= $inputs{'ShowSol'} if defined($inputs{'ShowSol'});
  199 
  200   my $hintsRequestedQ= 0;
  201     $hintsRequestedQ= $inputs{'ShowHint'} if defined($inputs{'ShowHint'});
  202 
  203     my $doNotRecordAnsRequestedQ= 0;
  204     $doNotRecordAnsRequestedQ= $inputs{'doNotRecordAns'} if defined($inputs{'doNotRecordAns'});
  205 
  206 
  207 #
  208 # # cache information about the problem set (from the webwork-database)
  209 # and begin constructing the environment for constructing and displaying the problem
  210   &attachProbSetRecord($psvn);
  211   &attachCLRecord(&getStudentLogin($psvn));
  212 
  213 
  214 # Get information from database
  215   my  ($currentTime,$odts,$ddts,$adts);
  216   $currentTime  = time;
  217   $odts     = &getOpenDate($psvn);
  218   $ddts     = &getDueDate($psvn);
  219   $adts     = &getAnswerDate($psvn);
  220 
  221 
  222   my  ($setNumber,$numberOfProblems);
  223   $setNumber      = &getSetNumber($psvn);
  224   $numberOfProblems     = &getAllProblemsForProbSetRecord($psvn);
  225   my $setNumber_display = $setNumber;
  226   $setNumber_display =~ s/_/ /g;
  227 
  228 
  229 # If answers have not been submitted and previous answers have been saved, patch them in
  230 # unless $show_old_answers = 0
  231 
  232   unless ($answers_submitted or !$show_old_answers) {
  233     my $student_answers = getProblemStudentAnswer($probNum,$psvn);
  234     if (defined $student_answers) {
  235       my $rh_answer_hash =  decode_submitted_answers($student_answers);
  236       my %answer_hash = %$rh_answer_hash;
  237       my ($label, $value);
  238       foreach $label (keys %answer_hash) {$inputs{$label} = $answer_hash{$label};}
  239     }
  240   }
  241 
  242 
  243 # Determine language from the file extension(e.g.  file.pg  or file.pz)
  244     $displayMode  = &getProblemFileName($probNum,$psvn);
  245   $displayMode   = $inputs{'probFileName'} if defined($inputs{'probFileName'});
  246 
  247   $displayMode  =~ s/^.*\.([^\.]*)$/$1/;
  248 
  249 
  250 # get problem name
  251   my $probFileName      =  &getProblemFileName($probNum,$psvn);
  252      $probFileName  =  $inputs{'probFileName'} if defined($inputs{'probFileName'});
  253 
  254 # determine time status.
  255 
  256 # check that the psvn corresponds to the user and that it is after the open
  257 # date.  This should only fail if someone is trying to break into WeBWorK.
  258 
  259 
  260     if ( ( ( $User ne &getStudentLogin($psvn)) ||($currentTime < $odts) )
  261             and ($permissions != $Global::instructor_permissions)
  262                 and   ($permissions != $Global::TA_permissions)
  263         )   {
  264     &hackerError;
  265     exit;
  266   }
  267 
  268 
  269 
  270 ## check to see if it is after due + answer date, if so, put note by
  271 ## submit answer button (below)
  272   my $dueDateNote = "";
  273   my $answerNote  = "";
  274 
  275   if($currentTime>$ddts)
  276     {$dueDateNote=" <EM>Note: it is after the due date.</EM>\n";}
  277   if($currentTime>$adts)
  278     {$answerNote= " <EM>Answers available.</EM>\n";}
  279 
  280 # determine display defaults
  281   my ($displayCorrectAnswersQ,$displayShowAnswerLineQ);
  282 
  283   $displayShowAnswerLineQ = ($permissions == $Global::instructor_permissions) || ($currentTime > $adts) ;
  284   $displayCorrectAnswersQ = 1 if  $answersRequestedQ && ($currentTime > $adts);
  285   $displayCorrectAnswersQ = 1 if $answersRequestedQ && ($permissions == $Global::instructor_permissions);
  286 
  287 
  288   my $displaySolutionsQ = 0;
  289   $displaySolutionsQ  = 1 if  $solutionsRequestedQ && ($currentTime > $adts);
  290   $displaySolutionsQ  = 1 if $solutionsRequestedQ && ($permissions == $Global::instructor_permissions);
  291 
  292   my $displayHintsQ = 0;
  293   $displayHintsQ  = 1 if  $hintsRequestedQ;
  294 
  295 #check if we need to save the updated version of the text
  296 my $problem_has_been_saved = '';
  297 if ( defined($inputs{'action'}) &&
  298      ( $inputs{'action'} eq 'Save updated version' ) &&
  299      ($permissions == $Global::instructor_permissions) &&
  300      defined($inputs{'source'})  ) {
  301     my $temp_source = decodeSource($inputs{'source'});
  302     $temp_source=~ s/\r\n/\n/g;
  303   #$temp_source = $cgi -> unescape( $temp_source );
  304   saveProblem($temp_source, $probFileName);
  305   $problem_has_been_saved = "<H4>Current version of the problem ${templateDirectory}$probFileName has been saved.</H4>
  306     <b>The original version has been appended to the file ${templateDirectory}$probFileName.bak . </b><br />";
  307 
  308   undef($inputs{'source'});   # make sure that we read input from the saved version
  309 }
  310 
  311 #check if we need to save the updated version of the text as a new problem
  312 
  313 if ( defined($inputs{'action'}) &&
  314      ( $inputs{'action'} eq 'Save as' ) &&
  315      ($permissions == $Global::instructor_permissions) &&
  316      defined($inputs{'source'})  ) {
  317     my $temp_source = decodeSource( $inputs{'source'} );
  318 
  319     $temp_source=~ s/\r\n/\n/g;
  320   #$temp_source = $cgi -> unescape( $temp_source );
  321     my $new_file_name = $inputs{'new file name'};
  322   saveNewProblem($temp_source, $new_file_name);
  323   $problem_has_been_saved = "<H4>The file ${templateDirectory}$new_file_name  has been saved.</H4>
  324     <b>The new problem must be added to the set definition file and the set must be rebuilt before the new problem
  325     will be displayed as part of the regular set.</b><br />";
  326 }
  327 
  328 
  329 # get the text source of the problem
  330 
  331 # first determine whether to load the source (and seed) from the calling HTML form or from the disk
  332  my $readSourceFromHTMLQ =0;
  333  $readSourceFromHTMLQ = 1 if (                            # load source from HTML if these conditions are met:
  334                             ($permissions == $Global::instructor_permissions ||   # only instructors can modify the source
  335                              ($User eq "practice666" )) &&              # practice666 can generate source
  336               defined($inputs{'source'})  &&              # there is a source field in the form
  337               defined($inputs{'seed'})    &&              # you need a seed field as well
  338               defined($inputs{'readSourceFromHTMLQ'}) &&
  339               $inputs{'readSourceFromHTMLQ'} == 1           # and the calling form asks that its source be read
  340               );
  341 
  342  # Over ride button forces reading the source from the disk.
  343    if (defined($inputs{'action'}) and $inputs{'action'} eq 'Read problem from disk') {
  344      $readSourceFromHTMLQ = 0;
  345      $inputs{refreshCachedImages} = 1;   # force the Latex2HTML rendering to be redone
  346    }
  347 
  348  # Determine whether to insert the source into the outgoing form.
  349  my $insertSourceIntoFormQ = 0;
  350  $insertSourceIntoFormQ = 1 if (                            # insert the source field into forms only if these conditions are met:
  351               ($permissions == $Global::instructor_permissions) ||    # only instructors can modify the source
  352                  ($User eq "practice666" )                          # practice666 can also
  353               );
  354 
  355 # Now lets get the source and the seed.
  356     my $source;
  357     my $seed;
  358     if ( $readSourceFromHTMLQ  )  {
  359 #   $source = $inputs{'source'};
  360     $source = decodeSource($inputs{'source'});
  361 #     if ( defined($inputs{'source_encoded_using'}) ) {  # the source has been encoded and we need to decode it first
  362 #       if ( $inputs{'source_encoded_using'} eq 'base64_encode' )  {
  363 #         $source = decode_base64($source);
  364 #       }
  365 #       elsif ( $inputs{'source_encoded_using'} eq 'cgi_escape' ) {
  366 #         $source = $cgi -> unescape($source);
  367 #       }
  368 #       elsif ( $inputs{'source_encoded_using'} eq 'none'  )    {
  369 #         # no action needed
  370 #
  371 #       }
  372 #       elsif ( $inputs{'source_encoded_using'} eq 'escaped_returns'  )    {
  373 #         $source =~s/&#010;/\n/g;  warn "uncoding escaped returns";
  374 #         $source =~s/\r\n/\n/g;
  375 #       }
  376 #       else {
  377 #         warn "Did not recognize the source encoding method $inputs{'source_encoded_using'}";
  378 #       }
  379 #      }
  380       ##substitute carriage return with a newline
  381       ##otherwise EndOfText construction does not work
  382       ##browsers always have \r\n at the end of the line
  383         $source=~ s/\r\n/\n/g;
  384 
  385         # get seed from the appropriate place
  386         $seed = $inputs{'seed'};
  387     }
  388   elsif ($probFileName eq '') {
  389     $probFileName = "New File";
  390     $source = '';
  391     $seed ="11111";  # perhaps we can pick a better initial value for the seed.
  392   }
  393   else {
  394     if (-e "${templateDirectory}$probFileName" ) {
  395       #print "|$probFileName|<BR>";
  396       unless (-r "${templateDirectory}$probFileName") {
  397         wwerror($0, "Can't read ${templateDirectory}$probFileName");
  398       }
  399       open(PROB,"<${templateDirectory}$probFileName");
  400       $source = join('',<PROB>);
  401       close(PROB);
  402     }
  403     else {
  404       wwerror($0, "<H4>Error: The problem ${templateDirectory}$probFileName could not be found!</H4>");
  405     }
  406       $seed = &getProblemSeed($probNum, $psvn);
  407   }
  408 
  409 ##################################################
  410 # begin processing problem
  411 ##################################################
  412 
  413 
  414   my %envir=defineProblemEnvir($mode,$probNum,$psvn,$Course);
  415 # my @envir_array = %envir;
  416 # warn "@envir_array";    #DEBUG
  417   ##Need to check what language is used here
  418   #this comes from createDisplayedProblem in displayMacros
  419   my @printlines;
  420 
  421   #this is no longer used     DME 6/15/2000
  422   #my $refSubmittedAnswers=$envir{'refSubmittedAnswers'};
  423 
  424   # require "${courseScriptsDirectory}PG_module_list.pl";
  425   # (Modules are defined by this require statement found near the top of this file, outside the loop.)
  426   my $pt = new PGtranslator;  #pt stands for problem translator;
  427   $pt -> evaluate_modules( @{main::modules_to_evaluate});
  428   $pt -> load_extra_packages(@{main::extra_packages_to_be_loaded});
  429   # The variables in the two preceding lines are  defined in PG_module_list.pl at Indiana.
  430 
  431   my $imgen="";
  432   if($mode eq 'HTML_dpng') {
  433     # for John Jones' WW1 ImageGenerator:
  434     #$imgen = new ImageGenerator;
  435     #$imgen->initialize(\%envir);
  436     # for Sam's WW2 ImageGenerator:
  437     $imgen = WeBWorK::PG::ImageGenerator->new(
  438       tempDir  => $Global::tempDirectory,
  439       latex    => $Global::externalLatexPath,
  440       dvipng   => $Global::externalDvipngPath,
  441       useCache => 1,
  442       cacheDir => "${Global::htmlTempDirectory}equations",
  443       cacheURL => "${Global::tempURL}equations",
  444       cacheDB  => $Global::equationCacheDB,
  445     );
  446   }
  447   $envir{imagegen} = $imgen;
  448 
  449   $pt ->  environment(\%envir);
  450   $pt ->  initialize();
  451   $pt ->  set_mask();
  452   $pt ->  source_string($source);
  453   $pt ->  unrestricted_load("${courseScriptsDirectory}PG.pl");
  454   $pt ->  unrestricted_load("${courseScriptsDirectory}dangerousMacros.pl");
  455   $pt ->  rf_safety_filter( \&safetyFilter);   # install blank safety filter
  456   $pt ->  translate();
  457 
  458 #   Code for logging students's answers to allow inspection of answer history.
  459     logCourseData($User,$setNumber,$probNum,\%inputs,$pt)  if ($answers_submitted);
  460 #     &&
  461 #             ($permissions != $Global::instructor_permissions) and
  462 #             ($permissions != $Global::TA_permissions));
  463 
  464 # $Global::logCourseAnswerData must be 1 in order to activate this subroutine.
  465 #   End student answer logging code.
  466 
  467 
  468   # dereference some flags returned by createPGtext;
  469         if ( defined( $pt ->rh_flags ) ) {
  470           $main::showPartialCorrectAnswers = $pt ->rh_flags->{'showPartialCorrectAnswers'};
  471           $main::recordSubmittedAnswers = $pt ->rh_flags->{'recordSubmittedAnswers'};
  472           $main::refreshCachedImages = $pt ->rh_flags->{'refreshCachedImages'};
  473         }
  474 
  475   if($mode eq 'HTML_dpng') {
  476     my $forceRefresh=0;
  477     if($inputs{'refreshCachedImages'} || $main::refreshCachedImages
  478        || $displaySolutionsQ || $displayHintsQ) {
  479       $forceRefresh=1;
  480     }
  481     # for both John Jones' WW1 ImageGenerator and Sam's WW2 ImageGenerator:
  482     $imgen->render('refresh'=>$forceRefresh); # Can force new images
  483   }
  484   # massage problem text if necessary.
  485   if($mode eq "HTML" || $mode eq 'HTML_tth' || $mode eq 'HTML_dpng' ||
  486      $pt ->rh_flags->{'error_flag'}) {
  487     @printlines=@{ $pt->ra_text() };
  488   }
  489   elsif ($mode eq 'Latex2HTML') {
  490       my %PG_flags = %{ $pt->rh_flags() };
  491       $PG_flags{'refreshCachedImages'} = $inputs{'refreshCachedImages'};
  492       $PG_flags{'refreshCachedImages'} = 1 if $main::refreshCachedImages;
  493       $PG_flags{'refreshCachedImages'} = 1 if $displaySolutionsQ;
  494       $PG_flags{'refreshCachedImages'} = 1 if $displayHintsQ;
  495     @printlines = &createDisplayedProblem($setNumber,$probNum,$psvn,$pt->ra_text(),\%PG_flags );
  496 
  497     @printlines = &l2h_sticky_answers($envir{'inputs_ref'}, \@printlines, $pt->rh_flags() );
  498 
  499 #   @printlines = &l2h_update_keys($envir{'sessionKey'}, \@printlines);
  500     } elsif ($mode eq "TeX") {   #TEMPORARY KLUDGE
  501       @printlines = @{$pt->ra_text() };
  502 
  503   } else {
  504       @printlines="$0: Error:  Mode |$mode| is not HTML, HTML_tth, HTML_dpng or Latex2HTML.";
  505     }
  506 
  507 
  508 
  509 # Determine the problem_state
  510 
  511 
  512 # Determine the recorded score
  513   my $recorded_score = getProblemStatus($probNum, $psvn);
  514 
  515 
  516 # Initialize the variables reporting the answers
  517   my $rh_answer_results = {};
  518   my $rh_problem_result = {};
  519   my $rh_problem_state = {};
  520   my $record_problem_message = '';
  521   my $answer_line_text = '';
  522   my $preview_text = '';
  523   my $expected_answer_count = keys( %{ $pt -> rh_correct_answers() } ); # count the number of correct answers
  524 
  525 # Determine which problem grader to use
  526   #$pt->rf_problem_grader($pt->rf_std_problem_grader);  #this is the default
  527     my $problem_grader_to_use = $pt->rh_flags->{PROBLEM_GRADER_TO_USE};
  528 
  529     if ( defined($problem_grader_to_use) and $problem_grader_to_use   ) {  # if defined and non-empty
  530       if ($problem_grader_to_use eq 'std_problem_grader') {
  531         # Reset problem grader to standard problem grader.
  532         $pt->rf_problem_grader($pt->rf_std_problem_grader);
  533       }
  534     elsif ($problem_grader_to_use eq 'avg_problem_grader') {
  535         # Reset problem grader to average problem grader.
  536             $pt->rf_problem_grader($pt->rf_avg_problem_grader);
  537       }
  538     elsif (ref($problem_grader_to_use) eq 'CODE') {
  539           # Set problem grader to instructor defined problem grader -- use cautiously.
  540         $pt->rf_problem_grader($problem_grader_to_use)
  541       }
  542     else {
  543           warn "Error:  Could not understand problem grader flag $problem_grader_to_use";
  544         #this is the default set by the translator and used if the flag is not understood
  545         #$pt->rf_problem_grader($pt->rf_std_problem_grader);
  546       }
  547 
  548     }
  549   else {#this is the default set by the translator and used if no flag is set.
  550       #$pt->rf_problem_grader($pt->rf_std_problem_grader);   }
  551     }
  552 
  553 # creates and stores a hash of answer results: $rh_answer_results
  554   if  ($answers_submitted == 1) {
  555     $pt -> process_answers(\%inputs);
  556   }
  557   else {
  558     $pt -> process_answers({});   ## pass a ref to an empty hash to process_answers
  559                     ## so that problem graders messages will be
  560                     ## output even when looking at a problem the
  561                     ## first time
  562   }
  563       ####################################################################
  564       # If preview mode has been selected, build the preview page and exit
  565       ####################################################################
  566 
  567     if  (($preview_mode ==1) and ($answers_submitted ==1)) {
  568 
  569     my $ra_answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
  570                         $pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
  571 
  572     $preview_text = preview_answers(
  573                                         $pt->rh_evaluated_answers,
  574                                         $rh_problem_result,
  575                                          {
  576                                           ANSWER_ENTRY_ORDER      => $ra_answer_entry_order,
  577                                           ANSWER_PREFIX               => ($pt->{PG_FLAGS_REF}->{ANSWER_PREFIX}) ? $pt->{PG_FLAGS_REF}->{ANSWER_PREFIX} :'AnSwEr'
  578 
  579                                          }
  580                                         );
  581     build_preview_page();
  582     exit(0);
  583   }
  584 
  585 
  586 
  587       ####################################################################
  588       # set the problem state.
  589       # Record the grade and report the answer results
  590       ####################################################################
  591 
  592 
  593     $pt->rh_problem_state({ recorded_score      => $recorded_score ,
  594                 num_of_correct_ans    => &getProblemNumOfCorrectAns($probNum,$psvn) ,
  595                 num_of_incorrect_ans  => &getProblemNumOfIncorrectAns($probNum,$psvn)
  596               } );
  597 
  598     my $ra_answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
  599                         $pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
  600 
  601     ($rh_problem_result,$rh_problem_state) = $pt->grade_problem( answers_submitted => $answers_submitted,
  602                                                                  ANSWER_ENTRY_ORDER => $ra_answer_entry_order
  603                                                                );       # grades the problem.
  604 # If there was a syntax error, do not report partial correct answers:
  605    $main::showPartialCorrectAnswers = 0 if defined($rh_problem_result->{show_partial_correct_answers})
  606                                            and  $rh_problem_result->{show_partial_correct_answers} == 0;
  607 
  608   if  ($answers_submitted == 1) {
  609 
  610     # Store the answers an an encoded form in the database
  611 
  612     my $saved_submitted_answers_string = encode_submitted_answers($ra_answer_entry_order);
  613 
  614 
  615 
  616     # If an answer form has been submitted format answer message,
  617       # record problem status and format the record_problem_message
  618       # check if before due date and number of incorrect attempts is
  619       # below limit (if any). If so, record answer
  620 
  621     $record_problem_message = '';
  622     my $attemptsRemaining =  getProblemMaxNumOfIncorrectAttemps($probNum,$psvn)
  623                            - getProblemNumOfCorrectAns($probNum,$psvn)
  624                            - getProblemNumOfIncorrectAns($probNum,$psvn);
  625 
  626     ## Professors and TA's are allowed to submit answers without results being recorded
  627     my $doNotRecordAnswers = 0;
  628     if (($permissions == $Global::instructor_permissions) or ($permissions == $Global::TA_permissions)) {
  629       $doNotRecordAnswers = 1 if $doNotRecordAnsRequestedQ;
  630     }
  631 
  632       #    Allow some leeway in the accepting of answers. Davide Cervone
  633       if ( (not $doNotRecordAnswers) and ($currentTime<=$ddts+$Global::dueDateLeeway) and
  634           ( ( getProblemMaxNumOfIncorrectAttemps($probNum,$psvn) < 0 ) or ( $attemptsRemaining >= 1 )) ) {
  635       &save_problem_state($saved_submitted_answers_string,$rh_problem_state,$probNum,$inputs{'user'},$psvn);
  636     }
  637     else {
  638       if ($doNotRecordAnswers){
  639         $record_problem_message = "<STRONG>Note: Answer not recorded.</STRONG><br />";
  640       }
  641       elsif ($currentTime>$ddts+$Global::dueDateLeeway){
  642         $record_problem_message = "<STRONG>Note: Answer not recorded - it is after the due date.</STRONG><br />";
  643       }
  644       else {
  645         $record_problem_message = "<STRONG>Note: Answer not recorded - You have already attempted this problem the maximum allowed number of times.</STRONG><br />";
  646       }
  647     }
  648       ####################################################################
  649       #  Format the answer section of the displayed problem
  650       ####################################################################
  651     my $ra_answer_entry_order = ( defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}) ) ?
  652                         $pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ;
  653 
  654     $answer_line_text = display_answers(
  655                                         $pt->rh_evaluated_answers,
  656                                         $rh_problem_result,
  657                                          {  displayCorrectAnswersQ    => $displayCorrectAnswersQ,
  658                                           showPartialCorrectAnswers   => $main::showPartialCorrectAnswers,
  659                                           ANSWER_ENTRY_ORDER      => $ra_answer_entry_order,
  660                                           ANSWER_PREFIX               => ($pt->{PG_FLAGS_REF}->{ANSWER_PREFIX}) ? $pt->{PG_FLAGS_REF}->{ANSWER_PREFIX} :'AnSwEr'
  661                                          }
  662                                         );
  663 
  664 
  665 
  666 
  667 
  668 }
  669 
  670 
  671       ####################################################################
  672       ###         format problem status message     ###
  673       ####################################################################
  674 my $status = getProblemStatus($probNum,$psvn);
  675 my $attempted = getProblemAttempted($probNum,$psvn);
  676 
  677 my $problemStatusMessage = '';
  678 if ( !$attempted) {
  679   $problemStatusMessage   = "Our records show problem $probNum of set $setNumber_display has not been attempted.";  # default value
  680 }
  681 elsif ($status >= 0 and $status <=1)  {
  682     my $percentCorr = int(100*$status+.5);
  683     my $problemValue = &getProblemValue($probNum,$psvn);
  684     my $score = round_score($status*$problemValue);
  685     my $pts = 'points';
  686     if ($score == 1) {$pts = 'point';}
  687   $problemStatusMessage     = "Our records show problem $probNum of set $setNumber_display has a score of ${percentCorr}\%  ($score $pts).";
  688 }
  689 else {
  690   $problemStatusMessage   = "Our records show problem $probNum of set $setNumber_display has an unknown status.";
  691 }
  692 ########## end format problem status message #######
  693 
  694 ##########################################################
  695 ###### format messages about time remaining. Contributed by Davide Cervone.
  696 ##########################################################
  697 
  698 my $currentTimeMessage = '';
  699 if (($Global::showRemainingTime) and (($ddts-$currentTime) < $Global::startShowingRemainingTime)) {
  700   my ($ctime) = formatDateAndTime($currentTime);
  701   my ($rtime) = formatTimeRemaining($ddts-$currentTime);
  702   $currentTimeMessage = "You have $rtime remaining to complete this problem (reload page to update times).";
  703 }
  704 
  705 sub formatTimeRemaining {
  706   my ($seconds) = @_;
  707   return("no time") if ($seconds <= 0);
  708   my ($minutes) = int($seconds/60);
  709   my ($hours) = int($minutes/60);
  710   my ($days) = int($hours/24);
  711   my ($message) = "about";
  712 
  713   if ($days > 1) {$message = "$days days"} elsif ($days == 1) {$message = "1 day"}
  714   else {
  715     if ($hours > 1) {$message = "$hours hours"} elsif ($hours == 1) {$message = "1 hour"}
  716     $minutes -= 60*$hours; $minutes++ if ($seconds >= 30);
  717     if ($minutes > 1) {$message .= " $minutes minutes"} elsif ($minutes == 1) {$message .= " 1 minute"}
  718     if ($hours == 0) {
  719       if ($minutes == 0) {if ($seconds > 1) {$message = "$seconds seconds"} else {$message = "1 second"}}
  720       if ($minutes < 30) {
  721         $message = '<FONT COLOR="#CC0000">'.$message.'</FONT>';
  722         $message =~ s/(.*)About /About$1/;
  723       }
  724     }
  725   }
  726   return $message;
  727 }
  728 
  729 ########## end format time remaining message #######
  730 
  731 ##########################################################
  732 ###### format messages about number of attempts remaining.
  733 ##########################################################
  734   my  $maxNumOfIncorrectAttempts  = &getProblemMaxNumOfIncorrectAttemps($probNum,$psvn);
  735   my  $numOfCorrectAns    = &getProblemNumOfCorrectAns($probNum,$psvn);
  736   my  $numOfIncorrectAns    = &getProblemNumOfIncorrectAns($probNum,$psvn);
  737   my  $numOfAttempts    = $numOfCorrectAns + $numOfIncorrectAns;
  738   my  $maxAttemptNote   = "";
  739   my  $attemptsRemaining = $maxNumOfIncorrectAttempts -$numOfAttempts;
  740 
  741 
  742 #
  743 
  744 
  745 
  746 #################################################
  747 #  begin printing the HTML text     #
  748 #################################################
  749     my $Edited = '';
  750     my $bg_color = undef;
  751     $bg_color = $Global::bg_color if  $Global::WARNINGS   ;
  752   $Edited = "EDITED " if $readSourceFromHTMLQ;
  753   $Edited = "NEW FILE " if (defined($inputs{'action'}) and ($inputs{'action'} eq 'Save as'));
  754   print &processProblem_htmlTOP("${Edited}Problem $probNum",
  755                                   ${ $pt->r_header },
  756                                  $bg_color    # background color
  757                                 );  #see subroutines at the bottom of this file
  758                                     #this allows the use of a small gif for the webwork logo
  759                                     #and takes up less screen real estate.
  760 
  761   #text in case the problem has been saved
  762   print $problem_has_been_saved;
  763 
  764 ################print Navigation Bar ###########
  765 
  766   print &format_navigation_bar($previousProbNum,$nextProbNum,$numberOfProblems);
  767 
  768 ##############print warning about setting the Encoding properly###############
  769      my $browser = $cgi -> user_agent();
  770      # browser contains a string such as: |Mozilla/4.07 (Macintosh; I; PPC, Nav) |
  771      $browser =~ m|Mozilla/([\d.]+)|;
  772      my $version = $1;
  773        print( qq!<FONT COLOR="#ff0000"><p /> <B>WARNING:</B> Versions of Netscape before 4.0 running on a Macintosh computer
  774                will not be able to display all the math symbols correctly in formatted text mode. Square root and integral
  775                signs may disappear entirely. Please use
  776                another mode.
  777                <p>
  778                 When using Netscape 4 or greater on a Macintosh computer, set your fonts by choosing
  779                <br />View --&gt;Encoding--&gt;Western(MacRoman) from the menu.  This will make square root signs
  780                and integral signs display correctly.
  781                </p></FONT>!) if ($mode eq 'HTML_tth' && $browser =~/Macintosh/ && $version < "4");
  782 
  783 ###############begin Answer Section###########
  784 
  785 if ($answers_submitted ==1) {
  786 # print "<br />Problem grader message is:<br /> " , $rh_problem_result->{msg}    if defined($rh_problem_result->{msg});
  787 
  788   print $answer_line_text,
  789           $record_problem_message;
  790 
  791   print(  "<br />Problem grader errors are " . $rh_problem_result->{errors} ) if $rh_problem_result->{errors};
  792 }
  793 
  794     print "\r\n<!-- BEGIN_PG_PROBLEM_FORM -->\r\n";
  795 
  796 ################begin Problem Text ###########
  797   print "\n",$cgi -> startform(-action=>"$Global::processProblem_CGI"),"\n\n";
  798   print "\r\n<!-- BEGIN_PG_PROBLEM_TEXT -->\r\n";
  799   print @printlines;
  800   print "\r\n<!-- END_PG_PROBLEM_TEXT -->\r\n";
  801   print '<p />';
  802 
  803 
  804 ################print Submit button and display check boxes###########
  805 
  806   print '<EM><B>Note:</B>' . $pt->rh_problem_result->{msg} . '</EM><br />' if ($pt->rh_problem_result->{msg});
  807   print "$currentTimeMessage <p />";
  808   my  $s      = '';
  809   if( $expected_answer_count > 1) {
  810     $s = 's'; #makes the Answer button plural (purely cosmetic)
  811   }
  812 
  813 # Decide whether the Do not save answers is visible
  814   if (($User ne &getStudentLogin($psvn)) and
  815     ( ($permissions == $Global::instructor_permissions) or ($permissions == $Global::TA_permissions) ) ) {
  816 
  817     print $cgi -> checkbox(-name=>'doNotRecordAns',
  818             -value=>1,
  819             -label=>"Do Not Record Answer$s",
  820             -checked,
  821             -override => 1), "\n\t";
  822   } else {
  823     print $cgi -> hidden(-name=>'doNotRecordAns',
  824         -value => 0,override => 1), "\n\t";
  825   }
  826 
  827 # Decide whether the showHint line is visible
  828 
  829   if (
  830     defined($pt ->rh_flags->{'hintExists'})
  831     and ($pt ->rh_flags->{'hintExists'} ==1)
  832     and ($numOfAttempts >= $pt ->rh_flags->{'showHintLimit'})
  833   ) {
  834         print $cgi -> checkbox(-name=>'ShowHint',
  835             -value=>1,
  836             -label=>"Show Hint",
  837             -override => 1);
  838   } else {
  839     print $cgi -> hidden(-name=>'ShowHint', -value=>0, -override => 1), "\n\t";
  840   }
  841 
  842 
  843 
  844 # Decide whether the showAnswer line is visible
  845 
  846   if (defined($displayShowAnswerLineQ) and $displayShowAnswerLineQ) {
  847     print $cgi -> checkbox(-name=>'ShowAns',
  848             -value=>1,
  849             -label=>"Show Correct Answer$s",
  850             -override => 1), "\n\t";
  851   } else {
  852     print $cgi -> hidden(-name=>'ShowAns',
  853         -value => 0,-override => 1), "\n\t";
  854   }
  855 
  856 
  857 
  858 # Decide whether the showSolution line is visible
  859 
  860   if (defined($displayShowAnswerLineQ) and $displayShowAnswerLineQ and defined($pt ->rh_flags->{'solutionExists'}) and $pt ->rh_flags->{'solutionExists'} ==1) {
  861       print $cgi -> checkbox(-name=>'ShowSol',
  862             -value=>1,
  863             -label=>"Show Solution$s",
  864             -override => 1);
  865   } else {
  866     print $cgi -> hidden(-name=>'ShowSol',  -value=>0, -override => 1), "\n\t";
  867   }
  868 
  869 
  870 ## check to see if $numOfAttempts is approaching or at the limit
  871 ## $maxNumOfIncorrectAttempts. If so, put note by
  872 ## submit answer button (below)
  873 ##  $maxNumOfIncorrectAttempts = -1 means unlimited attempts
  874   my $plural = '';
  875   $plural = 's'   if $attemptsRemaining > 1;
  876 
  877   if(($maxNumOfIncorrectAttempts >= 0) and ($attemptsRemaining <= 0) and ($currentTime<=$ddts)) {
  878     $maxAttemptNote = " <EM>Note: You have already attempted this problem the
  879                            maximum allowed number of times.</EM>\n";
  880   }
  881   elsif (($maxNumOfIncorrectAttempts >= 0) and
  882          ($attemptsRemaining <= $Global::maxAttemptsWarningLevel) and
  883          ($currentTime<=$ddts)
  884         )  {
  885        $maxAttemptNote = " <B>Note: You are allowed only $attemptsRemaining more
  886                            attempt$plural at this problem.</B>\n";
  887 
  888   }
  889 
  890 ############# print hidden information about problem and set
  891 
  892   print $cgi -> hidden( -name => 'probNum', -value => $probNum ), "\n\t",
  893       $cgi -> hidden( -name => 'probSetKey', -value => $psvn ), "\n\t",
  894       $cgi->hidden( -name=>'show_old_answers', -value=>$show_old_answers), "\n\t",
  895       $cgi -> hidden( -name => 'answer_form_submitted', -value => 1 );   # alerts the problem to show answers.
  896 
  897   my $button_style = 'width: 12em';
  898   #sessionKeyInputs() in scripts/HTMLglue.pl
  899   print &sessionKeyInputs(\%inputs),
  900     "<br />",
  901     qq!$maxAttemptNote $dueDateNote $answerNote!,
  902     "<br />",
  903     $cgi -> submit(  -name => 'action',  -value=>"Submit Answer$s", -style=>$button_style),  # -onClick=>"submitProblem()" # this javaScript call caused problems on some older browsers -- removed temporarily while we find a fix
  904 
  905     "\n\t",
  906     $cgi -> submit(  -name => 'action',  -value=>"Preview Answer$s", -style=>$button_style),"\n\t";
  907     if ($mode ne 'TeX') { #TEMPORARY KLUDGE
  908     my $displayMode_hidden_inputs = displaySelectModeLine_string($mode);
  909     $displayMode_hidden_inputs =~ s/<BR>//g;  # remove returns to get one line display
  910     print "<br />$displayMode_hidden_inputs<br />";
  911   }
  912 
  913 # $source =~ s/([^\r])\n/$1\r\n/g;  # replace any bare \n by \r\n
  914 # $source =~ s/\n/&#010;/g;
  915 #   my $sourceAsHTMLEncodingMethod = 'escaped_returns';  # this makes iCab work properly
  916    my $sourceAsHTMLEncodingMethod = 'base64_encode';
  917    my $sourceAsHTML = encode_base64($source);
  918    if ($readSourceFromHTMLQ ) {   # reading from source is a sticky option.
  919     print $cgi -> hidden(-name  => 'readSourceFromHTMLQ', -value => "1" );
  920     print "<br />\r\n",
  921           $cgi -> hidden(-name  =>  'source_encoded_using',   -value  =>  $sourceAsHTMLEncodingMethod, -override => 1),
  922           "<br />\r\n",
  923           $cgi -> hidden(-name  =>  'source',   -value  =>  $sourceAsHTML, -override => 1),
  924           "<br />\r\n",
  925           $cgi -> hidden(-name  => 'seed',    -value => "$seed" );
  926   }
  927   print "\r\n<!-- BEGIN_PG_READ_FROM_DISK -->\r\n";
  928   if ($readSourceFromHTMLQ ) {
  929     print $cgi -> submit(-name  =>  'action',   -value  => 'Read problem from disk');  # this allows an override about reading from the HTML source
  930 
  931                 # This ensures that we are using the current (possibly changed)
  932                 # seed even if we are resubmitting answers to a question.
  933    }
  934    print $cgi -> endform();
  935    print "\r\n<!-- END_PG_PROBLEM_FORM -->\r\n";
  936 #############################################################
  937 ##  End of main form, containing the problem and answer rules
  938 #############################################################
  939 ##print the form to get the editor in a different window if the
  940 ##person using WeBWorK has professor permissions
  941 
  942 #############################################################
  943 ##  Show editor form
  944 #############################################################
  945 
  946 if ($insertSourceIntoFormQ) {
  947   print "\n\n<!--Source is encoded for more security and to avoid problems with the " .
  948       "conversion from HTML to straight text-->\n";
  949   print "<hr><TABLE ><TR>\n<TD>";
  950   print $cgi -> startform(-action=>"$Global::problemEditor_CGI",
  951     -target=>'editor'),
  952     &sessionKeyInputs(\%inputs),
  953     $cgi -> hidden( -name =>'source_encoded_using',   -value => $sourceAsHTMLEncodingMethod, -override =>1), "\r\n",
  954     $cgi -> hidden( -name =>'source',       -value  =>  $sourceAsHTML, -override =>1), "\r\n",
  955     $cgi -> submit( -name =>'action',       -value  =>  "Show Editor", -style=> $button_style), "\r\n",
  956     $cgi -> hidden( -name =>'probSetKey',     -value  =>  $psvn), "\r\n",
  957     $cgi -> hidden( -name =>'probNum',      -value  =>  $probNum), "\n",
  958     $cgi -> hidden( -name =>'Mode',       -value  =>  $mode, -override =>1), "\r\n",
  959     $cgi -> hidden( -name =>'seed',       -value  =>  $seed, -override =>1), "\r\n",
  960     $cgi -> endform();
  961 
  962   #   Code for logging students's answers to allow inspection of answer history.
  963   if ($Global::logCourseAnswerData) {
  964       print "</TD>\n<TD>";
  965       print $cgi->startform(-action=>"$Global::showPastAnswers_CGI", -target=>'information'),
  966         &sessionKeyInputs(\%inputs),
  967         $cgi->hidden(-name => 'probNum', -value=>$probNum), "\n",
  968         $cgi->hidden(-name => 'setNum',  -value=>$setNumber), "\n",
  969         $cgi->hidden(-name => 'User',    -value=>getStudentLogin($psvn)), "\n",
  970         $cgi->submit(-name => 'action',  -value=>'Show Past Answers', -style=> $button_style), "\n",
  971         $cgi->endform();
  972       print "</TD></TR>\n</TABLE>\n";
  973   }
  974   #   End code for logging students's answers
  975 }
  976 
  977 
  978 
  979 #############################################################
  980 ##  End "Show editor" form
  981 ################################################################
  982   print &htmlBOTTOM($0, \%inputs, 'processProblemHelp.html');
  983 
  984   $main::Course = $Course;
  985   $main::User   = $User;
  986 
  987   exit(0);
  988 
  989 
  990 
  991 
  992 ### DONE ###
  993 ############################################
  994 ## SUBROUTINES specific to processProblem.pl
  995 # this normally loads in macro files -- but for the demo this is done by hand.
  996 
  997 sub save_problem_state {
  998     my ($saved_submitted_answers_string,$rh_problem_state, $num,$user, $psvn)=@_;
  999 
 1000     # define constants
 1001     my  $DELIM = $Global::delim;
 1002     my  $scoreFilePrefix = $Global::scoreFilePrefix;
 1003     my  $dash = $Global::dash;
 1004     my $numericalID = $Global::numericalGroupID;
 1005        $numericalID = $Global::numericalGroupID;
 1006     #
 1007 
 1008     #&attachProbSetRecord($psvn); # (not needed);
 1009     my($setNumber)=&getSetNumber($psvn);
 1010     my ($scoreFileName)="${databaseDirectory}$scoreFilePrefix$setNumber$dash${psvn}.sco";
 1011     unless (-e $scoreFileName) {
 1012         &createFile($scoreFileName, $Global::sco_files_permission, $numericalID);
 1013     }
 1014     open(TEMP_FILE,">>$scoreFileName") || print "Couldn't record answer in $scoreFileName";
 1015     my $time = &formatDateAndTime(time);    # add time stamp
 1016 
 1017     print TEMP_FILE "$num  $DELIM  " . $rh_problem_state->{recorded_score} . " $DELIM " . $rh_problem_state->{num_of_correct_ans} . " $DELIM" . $rh_problem_state->{num_of_incorrect_ans} . " $DELIM $user $DELIM $time\n";
 1018     close(TEMP_FILE);
 1019 
 1020   putProblemStudentAnswer($saved_submitted_answers_string,$num,$psvn) if $main::recordSubmittedAnswers;
 1021 
 1022     &putProblemNumOfCorrectAns($rh_problem_state->{num_of_correct_ans},$num,$psvn) if defined($rh_problem_state->{num_of_correct_ans}) ;
 1023     &putProblemNumOfIncorrectAns($rh_problem_state->{num_of_incorrect_ans},$num,$psvn) if defined($rh_problem_state->{num_of_incorrect_ans});
 1024 
 1025     &putProblemAttempted(1,$num,$psvn);  ## save_problem_state() is run only if the submit button has been
 1026                                          ## hit so that means the problem has been attempted
 1027 
 1028     if ( defined($rh_problem_state->{recorded_score})  ) {
 1029       &putProblemStatus( $rh_problem_state->{recorded_score} ,$num,$psvn);
 1030     } else {
 1031       warn "Error no recorded_score has been calculated for this problem.";
 1032     }
 1033 
 1034     #my %temp1 = getProbSetRecord($psvn);
 1035     #warn "number of correct attempts is pst$num ", $temp1{"pst$num"};
 1036     &detachProbSetRecord($psvn);
 1037 };
 1038 
 1039 
 1040 sub hackerError  { ## prints hacker error message
 1041 
 1042 
 1043     my $msg = "Attempt to hack into WeBWorK \n Remote Host is: ". $cgi -> remote_host()."\n";
 1044     $msg .= $cgi -> query_string();
 1045 #    &Global::log_error('hacker error', $cgi -> query_string);
 1046     &Global::log_error('hacker error', $msg);   ## log attempt
 1047 
 1048     ## notify by email
 1049 
 1050     my $toAdd = $Global::feedbackAddress;
 1051 
 1052     my $emailMsg = "To: $toAdd
 1053 Subject: Attempt to hack into WeBWorK
 1054 
 1055 Here are the details on the attempt to hack into weBWorK:\n
 1056 $msg
 1057 \n";
 1058 
 1059   my $smtp = Net::SMTP->new($Global::smtpServer, Timeout=>20);
 1060   $smtp->mail($Global::webmaster);
 1061   $smtp->recipient($Global::feedbackAddress);
 1062   $smtp->data($msg);
 1063   $smtp->quit;
 1064 
 1065 
 1066 #    my $SENDMAIL = $Global::SENDMAIL;
 1067 #    open (MAIL,"|$SENDMAIL");
 1068 #    print MAIL "$emailMsg";
 1069 #    close (MAIL);
 1070 
 1071     print   &htmlTOP("Hacker Error"),
 1072                         "<H2>Error:Please do not try to hack into WeBWorK!</H2>",
 1073                         $cgi -> startform(-action=>"${Global::welcomeAction_CGI}"),
 1074                         $cgi ->p ,
 1075                         &sessionKeyInputs(\%inputs),
 1076                         $cgi -> hidden(-name=>'local_psvns', -value=>$psvn),
 1077                         $cgi -> hidden(-name=>'action', -value=>'Do_problem_set'),
 1078                         $cgi -> endform(),
 1079                         &htmlBOTTOM($0, \%inputs);
 1080 }
 1081 
 1082 sub selectionError  ## prints error message
 1083   {
 1084   print   &htmlTOP("Error: need to select problem"),
 1085       "<H2>Error: You must select a problem!</H2>",
 1086       $cgi -> startform(-action=>"${Global::welcomeAction_CGI}"),
 1087       &sessionKeyInputs(\%inputs),
 1088                         $cgi -> hidden(-name=>'local_psvns', -value=>$psvn),
 1089                         $cgi -> hidden(-name=>'action', -value=>'Do_problem_set'),
 1090                         $cgi -> submit(-value=>"Return to Problem Set"),
 1091                         $cgi -> endform(),
 1092       &htmlBOTTOM($0, \%inputs);
 1093   }
 1094 
 1095 
 1096 ###################################################
 1097 sub decodeSource {
 1098   my $source = shift;
 1099   warn "Only source embedded in HTML needs to be decoded" unless defined($inputs{'source'});
 1100   if ( defined($inputs{'source_encoded_using'}) ) {  # the source has been encoded and we need to decode it first
 1101     if ( $inputs{'source_encoded_using'} eq 'base64_encode' )  {
 1102       $source = decode_base64($source);
 1103     }
 1104     elsif ( $inputs{'source_encoded_using'} eq 'cgi_escape' ) {
 1105       $source = $cgi -> unescape($source);
 1106     }
 1107     elsif ( $inputs{'source_encoded_using'} eq 'none'  )    {
 1108       # no action needed
 1109     }
 1110     elsif ( $inputs{'source_encoded_using'} eq 'escaped_returns'  )    {
 1111       $source =~s/&#010;/\n/g;  warn "uncoding escaped returns";
 1112       $source =~s/\r\n/\n/g;
 1113     }
 1114     else {
 1115       warn "Did not recognize the source encoding method $inputs{'source_encoded_using'}";
 1116     }
 1117    }
 1118      $source;
 1119 }
 1120 
 1121 
 1122 sub safetyFilter {
 1123 #   my $answer = shift;  # accepts one answer and checks it
 1124 #   $answer = '' unless defined $answer;
 1125 #   my ($errorno, $answerIsCorrectQ);
 1126 #   $answer =~ tr/\000-\037/ /;
 1127 #   #### Return if answer field is empty ########
 1128 #   unless ($answer =~ /\S/) {
 1129 #     $errorno =1; # "No answer was submitted.";
 1130 #
 1131 #     return ($answer,$errorno);
 1132 #     }
 1133 #   ######### replace ^ with **    (for exponentiation)
 1134 #   #   $answer =~ s/\^/**/g;
 1135 #   ######### Return if  forbidden characters are found
 1136 #   unless ($answer =~ /^[a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)\[\]\{\}]+$/ )  {
 1137 #     $answer =~ tr/a-zA-Z0-9_\-\+ \t\/@%\*\.\n^\(\)\[\]\{\}]/#/c;
 1138 #     $errorno = 2; #  "There are forbidden characters in your answer: $submittedAnswer<BR>";
 1139 #
 1140 #     return ($answer,$errorno);
 1141 #     }
 1142 #
 1143   my $answer = shift @_;
 1144   my $errorno = 0;
 1145 
 1146   return($answer, $errorno);
 1147 }
 1148 
 1149 
 1150 
 1151 sub processProblem_htmlTOP {
 1152       my ($title, $header_text, $bg_url) = @_;
 1153 
 1154       my $bg_color = $bg_url || $Global::bg_color;
 1155 
 1156       $header_text = '' unless defined($header_text);
 1157 #       my $out =  header(-type=>'text/html');
 1158 #     $out .= start_html(-'title'=>$title,
 1159 #                     -script=>$header_text,
 1160 #         -background=>$background_url);
 1161     my $test = $cgi -> user_agent();
 1162 #       determine the proper charset
 1163     my $charset_definition;
 1164     my $browser = $cgi -> user_agent();
 1165     # browser contains a string such as: |Mozilla/4.07 (Macintosh; I; PPC, Nav) |
 1166     if ($browser =~/Macintosh/  or $browser =~/Mac_PowerPC/) {  # do we need to know the mode in order to set this properly??
 1167       $charset_definition = q{charset="x-mac-roman";};
 1168     } else {
 1169       $charset_definition =q{};
 1170     }
 1171 
 1172         my $out = <<ENDhtmlTOP;
 1173 content-type: text/html; $charset_definition
 1174 
 1175 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
 1176 <HTML>
 1177 <HEAD>
 1178 <TITLE>$title</TITLE>
 1179 <style>
 1180   .parsehilight { background: yellow }
 1181 </style>
 1182 $header_text
 1183 </HEAD>
 1184 <BODY BGCOLOR="$bg_color"><p />
 1185 ENDhtmlTOP
 1186     $out;
 1187 }
 1188 
 1189 sub preview_answers_htmlTOP {
 1190       my ($title, $header_text, $bg_url) = @_;
 1191 
 1192       my $bg_color = $bg_url || $Global::bg_color;
 1193 
 1194       $header_text = '' unless defined($header_text);
 1195 
 1196         my $out = <<ENDhtmlTOP;
 1197 content-type: text/html;
 1198 
 1199 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
 1200 <HTML>
 1201 <HEAD>
 1202 <TITLE>$title</TITLE>
 1203 <style>
 1204   .parsehilight { background: yellow }
 1205 </style>
 1206 $header_text
 1207 </HEAD>
 1208 <BODY BGCOLOR="$bg_color"><p />
 1209 ENDhtmlTOP
 1210     $out;
 1211 }
 1212 
 1213 
 1214 
 1215 sub format_navigation_bar {
 1216 my ($previousProbNum, $nextProbNum,$numberOfProblems) = @_;
 1217 
 1218 ## first set up the navigation button forms
 1219 
 1220   my $prev_prob_form = '';
 1221   unless($previousProbNum <= 0) {
 1222     $prev_prob_form = join("\n",
 1223       $cgi->startform(-method=>'POST', -action=>"$Global::processProblem_CGI"),
 1224       $cgi->input({-type=>'IMAGE', -src=>"$Global::previousImgUrl", -alt=>'<--Previous Problem'}),
 1225       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1226       $cgi->hidden(-name=>'probNum', -value=>"$previousProbNum", -override=>1),
 1227       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1228       $cgi->hidden(-name=>'show_old_answers', -value=>$show_old_answers),
 1229       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1230       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1231       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1232       $cgi->endform()
 1233     );
 1234   }
 1235 
 1236   my $prob_list_form = join("\n",
 1237     $cgi->startform(-method=>'POST', -action=>"$Global::welcomeAction_CGI"),
 1238       $cgi->input({-type=>'IMAGE', -src=>"$Global::problistImgUrl", -alt=>'Problem List'}),
 1239     $cgi->hidden(-name=>'local_psvns', -value=>"$inputs{probSetKey}"),
 1240       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1241       $cgi->hidden(-name=>'action', -value=>"Do_problem_set",-override=>1),
 1242       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1243       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1244       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1245       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1246       $cgi->endform()
 1247     );
 1248 
 1249 
 1250   my $next_prob_form = '';
 1251   unless($nextProbNum > $numberOfProblems) {
 1252     $next_prob_form = join("\n",
 1253       $cgi->startform(-method=>'POST', -action=>"$Global::processProblem_CGI"),
 1254       $cgi->input({-type=>'IMAGE', -src=>"$Global::nextImgUrl", -alt=>'Next Problem-->'}),
 1255       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1256       $cgi->hidden(-name=>'probNum', -value=>"$nextProbNum", -override=>1),
 1257       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1258       $cgi->hidden(-name=>'show_old_answers', -value=>$show_old_answers),
 1259       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1260       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1261       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1262       $cgi->endform()
 1263     );
 1264   }
 1265 
 1266 ## next set up the inner table
 1267   my $inner_table =
 1268     $cgi->table(
 1269       $cgi->Tr(
 1270         $cgi->td({-align=>'CENTER', -valign=>'MIDDLE'},[$prev_prob_form, $prob_list_form, $next_prob_form])
 1271     )
 1272     );
 1273 
 1274 ## finally set up the main table
 1275   my $navigation_bar =
 1276     $cgi->table({-border=>0,-width=>'100%'},
 1277       $cgi->Tr({-align=>'CENTER', -valign=>'TOP'},
 1278         $cgi->td({-align=>'LEFT', -valign=>'MIDDLE'},$inner_table),
 1279         $cgi->td({-align=>'CENTER', -valign=>'MIDDLE'}),
 1280         $cgi->td({-align=>'RIGHT', -valign=>'TOP', -rowspan=>2},
 1281           $cgi->a({-href=>$Global::webworkDocsURL}, $cgi->img({-src=>$Global::squareWebworkGif,-border=>1,-alt=>'WeBWorK Docs'}))
 1282         )
 1283       ),
 1284       $cgi->Tr(
 1285         $cgi->td({-align=>'LEFT', -valign=>'BOTTOM'}, $cgi->h4($problemStatusMessage))
 1286       )
 1287     );
 1288   return $navigation_bar;
 1289 }
 1290 
 1291 
 1292 sub format_preview_navigation_bar {
 1293   my $curentProbNum = shift;
 1294 
 1295 ## first set up the navigation button forms
 1296 
 1297   my $current_prob_form = join("\n",
 1298     $cgi->startform(-method=>'POST', -action=>"$Global::processProblem_CGI"),
 1299     $cgi->input({-type=>'IMAGE', -src=>"$Global::currentImgUrl", -alt=>'Current Problem'}),
 1300     $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1301     $cgi->hidden(-name=>'probNum', -value=>"$curentProbNum", -override=>1),
 1302     $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1303     $cgi->hidden(-name=>'show_old_answers', -value=>$show_old_answers),
 1304     $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1305     $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1306     $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1307     $cgi->endform()
 1308   );
 1309 
 1310   my $prob_list_form = join("\n",
 1311     $cgi->startform(-method=>'POST', -action=>"$Global::welcomeAction_CGI"),
 1312       $cgi->input({-type=>'IMAGE', -src=>"$Global::problistImgUrl", -alt=>'Problem List'}),
 1313     $cgi->hidden(-name=>'local_psvns', -value=>"$inputs{probSetKey}"),
 1314       $cgi->hidden(-name=>'probSetKey', -value=>"$inputs{probSetKey}"),
 1315       $cgi->hidden(-name=>'action', -value=>"Do_problem_set",-override=>1),
 1316       $cgi->hidden(-name=>'Mode', -value=>"$inputs{Mode}"),
 1317       $cgi->hidden(-name=>'user', -value=>"$inputs{user}"),
 1318       $cgi->hidden(-name=>'key', -value=>"$inputs{key}"),
 1319       $cgi->hidden(-name=>'course', -value=>"$inputs{course}"),
 1320       $cgi->endform()
 1321     );
 1322 
 1323 
 1324 ## next set up the inner table
 1325   my $inner_table =
 1326     $cgi->table(
 1327       $cgi->Tr(
 1328         $cgi->td({-align=>'CENTER', -valign=>'MIDDLE'},[$current_prob_form, $prob_list_form])
 1329     )
 1330     );
 1331 
 1332 ## finally set up the main table
 1333   my $navigation_bar =
 1334     $cgi->table({-border=>0,-width=>'100%'},
 1335       $cgi->Tr({-align=>'CENTER', -valign=>'TOP'},
 1336         $cgi->td({-align=>'LEFT', -valign=>'MIDDLE'},$inner_table),
 1337         $cgi->td({-align=>'RIGHT', -valign=>'TOP', -width=>'20%', -rowspan=>2},
 1338           $cgi->a({-href=>$Global::webworkDocsURL}, $cgi->img({-src=>$Global::squareWebworkGif,-border=>1,-alt=>'WeBWorK Docs'}))
 1339         )
 1340       ),
 1341       $cgi->Tr(
 1342         $cgi->td({-align=>'LEFT', -valign=>'BOTTOM'}, $cgi->h4("Preview Answers for Problem $probNum of Set $setNumber_display"))
 1343       )
 1344     );
 1345   return $navigation_bar;
 1346 }
 1347 
 1348 
 1349 ##Subroutine saveProblem takes the modified source of the problem and
 1350 ##saves it to the file with the original problem name and appends the
 1351 ##old version of the problem to the file problemname.pg.bak
 1352 
 1353 sub saveProblem {
 1354   my ($source, $probFileName)= @_;
 1355   my $org_source;
 1356  #######get original source of the problem
 1357   if (-e "${templateDirectory}$probFileName" ) {
 1358     unless (-w "${templateDirectory}$probFileName") {
 1359       wwerror($0, "Can't write to ${templateDirectory}$probFileName.\n" .
 1360                    "No changes were saved.\n" .
 1361                    "Check that the  permissions for this problem are 660 (-rw-rw----)\n",
 1362                    "", "", $cgi -> query_string());
 1363     }
 1364     open(PROB,"<${templateDirectory}$probFileName");
 1365     $org_source = join("",<PROB>);
 1366       close(PROB);
 1367   } else {
 1368     wwerror($0, "<H4>Error: The problem ${templateDirectory}$probFileName could not be found!</H4>");
 1369   }
 1370 
 1371  #######append old version to problemfilename.pg.bak:
 1372   open BAKFILE, ">>${templateDirectory}${probFileName}.bak" or
 1373     wwerror($0, "Could not open \n${templateDirectory}${probFileName}.bak for appending.\nNo changes were saved.");
 1374   my ($sec, $min, $hour, $mday, $mon, $year)=localtime(time);
 1375   print BAKFILE "##################################################################\n",
 1376           "##########Date:: $mday-$mon-$year, $hour:$min:$sec################", "\n\n\n";
 1377   print BAKFILE $org_source;
 1378   close BAKFILE;
 1379 
 1380   chmod 0660, "${templateDirectory}${probFileName}.bak" ||
 1381                print "Content-type: text/html\n\n
 1382                       CAN'T CHANGE PERMISSIONS ON FILE ${templateDirectory}${probFileName}.bak";
 1383 
 1384 
 1385  #######copy new version to the file problemfilename.pg
 1386   open (PROBLEM, ">${templateDirectory}$probFileName") ||
 1387     wwerror($0, "Could not open ${templateDirectory}$probFileName for writing.
 1388     Check that the  permissions for this problem are 660 (-rw-rw----)");
 1389   print PROBLEM $source;
 1390   close PROBLEM;
 1391   chmod 0660, "${templateDirectory}${probFileName}" ||
 1392                print "Content-type: text/html\n\n
 1393                       CAN'T CHANGE PERMISSIONS ON FILE ${templateDirectory}${probFileName}";
 1394 
 1395 }
 1396 
 1397 ##Subroutine saveNewProblem takes the modified source of the problem and
 1398 ##saves it to the file with the $new_file_name
 1399 
 1400 sub saveNewProblem {
 1401   my ($source, $new_file_name)= @_;
 1402 
 1403  #######check that the new file name is legal
 1404   unless ($new_file_name =~ /^\w/ ) {
 1405     wwerror($0, "The file name or path\n".
 1406     "$new_file_name\n".
 1407     "can not begin with a non word character.\n" .
 1408     "<b>The new version was not saved.</b>\n" .
 1409     "Go back and choose a different name.");
 1410   }
 1411 
 1412   if ($new_file_name =~ /\.\./ ) {
 1413     wwerror($0, "The file name or path\n".
 1414     "$new_file_name\n".
 1415     "is illegal.\n" .
 1416     "<b>The new version was not saved.</b>\n" .
 1417     "Go back and choose a different name.");
 1418   }
 1419 
 1420 
 1421  #######check that the new file name doesn't exist
 1422   if (-e "${templateDirectory}$new_file_name" ) {
 1423     wwerror($0, "The file\n".
 1424     "${templateDirectory}$new_file_name\n".
 1425     "already exists.\n" .
 1426     "<b>The new version was not saved.</b>\n" .
 1427     "Go back and choose a different file name or\, if you really want to edit\n".
 1428     "${templateDirectory}$new_file_name\,\n".
 1429     "go back and hit the \&quot;Save updated version\&quot; button.");
 1430   }
 1431 
 1432 
 1433  #######copy new version to the file new_file_name
 1434   open (PROBLEM, ">${templateDirectory}$new_file_name") ||
 1435     wwerror($0, "Could not open ${templateDirectory}$new_file_name for writing.
 1436   Check that the  permissions for the directory ${templateDirectory} are 770 (drwxrwx---)
 1437   Also check permissions for any subdirectories in the path.");
 1438   print PROBLEM $source;
 1439   close PROBLEM;
 1440   chmod 0660, "${templateDirectory}$new_file_name" ||
 1441                print "Content-type: text/html\n\n
 1442                       CAN'T CHANGE PERMISSIONS ON FILE ${templateDirectory}$new_file_name";
 1443 
 1444 }
 1445 
 1446 
 1447 sub build_preview_page {
 1448     print preview_answers_htmlTOP("Preview Answers for Problem $probNum", '',$bg_color);
 1449   print format_preview_navigation_bar($probNum);
 1450   print $cgi -> startform(-action=>"$Global::processProblem_CGI");
 1451     print $preview_text;
 1452     ############# print hidden information about problem and set
 1453   $s = '';
 1454   if( $expected_answer_count > 1) {$s = 's'; }
 1455   print   $cgi -> hidden(-name=>'probNum',  -value=>$probNum),
 1456     $cgi -> hidden(-name=>'probSetKey', -value=>$psvn),
 1457     $cgi -> hidden(-name=>'answer_form_submitted', -value=>1),   # alerts the problem to show answers.
 1458     $cgi -> hidden(-name=>'Mode',   -value=>$mode);
 1459     $cgi -> hidden(-name=>'show_old_answers', -value=>$show_old_answers);
 1460   print   &sessionKeyInputs(\%inputs),
 1461     $cgi->br,
 1462     $cgi -> submit(  -name => 'action',  -value=>"Preview Again" ),"\n",
 1463     $cgi -> submit(  -name => 'action',  -value=>"Paste Answer$s" ),"\n",
 1464     $cgi -> submit(  -name => 'action',  -value=>"Submit Answer$s" ),"\n";
 1465 
 1466     print $cgi -> endform();
 1467 
 1468     print &htmlBOTTOM($0, \%inputs, 'previewAnswersHelp.html');
 1469 }
 1470 
 1471 sub encode_submitted_answers { ## returns an encoded string
 1472   my $ra_answer_entry_order = shift;
 1473   my @answer_labels = @$ra_answer_entry_order;
 1474   my %answer_hash =();
 1475   my ($label,$value,$out_string);
 1476   # This grabs the array labels that aren't recorded in the ANSWER_ENTRY_ORDER
 1477   if (defined($pt->{PG_FLAGS_REF}->{KEPT_EXTRA_ANSWERS})){
 1478     my @extra_labels = @{$pt->{PG_FLAGS_REF}->{KEPT_EXTRA_ANSWERS}};
 1479     my $extra_label;
 1480     foreach $extra_label (@extra_labels){
 1481       push @answer_labels, $extra_label;
 1482     }
 1483   }
 1484   ## we will use ## to joint the hash into a string for storage
 1485   ## so first we protect # in all keys and values
 1486   foreach $label (@answer_labels) {
 1487     $value = (defined $inputs{$label}) ? $inputs{$label} : '' ;
 1488     $value = substr($value,0,$Global::maxSizeRecordedAns) if length($value) > $Global::maxSizeRecordedAns;
 1489 #warn "label is |$label| \n";
 1490 #warn "val is |$value| \n";
 1491     $label =~ s/#/\\#\\/g;
 1492     $value =~ s/#/\\#\\/g;
 1493     $answer_hash{$label} = $value;
 1494   }
 1495   $out_string = join '##', %answer_hash;
 1496 
 1497   ## When using flat databases (gdbm, db), we use '&' and '=' to
 1498   ## separate values so we must replace all such occurences. We will
 1499   ## replace then by %% and @@. First we escape any of these.
 1500 
 1501 # this is now handled by protect_string in DBglue8 as it is specific to the database used
 1502 
 1503 # $out_string =~ s/%/\\%\\/g;
 1504 # $out_string =~ s/@/\\@\\/g;
 1505 # $out_string =~ s/&/%%/g;
 1506 # $out_string =~ s/=/@@/g;
 1507 #warn "outstring is |$out_string| \n";
 1508   $out_string;
 1509 }
 1510 
 1511 sub decode_submitted_answers { ## returns a ref to a hash of submitted answers
 1512   my $in_string = shift;
 1513 
 1514   ## reverse encoding process. See comments in encode_submitted_answers
 1515 # this is now handled by unprotect_string in DBglue8 as it is specific to the database used
 1516 
 1517 # $in_string =~ s/@@/=/g;
 1518 # $in_string =~ s/%%/&/g;
 1519 # $in_string =~ s/\\@\\/@/g;
 1520 # $in_string =~ s/\\%\\/%/g;
 1521 
 1522   $in_string =~ s/##$/## /;   # This makes sure that the last element has a value.
 1523                 # It may cause trouble if this value was supposed to be nil instead of a space.
 1524 
 1525   my %saved_answers = split /##/,$in_string;
 1526   my ($label,$value);
 1527   my %answer_hash = ();
 1528 
 1529   foreach $label (keys (%saved_answers)) {
 1530     $value = $saved_answers{$label};
 1531     $label =~ s/\\#\\/#/g;
 1532     $value =~ s/\\#\\/#/g;
 1533     $answer_hash{$label} = $value;
 1534   }
 1535   \%answer_hash;
 1536 }
 1537 
 1538 sub defineProblemEnvir {
 1539     my ($mode,$probNum,$psvn,$courseName)      =   @_;
 1540     my %envir=();
 1541     my $loginName = &getStudentLogin($psvn);
 1542   ##how to put an array submittedAnswers in a hash??
 1543 #    $envir{'refSubmittedAnswers'}    =   $refSubmittedAnswers if defined($refSubmittedAnswers);
 1544     $envir{'psvnNumber'}        =   $psvn;
 1545     $envir{'psvn'}            =   $psvn;
 1546     $envir{'studentName'}       =   &CL_getStudentName($loginName);
 1547   $envir{'studentLogin'}        = &getStudentLogin($psvn);
 1548   $envir{'studentID'}         = &CL_getStudentID($loginName);
 1549   $envir{'sectionName'}       = &CL_getClassSection($loginName);
 1550   $envir{'sectionNumber'}       = &CL_getClassSection($loginName);
 1551   $envir{'recitationName'}      = &CL_getClassRecitation($loginName);
 1552   $envir{'recitationNumber'}      = &CL_getClassRecitation($loginName);
 1553   $envir{'setNumber'}         = &getSetNumber($psvn);
 1554   $envir{'questionNumber'}        = $probNum;
 1555   $envir{'probNum'}           = $probNum;
 1556   $envir{'openDate'}          = &getOpenDate($psvn);
 1557   $envir{'formattedOpenDate'}     = &formatDateAndTime(&getOpenDate($psvn));
 1558   $envir{'dueDate'}           = &getDueDate($psvn);
 1559   $envir{'formattedDueDate'}      = &formatDateAndTime(&getDueDate($psvn));
 1560   $envir{'answerDate'}        = &getAnswerDate($psvn);
 1561   $envir{'formattedAnswerDate'}   = &formatDateAndTime(&getAnswerDate($psvn));
 1562    #  DavideCervone's new parameters
 1563    $envir{'showRemainingTime'} = $Global::showRemainingTime;
 1564   $envir{'startShowingRemainingTime'} = $Global::startShowingRemainingTime;
 1565    $envir{'dueDateLeeway'} = $Global::dueDateLeeway;
 1566    #  end DPVC
 1567   $envir{'problemValue'}        = &getProblemValue($probNum,$psvn);
 1568   $envir{'fileName'}          = &getProblemFileName($probNum,$psvn);
 1569   $envir{'probFileName'}        = &getProblemFileName($probNum,$psvn);
 1570   $envir{'languageMode'}        = $mode;
 1571   $envir{'displayMode'}       = $mode;
 1572   $envir{'outputMode'}        = $mode;
 1573   $envir{'courseName'}        = $courseName;
 1574   $envir{'sessionKey'}        = ( defined($inputs{'key'}) ) ?$inputs{'key'} : " ";
 1575 
 1576   # initialize constants for PGanswermacros.pl
 1577   $envir{'numRelPercentTolDefault'}   =     getNumRelPercentTolDefault();
 1578   $envir{'numZeroLevelDefault'}   =     getNumZeroLevelDefault();
 1579   $envir{'numZeroLevelTolDefault'}  =     getNumZeroLevelTolDefault();
 1580   $envir{'numAbsTolDefault'}      =     getNumAbsTolDefault();
 1581   $envir{'numFormatDefault'}      =     getNumFormatDefault();
 1582   $envir{'functRelPercentTolDefault'} =     getFunctRelPercentTolDefault();
 1583   $envir{'functZeroLevelDefault'}   =     getFunctZeroLevelDefault();
 1584   $envir{'functZeroLevelTolDefault'}  =     getFunctZeroLevelTolDefault();
 1585   $envir{'functAbsTolDefault'}    =     getFunctAbsTolDefault();
 1586   $envir{'functNumOfPoints'}      =     getFunctNumOfPoints();
 1587   $envir{'functVarDefault'}       =     getFunctVarDefault();
 1588   $envir{'functLLimitDefault'}    =     getFunctLLimitDefault();
 1589   $envir{'functULimitDefault'}    =     getFunctULimitDefault();
 1590   $envir{'functMaxConstantOfIntegration'} = getFunctMaxConstantOfIntegration();
 1591         $envir{'useBaseTenLog'} =     $Global::useBaseTenLog;
 1592   $envir{'defaultDisplayMatrixStyle'} =     $Global::defaultDisplayMatrixStyle;
 1593   #kludge check definition of number of attempts again. The +1 is because this is used before the current answer is evaluated.
 1594   $envir{'numOfAttempts'}             =     &getProblemNumOfCorrectAns($probNum,$psvn)
 1595                                           + &getProblemNumOfIncorrectAns($probNum,$psvn)+1;
 1596 
 1597 
 1598 
 1599   # defining directorys and URLs
 1600   $envir{'templateDirectory'}       = &getCourseTemplateDirectory();
 1601   $envir{'classDirectory'}        = $Global::classDirectory;
 1602   $envir{'cgiDirectory'}        = $Global::cgiDirectory;
 1603   $envir{'cgiURL'}                    =   getWebworkCgiURL();
 1604   $envir{'macroDirectory'}        = getCourseMacroDirectory();
 1605   $envir{'courseScriptsDirectory'}    = getCourseScriptsDirectory();
 1606   $envir{'htmlDirectory'}             =   getCourseHtmlDirectory();
 1607   $envir{'htmlURL'}           = getCourseHtmlURL();
 1608   $envir{'tempDirectory'}             =   getCourseTempDirectory();
 1609   $envir{'tempURL'}                   =   getCourseTempURL();
 1610   $envir{'scriptDirectory'}       = $Global::scriptDirectory;
 1611   $envir{'webworkDocsURL'}        = $Global::webworkDocsURL;
 1612   $envir{'externalTTHPath'}       = $Global::externalTTHPath;
 1613   $envir{'externalGif2EpsPath'}     = $scriptDirectory.'gif2eps';  #compatible with previous standard of storing this script in the scripts directory
 1614   $envir{'externalPng2EpsPath'}     = $scriptDirectory.'png2eps';
 1615   $envir{'externalLatexPath'}       = $Global::externalLaTeX2HTMLPath;
 1616 
 1617 
 1618   $envir{'inputs_ref'}                = \%inputs;
 1619   $envir{'problemSeed'}         =   $seed;
 1620   $envir{'displaySolutionsQ'}     =   $displaySolutionsQ;
 1621   $envir{'displayHintsQ'}       =   $displayHintsQ;
 1622 
 1623   # here is a way to pass environment variables defined in webworkCourse.ph
 1624   my $k;
 1625   foreach $k (keys %Global::PG_environment ) {
 1626     $envir{$k} = $Global::PG_environment{$k};
 1627   }
 1628   %envir;
 1629 }
 1630 
 1631 };  # end eval
 1632 
 1633 print "Content-type:  text/plain\n\n Error in $Global::processProblem_CGI\n$@" if $@;
 1634 
 1635 #### for error checking and debugging purposes
 1636 sub pretty_print_rh {
 1637   my $rh = shift;
 1638   foreach my $key (sort keys %{$rh})  {
 1639     print "  $key => ",$rh->{$key},"\n";
 1640   }
 1641 }
 1642 
 1643 #   Code for logging students's answers to allow inspection of answer history.
 1644 sub logCourseData {
 1645       return unless ($Global::logCourseAnswerData);
 1646 
 1647       my $user = shift;
 1648       my $setNum = shift;
 1649       my $probNum = shift;
 1650       my $inputs = shift;
 1651       my $pt = shift;
 1652       my @answers = (defined($pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER})) ?
 1653     @{$pt->{PG_FLAGS_REF}->{ANSWER_ENTRY_ORDER}} :
 1654     keys %{$pt->rh_evaluated_answers};
 1655       my ($id,$string);
 1656   # This grabs the array labels that aren't recorded in the ANSWER_ENTRY_ORDER
 1657   if (defined($pt->{PG_FLAGS_REF}->{KEPT_EXTRA_ANSWERS})){
 1658     my @extra_labels = @{$pt->{PG_FLAGS_REF}->{KEPT_EXTRA_ANSWERS}};
 1659     my $extra_label;
 1660     foreach $extra_label (@extra_labels){
 1661       push @answers, $extra_label;
 1662     }
 1663   }
 1664       my @ans = ("|$user|$setNum|$probNum|",time());
 1665       foreach $id (@answers) {
 1666       $string = $inputs->{$id}; $string = "" unless defined($string);
 1667       $string =~ s!\t! !g;  # just in case
 1668       push (@ans,$string);
 1669       }
 1670 
 1671       my $answerLog = getCourseLogsDirectory()."answer_log";
 1672       unless (-e $answerLog) {
 1673         &createFile($answerLog, $Global::log_file_permission, $Global::numericalGroupID);
 1674     }
 1675       open(LOG, ">>$answerLog") or warn "Can't open course access log $answerLog";
 1676       print LOG join("\t",@ans),"\n";  # data is tab-separated fields
 1677       close(LOG);
 1678 }
 1679 #   End code for logging students's answers
 1680 
 1681 
 1682 
 1683 
 1684 
 1685 END {
 1686    if (defined($main::SIG_TIME_OUT) && $main::SIG_TIME_OUT == 1) {
 1687       alarm(0);  # turn off the alarm
 1688 
 1689       my $problem_message = qq!Content-type: text/html\n\n<HTML><BODY BGCOLOR = "FF99CC">
 1690         <BLOCKQUOTE><H3>WeBWorK heavy useage time out.</H3>\n
 1691       <H4>Your request for a WeBWorK problem was cancelled because it took more
 1692       than $main::TIME_OUT_CONSTANT seconds.</H4>
 1693       If this occurs for only this problem, it is likely that there is a programing error
 1694       in this problem, maybe an infinite loop.  Please report this to your instructor.<p />\n
 1695       If you get this error on several different problems, it
 1696       is probably because the
 1697       WeBWorK server is extraordinarily busy.<p />\n
 1698       In this case you should be warned that WeBWorK response will be unusually slow.  If possible you should try
 1699       to use WeBWorK at another time when the load is not as high.  The highest useage periods are in the
 1700       evening, particularly in the two hours before assignments are due.<p />\n
 1701           Use the back button to return to the previous page and try again.<p />\n
 1702           If the high useage problem continues you can report this to your instructor using
 1703           the feedback button.
 1704           <p />
 1705           Script: $Global::processProblem_CGI
 1706            </BLOCKQUOTE></BODY></HTML>
 1707       !;
 1708         print $problem_message, "\n";
 1709 
 1710 
 1711 
 1712    }
 1713 
 1714     # begin Timing code
 1715   if( $main::logTimingData == 1 ) {
 1716     my $endTime = new Benchmark;
 1717     my $error_str='';
 1718 
 1719     if ($main::SIGPIPE) {
 1720       $error_str = 'broken PIPE--';
 1721     }
 1722     elsif ($main::SIG_TIME_OUT) {
 1723       $error_str = "TIME_OUT after $main::TIME_OUT_CONSTANT secs --";
 1724     }
 1725 
 1726     &Global::logTimingInfo($main::beginTime,$endTime,$error_str.'processProb8.pl '. "(mode: $main::display_mode, action: $main::Action)",$main::Course,$main::User);
 1727   }
 1728   # end Timing code
 1729 
 1730 }
 1731 

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9