From d1629ee5245a5ec0d7ffd7373a72f705499de1e3 Mon Sep 17 00:00:00 2001
From: Michael Gage <1203580+mgage@users.noreply.github.com>
Date: Sun, 6 Oct 2019 12:15:18 -0400
Subject: [PATCH 1/3] Remove references to Crypt::SSLeay which is no longer
needed for https
---
bin/check_modules.pl | 4 +-
clients/sendXMLRPC.pl | 1 -
.../ContentGenerator/instructorXMLHandler.pm | 1 -
.../ContentGenerator/renderViaXMLRPC.pm | 2 +-
lib/WebworkClient.pm.orig | 1085 +++++++++++++++++
5 files changed, 1087 insertions(+), 6 deletions(-)
create mode 100755 lib/WebworkClient.pm.orig
diff --git a/bin/check_modules.pl b/bin/check_modules.pl
index d83f1a40b1..80002c0f6f 100755
--- a/bin/check_modules.pl
+++ b/bin/check_modules.pl
@@ -37,9 +37,7 @@
Apache2::ServerUtil
);
-# Crypt::SSLeay was commented out below, but should the not be
-# in the array when commented out - remove it.
-# For WW 2.15 replace Email::Address with Email::Address::XS
+
my @modulesList = qw(
Array::Utils
diff --git a/clients/sendXMLRPC.pl b/clients/sendXMLRPC.pl
index 0dc6595dd6..16559e97ca 100755
--- a/clients/sendXMLRPC.pl
+++ b/clients/sendXMLRPC.pl
@@ -306,7 +306,6 @@ BEGIN
use Carp;
-#use Crypt::SSLeay; # needed for https
use LWP::Protocol::https;
use Time::HiRes qw/time/;
use MIME::Base64 qw( encode_base64 decode_base64);
diff --git a/lib/WeBWorK/ContentGenerator/instructorXMLHandler.pm b/lib/WeBWorK/ContentGenerator/instructorXMLHandler.pm
index 73015a6f84..3c2c483be5 100644
--- a/lib/WeBWorK/ContentGenerator/instructorXMLHandler.pm
+++ b/lib/WeBWorK/ContentGenerator/instructorXMLHandler.pm
@@ -31,7 +31,6 @@ use PGUtil qw(not_null);
our $UNIT_TESTS_ON = 0; # should be called DEBUG?? FIXME
-#use Crypt::SSLeay;
#use XMLRPC::Lite;
use strict;
diff --git a/lib/WeBWorK/ContentGenerator/renderViaXMLRPC.pm b/lib/WeBWorK/ContentGenerator/renderViaXMLRPC.pm
index de8c911df7..3d7efe82f0 100644
--- a/lib/WeBWorK/ContentGenerator/renderViaXMLRPC.pm
+++ b/lib/WeBWorK/ContentGenerator/renderViaXMLRPC.pm
@@ -27,7 +27,7 @@ use warnings;
package WeBWorK::ContentGenerator::renderViaXMLRPC;
use base qw(WeBWorK::ContentGenerator);
-#use Crypt::SSLeay;
+
#use XMLRPC::Lite;
#use MIME::Base64 qw( encode_base64 decode_base64);
diff --git a/lib/WebworkClient.pm.orig b/lib/WebworkClient.pm.orig
new file mode 100755
index 0000000000..2e409feb93
--- /dev/null
+++ b/lib/WebworkClient.pm.orig
@@ -0,0 +1,1085 @@
+#!/usr/bin/perl -w
+
+################################################################################
+# WeBWorK Online Homework Delivery System
+# Copyright © 2000-2018 The WeBWorK Project, http://openwebwork.sf.net/
+# $CVSHeader: webwork2/lib/WebworkClient.pm,v 1.1 2010/06/08 11:46:38 gage Exp $
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of either: (a) the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any later
+# version, or (b) the "Artistic License" which comes with this package.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See either the GNU General Public License or the
+# Artistic License for more details.
+################################################################################
+
+=head1 NAME
+
+WebworkClient.pm
+
+
+=head1 SYNPOSIS
+ our $xmlrpc_client = new WebworkClient (
+ url => $XML_URL,
+ form_action_url => $FORM_ACTION_URL,
+ site_password => $XML_PASSWORD//'',
+ courseID => $credentials{courseID},
+ userID => $credentials{userID},
+ session_key => $credentials{session_key}//'',
+ sourceFilePath => $fileName,
+ );
+
+Remember to configure the local output file and display command !!!!!!!!
+
+
+
+=head1 DESCRIPTION
+
+This script will take a file and send it to a WeBWorK daemon webservice
+to have it rendered.
+
+The result returned is split into the basic HTML rendering
+and evaluation of answers and then passed to a browser for printing.
+
+The formatting allows the browser presentation to be interactive with the
+daemon running the script webwork2/lib/renderViaXMLRPC.pm
+and with instructorXMLRPChandler.
+
+See WebworkWebservice.pm for related modules which operate on the server side
+
+ WebworkXMLRPC (contained in WebworkWebservice.pm)
+ renderViaXMLRPC
+ instructorXMLRPChandler
+
+=cut
+
+use strict;
+use warnings;
+
+
+# To configure the target webwork server
+# two URLs are required
+# 1. $XML_URL http://test.webwork.maa.org/mod_xmlrpc
+# points to the Webservice.pm and Webservice/RenderProblem modules
+# Is used by the client to send the original XML request to the webservice
+#
+# 2. $FORM_ACTION_URL http:http://test.webwork.maa.org/webwork2/html2xml
+# points to the renderViaXMLRPC.pm module.
+#
+# This url is placed as form action url when the rendered HTML from the original
+# request is returned to the client from Webservice/RenderProblem. The client
+# reorganizes the XML it receives into an HTML page (with a WeBWorK form) and
+# pipes it through a local browser.
+#
+# The browser uses this url to resubmit the problem (with answers) via the standard
+# HTML webform used by WeBWorK to the renderViaXMLRPC.pm handler.
+#
+# This renderViaXMLRPC.pm handler acts as an intermediary between the browser
+# and the webservice. It interprets the HTML form sent by the browser,
+# rewrites the form data in XML format, submits it to the WebworkWebservice.pm
+# which processes it and sends the the resulting HTML back to renderViaXMLRPC.pm
+# which in turn passes it back to the browser.
+# 3. The second time a problem is submitted renderViaXMLRPC.pm receives the WeBWorK form
+# submitted directly by the browser.
+# The renderViaXMLRPC.pm translates the WeBWorK form, has it processes by the webservice
+# and returns the result to the browser.
+# The The client renderProblem.pl script is no longer involved.
+# 4. Summary: renderProblem.pl is only involved in the first round trip
+# of the submitted problem. After that the communication is between the browser and
+# renderViaXMLRPC using HTML forms and between renderViaXMLRPC and the WebworkWebservice.pm
+# module using XML_RPC.
+
+
+our @COMMANDS = qw( listLibraries renderProblem ); #listLib readFile tex2pdf
+
+
+
+##################################################
+# XMLRPC client --
+# this code is identical between renderProblem.pl and renderViaXMLRPC.pm????
+##################################################
+
+package WebworkClient;
+
+
+
+use LWP::Protocol::https;
+use lib "$WeBWorK::Constants::WEBWORK_DIRECTORY/lib";
+use lib "$WeBWorK::Constants::PG_DIRECTORY/lib";
+use XMLRPC::Lite;
+use WeBWorK::Utils qw( wwRound encode_utf8_base64 decode_utf8_base64);
+use Encode qw(encode_utf8 decode_utf8);
+use WeBWorK::Utils::AttemptsTable;
+use WeBWorK::CourseEnvironment;
+use WeBWorK::Utils::DetermineProblemLangAndDirection;
+use WeBWorK::PG::ImageGenerator;
+use HTML::Entities;
+use WeBWorK::Localize;
+use WeBWorK::PG::ImageGenerator;
+use IO::Socket::SSL;
+use Digest::SHA qw(sha1_base64);
+use XML::Simple qw(XMLout);
+use JSON;
+use FormatRenderedProblem;
+
+use constant TRANSPORT_METHOD => 'XMLRPC::Lite';
+use constant REQUEST_CLASS => 'WebworkXMLRPC'; # WebworkXMLRPC is used for soap also!!
+use constant REQUEST_URI => 'mod_xmlrpc';
+
+our $UNIT_TESTS_ON = 0;
+
+##################
+# static variables
+
+# create seed_ce
+# then create imgGen
+our $seed_ce;
+
+eval {
+ $seed_ce = WeBWorK::CourseEnvironment->new(
+ {webwork_dir => $WeBWorK::Constants::WEBWORK_DIRECTORY,
+ courseName => '',
+ webworkURL => '',
+ pg_dir => $WeBWorK::Constants::PG_DIRECTORY,
+ });
+};
+ if ($@ or not ref($seed_ce)){
+ warn "Unable to find environment for WebworkClient:
+ webwork_dir => $WeBWorK::Constants::WEBWORK_DIRECTORY
+ pg_dir => $WeBWorK::Constants::PG_DIRECTORY";
+ }
+
+
+
+our %imagesModeOptions = %{$seed_ce->{pg}->{displayModeOptions}->{images}};
+our $site_url = $seed_ce->{server_root_url}//'';
+our $imgGen = WeBWorK::PG::ImageGenerator->new(
+ tempDir => $seed_ce->{webworkDirs}->{tmp},
+ latex => $seed_ce->{externalPrograms}->{latex},
+ dvipng => $seed_ce->{externalPrograms}->{dvipng},
+ useCache => 1,
+ cacheDir => $seed_ce->{webworkDirs}->{equationCache},
+ cacheURL => $site_url . $seed_ce->{webworkURLs}->{equationCache},
+ cacheDB => $seed_ce->{webworkFiles}->{equationCacheDB},
+ dvipng_align => $imagesModeOptions{dvipng_align},
+ dvipng_depth_db => $imagesModeOptions{dvipng_depth_db},
+);
+
+
+sub new { #WebworkClient constructor
+ my $invocant = shift;
+ my $class = ref $invocant || $invocant;
+ my $self = {
+ return_object => {},
+ request_object => {},
+ error_string => '',
+ encoded_source => '',
+ url => '',
+ course_password => '',
+ site_password => '',
+ courseID => '',
+ userID => '',
+ inputs_ref => { AnSwEr0001 => '',
+ AnSwEr0002 => '',
+ AnSwEr0003 => '',
+ displayMode => 'no displayMode defined',
+ forcePortNumber => '',
+ },
+ @_, # options and overloads
+ };
+
+ bless $self, $class;
+}
+
+
+our $result;
+
+##################################################
+# Utilities --
+# this code is identical between renderProblem.pl and renderViaXMLRPC.pm
+##################################################
+
+=head2 xmlrpcCall
+
+
+
+ $xmlrpc_client->encodeSource($source);
+ $xmlrpc_client->{sourceFilePath} = $fileName;
+
+ my $input = {
+ userID => $credentials{userID}//'',
+ session_key => $credentials{session_key}//'',
+ courseID => $credentials{courseID}//'',
+ courseName => $credentials{courseID}//'',
+ course_password => $credentials{course_password}//'',
+ site_password => $XML_PASSWORD//'',
+ envir => $xmlrpc_client->environment(
+ fileName => $fileName,
+ sourceFilePath => $fileName
+ ),
+ };
+ our($output, $return_string, $result);
+
+
+ if ( $result = $xmlrpc_client->xmlrpcCall('renderProblem', $input) ) {
+ $output = $xmlrpc_client->formatRenderedProblem;
+ } else {
+ $output = $xmlrpc_client->return_object; # error report
+ }
+
+ Keys in $result or in $xmlrpc_client->return_object for the command "renderProblem"
+ session_key
+ flags
+ errors
+ internal_debug_messages
+ WARNINGS
+ problem_state
+ debug_messages
+ userID
+ compute_time
+ warning_messages
+ courseID
+ text
+ problem_result
+ header_text
+ answers
+
+
+=cut
+
+
+
+
+
+sub xmlrpcCall {
+ my $self = shift;
+ my $command = shift;
+ my $input = shift||{};
+ my $requestObject;
+ $command = 'listLibraries' unless defined $command;
+ my $default_inputs = $self->default_inputs();
+ $requestObject = {%$default_inputs, %$input}; #input values can override default inputs
+
+ $self->request_object($requestObject); # store the request object for later
+
+ my $requestResult;
+ my $transporter = TRANSPORT_METHOD->new;
+
+ eval {
+ $requestResult= $transporter
+ #->uri('http://'.HOSTURL.':'.HOSTPORT.'/'.REQUEST_CLASS)
+ #-> proxy(PROTOCOL.'://'.HOSTURL.':'.HOSTPORT.'/'.REQUEST_URI);
+ -> proxy(($self->url).'/'.REQUEST_URI);
+ };
+ print STDERR "WebworkClient: Initiating xmlrpc request to url ",($self->url).'/'.REQUEST_URI, " \n Error: $@\n" if $@;
+ # turn off verification of the ssl cert
+ $transporter->transport->ssl_opts(verify_hostname=>0,
+ SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE);
+
+ if ($UNIT_TESTS_ON) {
+ print STDERR "WebworkClient.pm ".__LINE__." xmlrpcCall sent to ", $self->url,"\n";
+ print STDERR "WebworkClient.pm ".__LINE__." xmlrpcCall issued with command $command\n";
+ print STDERR "WebworkClient.pm ".__LINE__." input is: ",join(" ", %{$self->request_object}),"\n";
+ print STDERR "WebworkClient.pm ".__LINE__." xmlrpcCall $command initiated webwork webservice object $requestResult\n";
+ }
+
+ local( $result);
+ # use eval to catch errors
+ #print STDERR "WebworkClient: issue command ", REQUEST_CLASS.'.'.$command, " ",join(" ", %$input),"\n";
+ eval { $result = $requestResult->call(REQUEST_CLASS.'.'.$command, $self->request_object ) };
+ # result is of type XMLRPC::SOM
+ print STDERR "There were a lot of errors\n" if $@;
+ print STDERR "Errors: \n $@\n End Errors\n" if $@;
+
+ print CGI::h2("WebworkClient Errors") if $@;
+ print CGI::p("Errors:",CGI::br(),CGI::blockquote({style=>"color:red"},CGI::code($@)),CGI::br(),"End Errors") if $@;
+
+ if (not ref($result) ) {
+ my $error_string = "xmlrpcCall to $command returned no result for ".
+ ($self->{sourceFilePath}//'')."\n";
+ print STDERR $error_string;
+ $self->error_string($error_string);
+ $self->fault(1);
+ return $self;
+ } elsif ( $result->fault ) { # report errors
+ my $error_string = 'Error message for '.
+ join( ' ',
+ "command:",
+ $command,
+ "\n
faultcode:",
+ $result->faultcode,
+ "\n
faultstring:",
+ $result->faultstring, "\n
End error message
\n"
+ );
+
+ print STDERR $error_string;
+ $self->return_object($result->result());
+ $self->error_string($error_string);
+ $self->fault(1); # set fault flag to true
+ return $self;
+ } else {
+ if (ref($result->result())=~/HASH/ and defined($result->result()->{text}) ) {
+ $result->result()->{text} = decode_utf8_base64($result->result()->{text});
+ }
+ if (ref($result->result())=~/HASH/ and defined($result->result()->{header_text}) ) {
+ $result->result()->{header_text} = decode_utf8_base64($result->result()->{header_text});
+ }
+
+ $self->return_object($result->result());
+ # print "\n retrieve result ", keys %{$self->return_object};
+ return $self->return_object; # $result->result();
+ # would it be better to return the entire $result?
+ # probably not, there is no hash directly available from the $result object.
+ }
+
+}
+
+
+=head2 jsXmlrpcCall
+
+=cut
+
+sub jsXmlrpcCall {
+ my $self = shift;
+ my $command = shift;
+ my $input = shift;
+ $command = 'listLibraries' unless $command;
+ if ($UNIT_TESTS_ON) {
+ print STDERR "WebworkClient.pm ".__LINE__." jsXmlrpcCall issued with command $command\n";
+ }
+
+ print "the command was $command";
+
+ my $transporter = TRANSPORT_METHOD->new;
+
+ my $requestResult = $transporter
+ -> proxy(($self->url).'/'.REQUEST_URI);
+ $transporter->transport->ssl_opts(verify_hostname=>0,
+ SSL_verify_mode => 'SSL_VERIFY_NONE');
+
+ local( $result);
+ # use eval to catch errors
+ eval { $result = $requestResult->call(REQUEST_CLASS.'.'.$command,$input) };
+ if ($@) {
+ print STDERR "There were a lot of errors for $command\n" ;
+ print STDERR "Errors: \n $@\n End Errors\n" ;
+ return 0 #failure
+ }
+ print "hmm $result";
+ unless (ref($result) and $result->fault) {
+ my $rh_result = $result->result();
+ print "\n success \n";
+ print pretty_print($rh_result->{'ra_out'});
+ $self->return_object( $rh_result );
+ return 1; # success
+
+ } else {
+ $self->return_object( 'Error from server: '. join( ",\n ",
+ $result->faultcode,
+ $result->faultstring)
+ );
+ return 0; #failure
+ }
+}
+
+=head2 encodeSource
+
+
+=cut
+sub encodeSource {
+ my $self = shift;
+ my $source = shift||'';
+ $self->{encoded_source} =encode_utf8_base64($source);
+}
+
+=head2 Accessor methods
+
+ encoded_source
+ request_object
+ return_object
+ error_string
+ fault
+ url
+ form_data
+
+=cut
+
+sub encoded_source {
+ my $self = shift;
+ my $source = shift;
+ $self->{encoded_source} =$source if defined $source and $source =~/\S/; # source is non-empty
+ $self->{encoded_source};
+}
+sub request_object { # in or input
+ my $self = shift;
+ my $object = shift;
+ $self->{request_object} =$object if defined $object and ref($object); # source is non-empty
+ $self->{request_object};
+}
+sub return_object { # out
+ my $self = shift;
+ my $object = shift;
+ $self->{return_object} =$object if defined $object and ref($object); # source is non-empty
+ $self->{return_object};
+}
+sub error_string {
+ my $self = shift;
+ my $string = shift;
+ $self->{error_string} =$string if defined $string and $string =~/\S/; # source is non-empty
+ $self->{error_string};
+}
+sub fault {
+ my $self = shift;
+ my $fault_flag = shift;
+ $self->{fault_flag} =$fault_flag if defined $fault_flag and $fault_flag =~/\S/; # source is non-empty
+ $self->{fault_flag};
+}
+sub url {
+ my $self = shift;
+ my $new_url = shift;
+ $self->{url} = $new_url if defined($new_url) and $new_url =~ /\S/;
+ $self->{url};
+}
+
+sub form_data {
+ my $self = shift;
+ my $form_data = shift;
+ $self->{inputs_ref} = $form_data if defined($form_data) and $form_data =~ /\S/;
+ $self->{inputs_ref};
+}
+
+=head2 initiate default values
+
+=cut
+sub setInputTable_for_listLib {
+ my $self = shift;
+ my $out = {
+ set => 'set0',
+ library_name => 'Library',
+ command => 'all',
+ };
+
+ $out;
+}
+
+sub default_inputs {
+ my $self = shift;
+ my $webwork_dir = $WeBWorK::Constants::WEBWORK_DIRECTORY; #'/opt/webwork/webwork2';
+ my $seed_ce = new WeBWorK::CourseEnvironment({ webwork_dir => $webwork_dir});
+ die "Can't create seed course environment for webwork in $webwork_dir" unless ref($seed_ce);
+
+ $self->{seed_ce} = $seed_ce;
+
+ my @modules_to_evaluate;
+ my @extra_packages_to_load;
+ my @modules = @{ $seed_ce->{pg}->{modules} };
+
+ foreach my $module_packages_ref (@modules) {
+ my ($module, @extra_packages) = @$module_packages_ref;
+ # the first item is the main package
+ push @modules_to_evaluate, $module;
+ # the remaining items are "extra" packages
+ push @extra_packages_to_load, @extra_packages;
+ }
+
+ my $out = {
+ library_name => 'Library',
+ command => 'renderProblem',
+ answer_form_submitted => 1,
+ course => $self->{course},
+ extra_packages_to_load => [@extra_packages_to_load],
+ mode => $self->{displayMode},
+ displayMode => $self->{displayMode},
+ modules_to_evaluate => [@modules_to_evaluate],
+ envir => $self->environment(),
+ problem_state => {
+
+ num_of_correct_ans => 0,
+ num_of_incorrect_ans => 4,
+ recorded_score => 1.0,
+ },
+ source => $self->encoded_source, #base64 encoded
+ };
+
+ $out;
+}
+
+=item environment
+
+=cut
+
+sub environment {
+ my $self = shift;
+ my $envir = {
+ answerDate => '4014438528',
+ CAPA_Graphics_URL=>'http://webwork-db.math.rochester.edu/capa_graphics/',
+ CAPA_GraphicsDirectory =>'/ww/webwork/CAPA/CAPA_Graphics/',
+ CAPA_MCTools=>'/ww/webwork/CAPA/CAPA_MCTools/',
+ CAPA_Tools=>'/ww/webwork/CAPA/CAPA_Tools/',
+ cgiDirectory=>'Not defined',
+ cgiURL => 'foobarNot defined',
+ classDirectory=> 'Not defined',
+ courseName=>'Not defined',
+ courseScriptsDirectory=>'not defined',
+ displayMode=>$self->{inputs_ref}->{displayMode}//"no display mode defined in WebworkClient-> environment",
+ dueDate=> '4014438528',
+ effectivePermissionLevel => 10,
+ externalGif2EpsPath=>'not defined',
+ externalPng2EpsPath=>'not defined',
+ externalTTHPath=>'/usr/local/bin/tth',
+ fileName=>'WebworkClient.pm:: define fileName in environment',
+ formattedAnswerDate=>'6/19/00',
+ formattedDueDate=>'6/19/00',
+ formattedOpenDate=>'6/19/00',
+ functAbsTolDefault=> 0.0000001,
+ functLLimitDefault=>0,
+ functMaxConstantOfIntegration=> 1000000000000.0,
+ functNumOfPoints=> 5,
+ functRelPercentTolDefault=> 0.000001,
+ functULimitDefault=>1,
+ functVarDefault=> 'x',
+ functZeroLevelDefault=> 0.000001,
+ functZeroLevelTolDefault=>0.000001,
+ htmlDirectory =>'not defined',
+ htmlURL =>'not defined',
+ inputs_ref => $self->{inputs_ref},
+ macroDirectory=>'not defined',
+ numAbsTolDefault=>0.0000001,
+ numFormatDefault=>'%0.13g',
+ numOfAttempts=> 0,
+ numRelPercentTolDefault => 0.0001,
+ numZeroLevelDefault =>0.000001,
+ numZeroLevelTolDefault =>0.000001,
+ openDate=> '3014438528',
+ permissionLevel =>10,
+ PRINT_FILE_NAMES_FOR => [ 'gage'],
+ probFileName => 'WebworkClient.pm:: define probFileName in environment',
+ problemSeed => $self->{inputs_ref}->{problemSeed}//3333,
+ problemUUID => $self->{inputs_ref}->{problemUUID}//0,
+ problemValue =>1,
+ probNum => 13,
+ psvn => $self->{inputs_ref}->{psvn}//54321,
+ questionNumber => 1,
+ scriptDirectory => 'Not defined',
+ sectionName => 'Gage',
+ sectionNumber => 1,
+ server_root_url =>"foobarfoobar",
+ sessionKey=> 'Not defined',
+ setNumber =>'not defined',
+ studentLogin =>'gage',
+ studentName => 'Mike Gage',
+ tempDirectory => 'not defined',
+ templateDirectory=>'not defined',
+ tempURL=>'not defined',
+ webworkDocsURL => 'not defined',
+ showHints => 1, # extra options -- usually passed from the input form
+ showSolutions => 1,
+ @_,
+ };
+ $envir;
+};
+
+=item formatRenderedLibraries
+
+=cut
+
+sub formatRenderedLibraries {
+ my $self = shift;
+ #my @rh_result = @{$self->return_object}; # wrap problem in formats
+ my %rh_result = %{$self->return_object};
+ my $result = "";
+ foreach my $key (sort keys %rh_result) {
+ $result .= "$key";
+ $result .= $rh_result{$key};
+ }
+ return $result;
+}
+
+=item formatRenderedProblem
+
+=cut
+
+sub formatRenderedProblem {
+<<<<<<< HEAD
+ FormatRenderedProblem::formatRenderedProblem(@_);
+=======
+ my $self = shift;
+ my $problemText ='';
+ my $rh_result = $self->return_object() || {}; # wrap problem in formats
+ $problemText = "No output from rendered Problem" unless $rh_result ;
+ #print "formatRenderedProblem text $rh_result = ",%$rh_result,"\n";
+ if (ref($rh_result) and $rh_result->{text} ) {
+ $problemText = $rh_result->{text};
+ } else {
+ $problemText .= "Unable to decode problem text
\n".
+ $self->{error_string}."\n".
+ format_hash_ref($rh_result);
+ }
+ my $problemHeadText = $rh_result->{header_text}//'';
+ my $rh_answers = $rh_result->{answers}//{};
+ my $answerOrder = $rh_result->{flags}->{ANSWER_ENTRY_ORDER}; #[sort keys %{ $rh_result->{answers} }];
+ my $encoded_source = $self->encoded_source//'';
+ my $sourceFilePath = $self->{sourceFilePath}//'';
+ my $warnings = '';
+ my $answerhashXML = XMLout($rh_answers, RootName => 'answerhashes');
+
+ #################################################
+ # Code to get and set problem language and direction based on flags set by the PG problem.
+ # This uses the same utility function as used by lib/WeBWorK/ContentGenerator/Problem.pm
+ # and various modules in lib/WeBWorK/ContentGenerator/Instructor/ .
+ # However, for technical reasons it requires using additional optional arguments
+ # which were added for the use here as they are not available via an internal
+ # CourseEnvironment where it was available in the other uses.
+ #################################################
+ # Need to set things like $PROBLEM_LANG_AND_DIR = "lang=\"he\" dir=\"rtl\"";
+
+ my $formLanguage = ($self->{inputs_ref}->{language})//'en';
+
+ my @PROBLEM_LANG_AND_DIR = ();
+
+ my $mode_for_get_problem_lang_and_dir = "auto:en:ltr"; # Will be used to set the default
+ # Setting to force English and LTR always:
+ # $mode_for_get_problem_lang_and_dir = "force:en:ltr";
+ # Setting to avoid any setting be used:
+ # $mode_for_get_problem_lang_and_dir = "none";
+
+ my @to_set_lang_dir = get_problem_lang_and_dir( $self, $rh_result, $mode_for_get_problem_lang_and_dir, $formLanguage );
+ # We are calling get_problem_lang_and_dir() when $self does not
+ # have a request hash called "r" inside it, so need to set the requested
+ # and the course-wide language. We request mode $mode_for_get_problem_lang_and_dir
+ # which by default is set above to "auto:en:ltr" so PG files can request their
+ # language and text direction be set, but falls back to English and LTR.
+ # We also do not have access to a default course language in the same sense
+ # so use the $formLanguage instead.
+
+ while ( scalar(@to_set_lang_dir) > 0 ) {
+ push( @PROBLEM_LANG_AND_DIR, shift( @to_set_lang_dir ) ); # HTML tag being set
+ push( @PROBLEM_LANG_AND_DIR, "=\"" );
+ push( @PROBLEM_LANG_AND_DIR, shift( @to_set_lang_dir ) ); # HTML value being set
+ push( @PROBLEM_LANG_AND_DIR, "\" " );
+ }
+ my $PROBLEM_LANG_AND_DIR = join("",@PROBLEM_LANG_AND_DIR);
+
+ #################################################
+ # Code to get and set main language and direction for generated HTML pages.
+ # Very similar to the code in output_course_lang_and_dir() of
+ # lib/WeBWorK/ContentGenerator.pm with changes for the XMLRPC on the setting.
+ # It depends on the $formLanguage and not a course setting.
+ #################################################
+
+ my $master_lang_setting = "lang=\"en-US\""; # default setting
+ my $master_dir_setting = ""; # default is NOT set
+
+ if ( $formLanguage ne "en" ) {
+ # Attempt to override the defaults
+ if ( $formLanguage =~ /^he/i ) { # supports also the current "heb" option
+ # Hebrew - requires RTL direction
+ $master_lang_setting = "lang=\"he\""; # Hebrew
+ $master_dir_setting = " dir=\"rtl\""; # RTL
+ } elsif ( $formLanguage =~ /^ar/i ) {
+ # Arabic - requires RTL direction
+ $master_lang_setting = "lang=\"ar\""; # Arabic
+ $master_dir_setting = " dir=\"rtl\""; # RTL
+ } else {
+ # Use the $formLanguage without changing the text direction.
+ # Additional RTL languages should be added above, as needed.
+ $master_lang_setting = "lang=\"${formLanguage}\"";
+ }
+ }
+
+ my $COURSE_LANG_AND_DIR = "${master_lang_setting}${master_dir_setting}";
+
+ #################################################
+ # regular Perl warning messages generated with warn
+ #################################################
+
+ if ( defined ($rh_result->{WARNINGS}) and $rh_result->{WARNINGS} ){
+ $warnings = "
WARNINGS
".decode_utf8_base64($rh_result->{WARNINGS})."
$key | => | ".pretty_print($r_input->{$key}) . " |