From 3b696b42a5ce9d729e7c52c6907f3abb87b0728c Mon Sep 17 00:00:00 2001 From: Geoff Goehle Date: Mon, 20 Jun 2016 20:57:44 -0400 Subject: [PATCH 01/12] Add UTF8 to xmlrpc --- lib/WeBWorK/PG/IO.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/WeBWorK/PG/IO.pm b/lib/WeBWorK/PG/IO.pm index 0990606be6..feecdfa0f8 100644 --- a/lib/WeBWorK/PG/IO.pm +++ b/lib/WeBWorK/PG/IO.pm @@ -139,7 +139,7 @@ sub read_whole_file { unless path_is_course_subdir($filePath); local (*INPUT); - open(INPUT, "<$filePath") || die "$0: read_whole_file subroutine:
Can't read file $filePath"; + open(INPUT, "<:utf8", $filePath) || die "$0: read_whole_file subroutine:
Can't read file $filePath"; local($/)=undef; my $string = ; # can't append spaces because this causes trouble with <<'EOF' \nEOF construction close(INPUT); From d2d636c1f79a66ccd0d719c9f576db0820a041d6 Mon Sep 17 00:00:00 2001 From: Geoff Goehle Date: Fri, 15 Jul 2016 12:02:18 -0400 Subject: [PATCH 02/12] Add utf8 encoding to the base64 methods. --- lib/PGcore.pm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/PGcore.pm b/lib/PGcore.pm index fc4794fea9..b2f12f80bd 100755 --- a/lib/PGcore.pm +++ b/lib/PGcore.pm @@ -29,6 +29,7 @@ use Tie::IxHash; use WeBWorK::Debug; use MIME::Base64(); use PGUtil(); +use Encode qw(encode_utf8 decode_utf8); ################################## # PGcore object @@ -563,13 +564,15 @@ sub PG_restricted_eval { sub decode_base64 ($) { my $self = shift; my $str = shift; - MIME::Base64::decode_base64($str); + $str = MIME::Base64::decode_base64($str); + decode_utf8($str); } sub encode_base64 ($;$) { my $self = shift; my $str = shift; my $option = shift; + $str = encode_utf8($str); MIME::Base64::encode_base64($str); } From 539406cc210c8c6d421f3650797f13e6245e712c Mon Sep 17 00:00:00 2001 From: Geoff Goehle Date: Wed, 17 Aug 2016 16:43:46 -0400 Subject: [PATCH 03/12] picked an ascii character for the verb escape character so that it doesn't interfere with utf8 --- lib/Value/String.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Value/String.pm b/lib/Value/String.pm index 438a10f8b0..bf9022f705 100644 --- a/lib/Value/String.pm +++ b/lib/Value/String.pm @@ -72,7 +72,7 @@ sub compare { # # Mark a string to be display verbatim # -sub verb {shift; return "\\verb".chr(0x85).(shift).chr(0x85)} +sub verb {shift; return "\\verb".chr(0x1F).(shift).chr(0x1F)} # # Put normal strings into \text{} and others into \verb From a561c0e75a0db16ab71bf89818ba421c7bf0d30c Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Mon, 31 Jul 2017 14:04:53 -0400 Subject: [PATCH 04/12] Add additional utf8 related changes to PG files. --- lib/PGcore.pm | 3 ++- lib/PGloadfiles.pm | 2 +- lib/WeBWorK/PG/IO.pm | 4 ++-- lib/WeBWorK/PG/Translator.pm | 8 +++++--- macros/PG.pl | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/PGcore.pm b/lib/PGcore.pm index 7c4f1137f1..198d5e3f04 100755 --- a/lib/PGcore.pm +++ b/lib/PGcore.pm @@ -30,7 +30,8 @@ use WeBWorK::Debug; use MIME::Base64(); use PGUtil(); use Encode qw(encode_utf8 decode_utf8); - +use utf8; +binmode(STDOUT, ":uft8"); ################################## # PGcore object ################################## diff --git a/lib/PGloadfiles.pm b/lib/PGloadfiles.pm index 1445cc734e..a262b75c72 100644 --- a/lib/PGloadfiles.pm +++ b/lib/PGloadfiles.pm @@ -232,7 +232,7 @@ sub compile_file { local($/); $/ = undef; # allows us to treat the file as a single line - open(MACROFILE, "<$filePath") || die "Cannot open file: $filePath"; + open(MACROFILE, "<:utf8", $filePath) || die "Cannot open file: $filePath"; my $string = 'BEGIN {push @__eval__, __FILE__};' . "\n" . ; #warn "compiling $string"; my ($result,$error,$fullerror) = $self->PG_macro_file_eval($string); diff --git a/lib/WeBWorK/PG/IO.pm b/lib/WeBWorK/PG/IO.pm index feecdfa0f8..74ce7251cf 100644 --- a/lib/WeBWorK/PG/IO.pm +++ b/lib/WeBWorK/PG/IO.pm @@ -139,7 +139,7 @@ sub read_whole_file { unless path_is_course_subdir($filePath); local (*INPUT); - open(INPUT, "<:utf8", $filePath) || die "$0: read_whole_file subroutine:
Can't read file $filePath"; + open(INPUT, "<:encoding(utf8)", $filePath) || die "$0: read_whole_file subroutine:
Can't read file $filePath"; local($/)=undef; my $string = ; # can't append spaces because this causes trouble with <<'EOF' \nEOF construction close(INPUT); @@ -201,7 +201,7 @@ sub createFile { die 'Path is unsafe' unless path_is_course_subdir($fileName); - open(TEMPCREATEFILE, ">$fileName") + open(TEMPCREATEFILE, ">:encoding(UTF-8)",$fileName) or die "Can't open $fileName: $!"; my @stat = stat TEMPCREATEFILE; close(TEMPCREATEFILE); diff --git a/lib/WeBWorK/PG/Translator.pm b/lib/WeBWorK/PG/Translator.pm index c3028b3b9f..3fae095d0b 100644 --- a/lib/WeBWorK/PG/Translator.pm +++ b/lib/WeBWorK/PG/Translator.pm @@ -14,7 +14,9 @@ use Net::SMTP; use PGcore; use PGUtil qw(pretty_print); use WeBWorK::PG::IO qw(fileFromPath); - +use utf8; +use v5.12; +binmode(STDOUT,":utf8"); #use PadWalker; # used for processing error messages #use Data::Dumper; @@ -388,7 +390,7 @@ sub pre_load_macro_files { local(*MACROFILE); local($/); $/ = undef; # allows us to treat the file as a single line - open(MACROFILE, "<$filePath") || die "Cannot open file: $filePath"; + open(MACROFILE, "<:encoding(utf8)", $filePath) || die "Cannot open file: $filePath"; my $string = ; close(MACROFILE); @@ -524,7 +526,7 @@ sub source_file { local($/); $/ = undef; # allows us to treat the file as a single line my $err = ""; - if ( open(SOURCEFILE, "<$filePath") ) { + if ( open(SOURCEFILE, "<:encoding(utf8)", $filePath) ) { $self -> {source} = ; close(SOURCEFILE); } else { diff --git a/macros/PG.pl b/macros/PG.pl index b65f163754..bdcafefd81 100644 --- a/macros/PG.pl +++ b/macros/PG.pl @@ -8,7 +8,7 @@ $main::VERSION ="WW2"; sub _PG_init{ - $main::VERSION ="WW2.9+"; + $main::VERSION ="WW2.13"; # # Set up MathObject context for use in problems # that don't load MathObjects.pl From da5d9059269796b263aad4d326e1d9973f0e1b07 Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Fri, 29 Dec 2017 22:41:32 -0500 Subject: [PATCH 05/12] Add new test files for units. Update the definition of parsec to include more accuracy -- it still doesn't pass the test_units.t file. The definition of steradian is still iffy. --- lib/Units.pm | 2 +- t/pg_test_problems/test_units1.pg | 96 +++++++++++++++++++++++++++++++ t/test_units.t | 3 +- 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 t/pg_test_problems/test_units1.pg diff --git a/lib/Units.pm b/lib/Units.pm index 60b6582492..556693f47e 100644 --- a/lib/Units.pm +++ b/lib/Units.pm @@ -283,7 +283,7 @@ our %known_units = ('m' => { 'm' => 1 }, 'parsec' => { - 'factor' => 30.857E15, + 'factor' => 3.08567758149137E16, #30.857E15, 'm' => 1 }, # VOLUME diff --git a/t/pg_test_problems/test_units1.pg b/t/pg_test_problems/test_units1.pg new file mode 100644 index 0000000000..d0db0f0442 --- /dev/null +++ b/t/pg_test_problems/test_units1.pg @@ -0,0 +1,96 @@ +## DESCRIPTION +## Functions: Input and Output + + +## DBsubject(WeBWorK) +## DBchapter(TEST) +## DBsection(Units) +## Date(01/01/10) +## Institution(U of R) +## Author(Gage) +## Level() +## MO(1) + +## KEYWORDS('test','units',) + +DOCUMENT(); + +loadMacros( +"PGstandard.pl", +"MathObjects.pl", +"AnswerFormatHelp.pl", +"PGML.pl", +"parserNumberWithUnits.pl", +"parserFormulaWithUnits.pl", +"PGcourse.pl", +); + +TEXT(beginproblem()); + +################################## +# Setup + +Context("Numeric"); + + +$one_mph = NumberWithUnits(1,"mph"); +$x2_mph = FormulaWithUnits("x^2", "mph"); + +$hz_0_05 = NumberWithUnits(.05, "Hz"); +$five_percent_per_second = NumberWithUnits(5, "%/s"); +$five_percent = NumberWithUnits(5, "%"); +$one_degree = NumberWithUnits(1, "deg"); +$one_radian = NumberWithUnits(1, "rad"); +$one_hour = NumberWithUnits(1,"hours"); +$one_inch = NumberWithUnits(1,"inches"); +$one_foot = NumberWithUnits(1,"feet"); +$one_minute = NumberWithUnits(1,"minute"); +$one_second = NumberWithUnits(1,"s"); #only s works +$one_cup = NumberWithUnits(.236588 ,"L"); +$one_footpersecond = NumberWithUnits(1,"feet/s"); +$x2_footpersecond = FormulaWithUnits("x^2","feet/s"); + + +##################################### +# Main text + +Context()->texStrings; +BEGIN_PGML +These units are equivalent: +* deg, degree, degrees +* rad, radian, radians, +* in, inch, inches +* ft, feet, foot +* min, minute, minutes +* h, hr, hour, hours +* s, sec,?? +* cup, cups, 0.000236588 m^3 or .236588 L + + +* sr ( steradian or square radian a measure of solid angle. 1 sr = rad^2 ?) The actual definition is the central solid angle of a patch on a sphere of radius r whose area is r^2. A full sphere measures 4pi steradian's. + +The definition here is 1 sr = 1 rad^2 --- is that really right? + +TESTS: + +These should be equivalent: +* Enter .05 Hz in %/s [_________]{$hz_0_05} as [`5*2\pi %*rad/s`] +* Enter 5 %/s as Hz [__________]{$five_percent_per_second} as[`.05/(2pi) Hz/rad`] +* Enter 5 % as [__________]{$five_percent} as [`.05 rad/rad`] +* Enter 1 mph [__________]{$one_mph} as 5280 ft/hr +* Enter x^2 mph [__________]{$x2_mph} + +* Enter one degree: [__________]{$one_degree} +* Enter one radian: [__________]{$one_radian} as [`(2\pi)^-1 cycles`] +* Enter one hour: [__________]{$one_hour} +* Enter one inch: [__________]{$one_inch} +* Enter one foot: [__________]{$one_foot} +* Enter one minute: [__________]{$one_minute} +* Enter one second: [__________]{$one_second} +* Enter one cup: [__________]{$one_cup} +* Enter one ft/sec [__________]{$one_footpersecond} +* [`x^2`] ft/sec [__________]{$x2_footpersecond} +END_PGML + + +ENDDOCUMENT(); \ No newline at end of file diff --git a/t/test_units.t b/t/test_units.t index 76d6d0ecce..605dcfdd8c 100755 --- a/t/test_units.t +++ b/t/test_units.t @@ -5,6 +5,7 @@ #use Test::More tests => 5; use Test::More qw( no_plan ); use lib "../lib"; # location of Units.pm module +use lib "lib"; # location of Units.pm module we run perl t/test_units.t BEGIN { use_ok('Units'); @@ -67,7 +68,7 @@ is_deeply( {evaluate_units('c*yr')}, {evaluate_units('light-year')}, 'light year is_deeply( multiply_by((180/$Units::PI)**2, evaluate_units('deg^2')), {evaluate_units('sr')}, 'solid angle conversion'); -is_deeply( multiply_by(0.01), {evaluate_units('%')}, 'percent conversion'); +is_deeply( multiply_by(0.01,evaluate_units('rad/rad')), {evaluate_units('%')}, 'percent conversion'); } From f121ef49979f007e7aca2275f6d82ee6f4979d7d Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sat, 30 Dec 2017 08:51:47 -0500 Subject: [PATCH 06/12] Add test for inverting matrix (#331) --- t/pg_test_problems/matrix_inverse.pg | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 t/pg_test_problems/matrix_inverse.pg diff --git a/t/pg_test_problems/matrix_inverse.pg b/t/pg_test_problems/matrix_inverse.pg new file mode 100644 index 0000000000..268bc914da --- /dev/null +++ b/t/pg_test_problems/matrix_inverse.pg @@ -0,0 +1,69 @@ +##DESCRIPTION +## +## +## +##ENDDESCRIPTION +## +## +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGstandard.pl", # Standard macros for PG language + "MathObjects.pl", + "PGML.pl", + #"source.pl", # used to display problem source button + "PGcourse.pl", # Customization file for the course +); + +TEXT(beginproblem()); +$showPartialCorrectAnswers = 1; + +############################################################## +############################################################### +# Setup +# # +# ## +## Context("Numeric"); + +############################################################## +############################################################### +# Text +# # +# ## +# ## +Context("Matrix"); +Context()->constants->add(A=>Matrix([1,2],[3,4])); +Context()->variables->add(M=>Matrix([1,2],[3,4])); +TEXT(Formula("A^(-1)")->reduce,$BR); +TEXT(Formula("M^(-1)")->reduce,$BR); +TEXT(Formula("[[x,2],[3,x]]^(-1)")->reduce,$BR); +TEXT(Formula("x^(-1)")->reduce,$BR); +TEXT(Formula("x^(-2)")->reduce,$BR); + +BEGIN_PGML +Without the patch, the first three reductions will produce an error about only being able +to divide by a number. With the patch, all three should succeed, and you should get + +* A^(-1) +* M^(-1) +* [`[[x,2],[3,x]]^{(-1)}`] +* 1/x +* 1/(x^2) + +as the output. + +Note that this does change the name of the reduction rule from x^(-1) to x^(-a). I've +checked the macro files and the OPL and don't see any uses of reduction rule x^(-1), so I +think this should not be a problem (though some Wiki pages may need to be updated). + + +END_PGML +############################################################## +############################################################### +# Answers +# # +# ## +# ## +# ## +# ## +ENDDOCUMENT(); # This should be the last executable line in the problem. \ No newline at end of file From b873d7e5ab2266aff770dac010ba16bf524f24f5 Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sat, 30 Dec 2017 09:37:04 -0500 Subject: [PATCH 07/12] Cosmetic changes --- t/pg_test_problems/matrix_inverse.pg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/t/pg_test_problems/matrix_inverse.pg b/t/pg_test_problems/matrix_inverse.pg index 268bc914da..af0af40031 100644 --- a/t/pg_test_problems/matrix_inverse.pg +++ b/t/pg_test_problems/matrix_inverse.pg @@ -56,9 +56,10 @@ Note that this does change the name of the reduction rule from x^(-1) to x^(-a). checked the macro files and the OPL and don't see any uses of reduction rule x^(-1), so I think this should not be a problem (though some Wiki pages may need to be updated). - +------------ END_PGML -############################################################## + +############################################################# ############################################################### # Answers # # From e1982604ba5af65aa79a4f61a47f53fe5eac76c3 Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sat, 30 Dec 2017 09:52:14 -0500 Subject: [PATCH 08/12] add test for error messages -- you need to comment out some error causing statements to see the next error. --- t/pg_test_problems/matrix_inverse2.pg | 83 +++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 t/pg_test_problems/matrix_inverse2.pg diff --git a/t/pg_test_problems/matrix_inverse2.pg b/t/pg_test_problems/matrix_inverse2.pg new file mode 100644 index 0000000000..b59571e199 --- /dev/null +++ b/t/pg_test_problems/matrix_inverse2.pg @@ -0,0 +1,83 @@ +##DESCRIPTION + + + +##ENDDESCRIPTION + + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( + "PGstandard.pl", # Standard macros for PG language + "MathObjects.pl", + "PGML.pl", + #"source.pl", # used to display problem source button + "PGcourse.pl", # Customization file for the course +); + +TEXT(beginproblem()); +$showPartialCorrectAnswers = 1; + +############################################################## +# +# Setup +# +# +Context("Numeric"); + +############################################################## +# +# Text +# +# + +Context("Matrix"); +Context()->constants->add( + A => Matrix([[1,2,3],[4,5,6]]), + B => Matrix([0,0],[0,0]), +); +Context()->variables->add( + M => Matrix([[1,2,3],[4,5,6]]), + N => Matrix([[1,2],[3,4]]), +); + +#Formula("A^(-1)"); +#Formula("M^(-1)"); +#Formula("[[1,2,3],[4,5,x]]^(-1)"); +#Formula("[[1,2,3],[4,5,6]]^(-1)"); + +#Formula("B^(-1)")->eval; +#Formula("N^(-1)")->eval(N => Matrix([[0,0],[0,0]])); +#Formula("[[0,0],[0,0]]^(-1)"); +#Formula("[[x,0],[0,x]]^(-1)")->eval(x => 0); +#Matrix([[0,0],[0,0]]) ** -1; + +Matrix([[0,0],[0,0]])->inverse; +Matrix([[0,0],[0,0]])->solve_LR(Vector(1,1)); + + +BEGIN_PGML +Without the patch, the first four should produce errors +about 2x3 and 2x3 matrixes not being able to be multiplied, +while the next five and final two should produce errors +about matrices needing at least one entry. + +With the patch, the first four should produce messages +that only a square matrix can be inverted, the next +five should say that the matrix is not invertible, +and the last two should produce an undefined value +and a list of three undefined values, respectively. + + +END_PGML +# + +############################################################## +# +# Answers +# +# + + + +ENDDOCUMENT(); # This should be the last executable line in the problem. \ No newline at end of file From 9575b1f15044acf77d454d8cd2f08ef9357caaf8 Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Sat, 30 Dec 2017 11:39:51 -0500 Subject: [PATCH 09/12] Add two test files for chemical reactions. (PR #334) --- t/pg_test_problems/chem_react1.pg | 57 +++++++++++++++++++++++++++++++ t/pg_test_problems/chem_react2.pg | 56 ++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 t/pg_test_problems/chem_react1.pg create mode 100644 t/pg_test_problems/chem_react2.pg diff --git a/t/pg_test_problems/chem_react1.pg b/t/pg_test_problems/chem_react1.pg new file mode 100644 index 0000000000..9fe95de5e6 --- /dev/null +++ b/t/pg_test_problems/chem_react1.pg @@ -0,0 +1,57 @@ +DOCUMENT(); +loadMacros( +"PGstandard.pl", +"MathObjects.pl", +"contextReaction.pl" +); +# +# +TEXT(&beginproblem); +# +$showPartialCorrectAnswers = 1; +Context("Reaction"); +# +$named_reactants ="Silver nitrate + Sodium chloride"; +$named_products = "Silver chloride + Sodium nitrate"; +# +# ID react, prod for complete molecular, total ionic, and net ionic equations. +# +$COMPLETE_REACTION=Formula("AgNO_{3} (aq) + NaCl (aq) --> AgCl (s) + NaNO_{3} (aq)"); +# +$TOTAL_IONIC = Formula("Ag^{+1}(aq) + NO_{3}^{-1}(aq) + Na^{+1}(aq) + Cl^{-1}(aq) --> AgCl(s)+Na^{+1}(aq) + NO_{3}^{-1}(aq)"); +# +$NET_IONIC=Formula("Ag^{+1}(aq) + Cl^{-1}(aq) --> AgCl(s)"); +# +COMMENT("Reaction arrow is --> NOTE: two dashes and >. Charges for ions should be entered +1, +2, -1, -2, etc. Note the order and the 1 for the + and - cases"); +Context()->texStrings; +BEGIN_TEXT +$BBOLD Answers should be entered using guidlines discussed in lecture. $EBOLD $BR +Consider the reaction shown below.$BR +$named_reactants \(\longrightarrow\) $named_products $BR +Write the complete molecular reaction equation.$BR +\{ans_rule(60)\}$BR +Write the total ionic equation.$BR +\{ans_rule(60)\}$BR +Write the net ionic equation for the reaction.$BR +\{ans_rule(60)\} +END_TEXT + +BEGIN_TEXT + +Solutions: +\($COMPLETE_REACTION\) +$PAR +\($TOTAL_IONIC\) +$PAR +\($NET_IONIC\) + +END_TEXT + +Context()->normalStrings; + +# +ANS($COMPLETE_REACTION->cmp); +ANS($TOTAL_IONIC->cmp); +ANS($NET_IONIC->cmp); +# +ENDDOCUMENT(); \ No newline at end of file diff --git a/t/pg_test_problems/chem_react2.pg b/t/pg_test_problems/chem_react2.pg new file mode 100644 index 0000000000..5e2bba3fb5 --- /dev/null +++ b/t/pg_test_problems/chem_react2.pg @@ -0,0 +1,56 @@ +DOCUMENT(); +loadMacros( +"PGstandard.pl", +"MathObjects.pl", +"contextReaction.pl" +); +# +# +TEXT(&beginproblem); +# +$showPartialCorrectAnswers = 1; +Context("Reaction"); +Context()->variables->add('e' => $context::Reaction::ELEMENT); +# +$named_reactants ="Zinc + Copper(II) sulfate"; +$named_products = "Zinc sulfate + Copper"; +# +$COMPLETE_REACTION=Formula("Zn(s) + CuSO_{4}(aq) --> ZnSO_{4}(aq) + Cu(s)"); +# +$OXIDATION = Formula("Zn(s) --> Zn^{+2} + 2e^{-1}"); +# +$REDUCTION=Formula("Cu^{+2} + 2e^{-1} --> Cu(s)"); +# +COMMENT("Reaction arrow is --> NOTE: two dashes and >. Charges for ions should be entered +1, +2, -1, -2, etc. Note the order and the 1 for the + and - cases. Electrons are added as e^{-1}"); +Context()->texStrings; +BEGIN_TEXT +$BBOLD Answers should be entered using guidlines discussed in lecture. $EBOLD $BR +Consider the reaction shown below.$BR +$named_reactants \(\longrightarrow\) $named_products $BR +Write the complete molecular reaction equation.$BR +\{ans_rule(60)\}$BR +Write the oxidation half-reaction.$BR +\{ans_rule(60)\}$BR +Write the reduction half-reaction.$BR +\{ans_rule(60)\} +END_TEXT + +BEGIN_TEXT + +Solutions: +\($COMPLETE_REACTION\) +$PAR +\($OXIDATION\) +$PAR +\($REDUCTION\) + +END_TEXT + +Context()->normalStrings; + +# +ANS($COMPLETE_REACTION->cmp); +ANS($OXIDATION->cmp); +ANS($REDUCTION->cmp); +# +ENDDOCUMENT(); \ No newline at end of file From e904c9d11f406ed2816f91c3154ed8928472b1da Mon Sep 17 00:00:00 2001 From: Michael Gage Date: Mon, 1 Jan 2018 20:06:52 -0500 Subject: [PATCH 10/12] Add PG problem with arabic characters for testing This can be used to test utf8 coverage as well as the template math4_ar which has right justification and is a preliminary stab at creating a template suitable for arabic PG problems. --- t/pg_test_problems/arabic_test.pg | 83 +++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 t/pg_test_problems/arabic_test.pg diff --git a/t/pg_test_problems/arabic_test.pg b/t/pg_test_problems/arabic_test.pg new file mode 100644 index 0000000000..a16001f13c --- /dev/null +++ b/t/pg_test_problems/arabic_test.pg @@ -0,0 +1,83 @@ +## Translator(Kamal Saleh) +## DESCRIPTION +## Linear Algebra +## ENDDESCRIPTION + +## Tagged by tda2d + +## DBsubject(Lineare Algebra) +## DBchapter(Lineare Gleichungssysteme) +## DBsection(Matrix-Vektor-Form) +## Date(July 2013) +## Institution(TCNJ and Hope College) +## Author(Paul Pearson) +## Level(4) +## MO(1) +## KEYWORDS('matrix' 'equation') + + +## Comments from Mike Gage +## This problem won't render correctly until all of the utf8 changes are in place +## It's a good test for utf8. + +## This problem should be rendered using the math4-ar template as a test of whether +## the right to left format is working properly for rendering arabic (or hebrew). + +DOCUMENT(); # This should be the first executable line in the problem. + +loadMacros( +"PGstandard.pl", +"MathObjects.pl", +"PGcourse.pl", +); + +TEXT(beginproblem()); +$showPartialCorrectAnswers = 1; + +Context('Matrix'); + +foreach $i (1..2) { + $u[$i] = non_zero_random(-5,5,1); + $v[$i] = non_zero_random(-5,5,1); +} +$m = random(-1,1,2) * random(2,5,1); +$n = random(-1,1,2) * random(2,5,1); + +$U = Matrix([[$u[1]], [$u[2]]]); +$V = Matrix([[$v[1]], [$v[2]]]); + +$answer = Matrix([ $m*$u[1]+$n*$v[1], $m*$u[2]+$n*$v[2] ])->transpose; + +Context()->texStrings; +BEGIN_TEXT +لتكن +\( A \) + مصفوفة تطبيق خطي أبعادها +\( 3 \times 2 \) +و أعمدتها مستقلة خطياًًًََُ ً +. +ليكن +\( \vec{u} = $U \) +و +\( \vec{v} = $V \) +شعاعين يحققان المعادلتين +\( A\vec{u} = \vec{a} \) +و +\( A\vec{v} = \vec{b} \) +. +أوجد حل +\( \vec{x} \) +للمعادلة +\( A\vec{x} = $m \vec{a} + $n \vec{b} \). +$BR +$BR +$BLTR +\(\vec{x} = \) \{ $answer->ans_array(20) \} +$ELTR +. +END_TEXT +Context()->normalStrings; + +ANS($answer->cmp); +; +ENDDOCUMENT(); From 414b3569d63bb4e6c28b801ffc993d583d6af0d1 Mon Sep 17 00:00:00 2001 From: Nathan Wallach Date: Wed, 9 May 2018 17:11:30 +0300 Subject: [PATCH 11/12] Added functions SET_PROBLEM_LANGUAGE() SET_PROBLEM_TEXTDIRECTION() which create records in PG->{flags} with settings which will influence the HTML lang and dir attributes set for the HTML element containing the problem. This allows proper detection of the language of the problem in the browser, when it is not the primary course language, and to override the direction for cases when a LTR problem is being viewed/assigned in a course in a RTL course, or visa-versa. The flag values set in the problem are processed in the subroutine output_problem_lang_and_dir() in webwork2/lib/WeBWorK/ContentGenerator/Problem.pm if there is no override set in the course configuration. --- macros/PG.pl | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/macros/PG.pl b/macros/PG.pl index b36e3f617e..156f02ba48 100644 --- a/macros/PG.pl +++ b/macros/PG.pl @@ -142,6 +142,62 @@ sub POST_HEADER_TEXT { $PG->POST_HEADER_TEXT(@_); } +# We expect valid HTML language codes, but there can also include a region code, or other +# settings. +# See https://www.w3.org/International/questions/qa-choosing-language-tags +# Example settings: en-US, en-UK, he-IL +# Some special language codes (zh-Hans) are longer +# http://www.rfc-editor.org/rfc/bcp/bcp47.txt +# https://www.w3.org/International/articles/language-tags/ +# https://www.w3.org/International/questions/qa-lang-2or3.en.html +# http://www.iana.org/assignments/language-subtag-registry/language-subtag-registry +# https://www.w3schools.com/tags/ref_language_codes.asp +# https://www.w3schools.com/tags/ref_country_codes.asp +# Tester at https://r12a.github.io/app-subtags/ + +sub SET_PROBLEM_LANGUAGE { + my $requested_lang = shift; + + # Clean it up for safety + my $selected_lang = $requested_lang; + $selected_lang =~ s/[^a-zA-Z0-9-]//g ; # Drop any characters not permitted. + + if ( $selected_lang ne $requested_lang ) { + warn "PROBLEM_LANGUAGE was edited. Requested: $requested_lang which was replaced by $selected_lang"; + } + $PG->{flags}->{"language"} = $selected_lang; +} + +# SET_PROBLEM_TEXTDIRECTION to set the HTML DIRection attribute to be applied +# to the DIV element containing this problem. + +# We only permit valid settings for the HTML direction attribute: +# dir="ltr|rtl|auto" +# https://www.w3schools.com/tags/att_global_dir.asp + +# It is likely that only problems written in RTL scripts +# will need to call the following function to set the base text direction +# for the problem. + +# Note the flag may not be set, and then webwork2 will use default behavior. + +sub SET_PROBLEM_TEXTDIRECTION { + my $requested_dir = shift; + + # Only allow valid values: + + if ( $requested_dir =~ /^ltr$/i ) { + $PG->{flags}->{"textdirection"} = "ltr"; + } elsif ( $requested_dir =~ /^rtl$/i ) { + $PG->{flags}->{"textdirection"} = "trl"; + } elsif ( $requested_dir =~ /^auto$/i ) { + $PG->{flags}->{"textdirection"} = "auto"; # NOT RECOMMENDED + } else { + warn " INVALID setting for PROBLEM_TEXTDIRECTION: $requested_dir was DROPPED."; + } +} + + sub AskSage { my $python = shift; my $options = shift; From 67fcefcc2de85e6518a7db52997d703383873435 Mon Sep 17 00:00:00 2001 From: Nathan Wallach Date: Wed, 9 May 2018 20:58:54 +0300 Subject: [PATCH 12/12] Added SET_PROBLEM_LANGUAGE() SET_PROBLEM_TEXTDIRECTION() functions which set flags for the problem language and textdirection which can be accessed inside the webwork2 code to allow using this data to set the HTML lang and dir tags as needed on DIV elements which envelop the problem text. --- macros/PG.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/PG.pl b/macros/PG.pl index 156f02ba48..3b96047001 100644 --- a/macros/PG.pl +++ b/macros/PG.pl @@ -189,7 +189,7 @@ sub SET_PROBLEM_TEXTDIRECTION { if ( $requested_dir =~ /^ltr$/i ) { $PG->{flags}->{"textdirection"} = "ltr"; } elsif ( $requested_dir =~ /^rtl$/i ) { - $PG->{flags}->{"textdirection"} = "trl"; + $PG->{flags}->{"textdirection"} = "rtl"; } elsif ( $requested_dir =~ /^auto$/i ) { $PG->{flags}->{"textdirection"} = "auto"; # NOT RECOMMENDED } else {