package WeBWorK::ContentGenerator::Problem; use base qw(WeBWorK::ContentGenerator); use strict; use warnings; use Apache::Constants qw(:common); use WeBWorK::ContentGenerator; use WeBWorK::PG; # "Classic" form fields from processProblem8.pl # # user - user ID # key - session key # course - course name # probSetKey - USUALLY known as the PSVN # probNum - problem number a.k.a. ID a.k.a. name # # Mode - display mode (HTML, HTML_tth, or typeset or whatever it's called) # show_old_answers - whether or not student's old answers should be filled in # ShowAns - asks for correct answer to be shown -- only available for instructors # answer$i - student answers # showEdit - checks if the ShowEditor button should be shown and clicked # showSol - checks if the solution button ishould be shown and clicked # # source - contains modified problem source when called from the web-based problem editor # seed - contains problem seed when called from the web-based problem editor # readSourceFromHTMLQ - if true, problem is read from 'source' instead of file # action - submit button clicked to invoke script (alledgedly) # 'Save updated version' # 'Read problem from disk' # 'Submit Answers' # 'Preview Answers' # 'Preview Again' # probFileName - name of the PG file being edited # languageType - afaik, always set to 'pg' sub title { my ($self, $problem_set, $problem) = @_; my $r = $self->{r}; my $user = $r->param('user'); return "Problem $problem of problem set $problem_set for $user"; } sub body { my ($self, $problem_set, $problem) = @_; # we have to call init_translator like this: my $pt = WeBWorK::PG->new($courseEnv, $userName, $setName, $problemNumber, $formData); # # ----- this is not a place of honor ----- # Run the problem (output the html text) but also store it within the object. # The correct answers are also calculated and stored within the object $pt ->translate(); # print problem output print "Problem goes here

\n"; print "Problem output
\n"; print "


"; print ${$pt->r_text()}; print "
"; print "

End of problem output
"; # print source code print "Source code

\n";
	print $SOURCE1;
	print "
End source code

"; # The format for the output is described here. We'll need a local variable # to handle the warnings. From within the problem the warning command # has been slaved to the __WARNINGS__ routine which is defined in Global. # We'll need to provide an alternate mechanism. # The base64 encoding is only needed for xml transmission. print "


"; print "Warnings output
"; my $WARNINGS = "Let this be a warning:"; print $WARNINGS; # Install the standard problem grader. See gage/xmlrpc/daemon.pm or processProblem8 for detailed # code on how to choose which problem grader to install, depending on courseEnvironment and problem data. # See also PG.pl which provides for problem by problem overrides. $pt->rf_problem_grader($pt->rf_std_problem_grader); # creates and stores a hash of answer results inside the object: $rh_answer_results $pt -> process_answers($rh->{envir}->{inputs_ref}); # THE UPDATE AND GRADING LOGIC COULD USE AN OVERHAUL. IT WAS SOMEWHAT CONSTRAINED # BY LEGACY CONDITIONS IN THE ORIGINAL PROCESSPROBLEM8. IT'S NOT BAD # BUT IT COULD PROBABLY BE MADE A LITTLE MORE STRAIGHT FORWARD. # # updates the problem state stored by the translator object from the problemEnvironment data # $pt->rh_problem_state({ recorded_score => $rh->{problem_state}->{recorded_score}, # num_of_correct_ans => $rh->{problem_state}->{num_of_correct_ans} , # num_of_incorrect_ans => $rh->{problem_state}->{num_of_incorrect_ans} # } ); # grade the problem (and update the problem state again.) # # Define an entry order -- the default is the order they are received from the browser. # (Which as I understand it is NOT guaranteed to be the Left->Right Up-> Down order we're # used to in the West. my %PG_FLAGS = $pt->h_flags; my $ra_answer_entry_order = ( defined($PG_FLAGS{ANSWER_ENTRY_ORDER}) ) ? $PG_FLAGS{ANSWER_ENTRY_ORDER} : [ keys %{$pt->rh_evaluated_answers} ] ; # Decide whether any answers were submitted. my $answers_submitted = 0; $answers_submitted = 1 if defined( $rh->{answer_form_submitted} ) and 1 == $rh->{answer_form_submitted}; # If there are answers, grade them my ($rh_problem_result,$rh_problem_state) = $pt->grade_problem( answers_submitted => $answers_submitted, ANSWER_ENTRY_ORDER => $ra_answer_entry_order ); # grades the problem. # Output format expected by Webwork.pm (and I believe processProblem8, but check.) my $out = { text => ${$pt ->r_text()}, # encode_base64( ${$pt ->r_text()} ), header_text => $pt->r_header, # encode_base64( ${ $pt->r_header } ), answers => $pt->rh_evaluated_answers, errors => $pt-> errors(), WARNINGS => $WARNINGS, #encode_base64($WARNINGS ), problem_result => $rh_problem_result, problem_state => $rh_problem_state, PG_flag => \%PG_FLAGS }; # Debugging printout of environment tables print "

Request item

\n\n"; print ""; print $self->print_form_data(''); print "
','','
\n"; print "path info
\n"; print $r->path_info(); print "

\n\ncourseEnvironment

\n\n"; print pretty_print_rh($courseEnvironment); print "

\n\nproblemEnvironment

\n\n"; print pretty_print_rh($problemEnvir_rh); ""; } sub pretty_print_rh { my $r_input = shift; my $out = ''; if ( not ref($r_input) ) { $out = $r_input; # not a reference } elsif (is_hash_ref($r_input)) { local($^W) = 0; $out .= ""; foreach my $key (sort keys %$r_input ) { $out .= ""; } $out .="
$key=> ".pretty_print_rh($r_input->{$key}) . "
"; } elsif (is_array_ref($r_input) ) { my @array = @$r_input; $out .= "( " ; while (@array) { $out .= pretty_print_rh(shift @array) . " , "; } $out .= " )"; } elsif (ref($r_input) eq 'CODE') { $out = "$r_input"; } else { $out = $r_input; } $out; } sub is_hash_ref { my $in =shift; my $save_SIG_die_trap = $SIG{__DIE__}; $SIG{__DIE__} = sub {CORE::die(@_) }; my $out = eval{ %{ $in } }; $out = ($@ eq '') ? 1 : 0; $@=''; $SIG{__DIE__} = $save_SIG_die_trap; $out; } sub is_array_ref { my $in =shift; my $save_SIG_die_trap = $SIG{__DIE__}; $SIG{__DIE__} = sub {CORE::die(@_) }; my $out = eval{ @{ $in } }; $out = ($@ eq '') ? 1 : 0; $@=''; $SIG{__DIE__} = $save_SIG_die_trap; $out; } 1; __END__ my $foo =0; # The warning mechanism. This needs to be turned into an object of its own ############### ## Error message routines cribbed from CGI ############### BEGIN { #error message routines cribbed from CGI my $CarpLevel = 0; # How many extra package levels to skip on carp. my $MaxEvalLen = 0; # How much eval '...text...' to show. 0 = all. sub longmess { my $error = shift; my $mess = ""; my $i = 1 + $CarpLevel; my ($pack,$file,$line,$sub,$eval,$require); while (($pack,$file,$line,$sub,undef,undef,$eval,$require) = caller($i++)) { if ($error =~ m/\n$/) { $mess .= $error; } else { if (defined $eval) { if ($require) { $sub = "require $eval"; } else { $eval =~ s/[\\\']/\\$&/g; if ($MaxEvalLen && length($eval) > $MaxEvalLen) { substr($eval,$MaxEvalLen) = '...'; } $sub = "eval '$eval'"; } } elsif ($sub eq '(eval)') { $sub = 'eval {...}'; } $mess .= "\t$sub " if $error eq "called"; $mess .= "$error at $file line $line\n"; } $error = "called"; } $mess || $error; } } ############### ### Our error messages for giving maximum feedback to the user for errors within problems. ############### BEGIN { sub PG_floating_point_exception_handler { # 1st argument is signal name my($sig) = @_; print "Content-type: text/html\n\n

There was a floating point arithmetic error (exception SIG$sig )

--perhaps you divided by zero or took the square root of a negative number?
\n Use the back button to return to the previous page and recheck your entries.
\n"; exit(0); } $SIG{'FPE'} = \&PG_floating_point_exception_handler; #!/usr/bin/perl -w sub PG_warnings_handler { my @input = @_; my $msg_string = longmess(@_); my @msg_array = split("\n",$msg_string); my $out_string = ''; # Extra stack information is provided in this next block # If the warning message does NOT end in \n then a line # number is appended (see Perl manual about warn function) # The presence of the line number is detected below and extra # stack information is added. # To suppress the line number and the extra stack information # add \n to the end of a warn message (in .pl files. In .pg # files add ~~n instead if ($input[$#input]=~/line \d*\.\s*$/) { $out_string .= "##More details:
\n----"; foreach my $line (@msg_array) { chomp($line); next unless $line =~/\w+\:\:/; $out_string .= "----" .$line . "
\n"; } } $Global::WARNINGS .="* " . join("
",@input) . "
\n" . $out_string . "
\n--------------------------------------
\n
\n"; $Global::background_plain_url = $Global::background_warn_url; $Global::bg_color = '#FF99CC'; #for warnings -- this change may come too late } $SIG{__WARN__}=\&PG_warnings_handler; $SIG{__DIE__} = sub { my $message = longmess(@_); $message =~ s/\n/
\n/; my ($package, $filename, $line) = caller(); # use standard die for errors eminating from XML::Parser::Expat # it uses a trapped eval which sometimes fails -- apparently on purpose # and the error is handled by Expat itself. We don't want # to interfer with that. if ($package eq 'XML::Parser::Expat') { die @_; } #print "$package $filename $line \n"; print "Content-type: text/html\r\n\r\n

Software error

\n\n$message\n

\n Please inform the webwork meister.

\n In addition to the error message above the following warnings were detected:


$Global::WARNINGS;
It's sometimes hard to tell exactly what has gone wrong since the full error message may have been sent to standard error instead of to standard out.

To debug you can

Good luck.

\n" ; }; }