diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 210c0555a2..2c372d5c0a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username -custom: ["https://webwork.maa.org/wiki"] +custom: ['https://wiki.openwebwork.org/wiki'] diff --git a/LICENSE b/LICENSE index 821f53097f..57b471950a 100644 --- a/LICENSE +++ b/LICENSE @@ -13,19 +13,19 @@ Software Foundation; either version 2, or (at your option) any later version, or - b) the "Artistic License" which comes with this package. + b) the "Artistic License" 1.0 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. - You should have received a copy of the Artistic License with this - package, in the file named "Artistic" inside the `doc` folder. If not, we'll be glad to provide - one. + You should have received a copy of the Artistic License 1.0 with this + package, in the file named "Artistic" inside the `doc` folder. If not, + you can find a copy at https://github.com/openwebwork/webwork2/blob/main/doc/Artistic + or https://perlfoundation.org/artistic-license-10.html. You should also have received a copy of the GNU General Public License - along with this program in the file named "Copying" inside the `doc` folder. If not, write to the - Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307, USA or visit their web page on the internet at - http://www.gnu.org/copyleft/gpl.html. + along with this program in the file named "Copying" inside the `doc` folder. + If not, you can find a copy at https://github.com/openwebwork/webwork2/blob/main/doc/Copying + or https://www.gnu.org/licenses/old-licenses/gpl-2.0.html. diff --git a/README.md b/README.md index db8e9a149c..7d213d39db 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,35 @@ - WeBWorK - Online Homework Delivery System - Version 2.* - Branch: github.com/openwebwork - - https://webwork.maa.org/wiki/Release_notes_for_WeBWorK_2.20 - Copyright 2000-2025, The WeBWorK Project - https://openwebwork.org/ - All rights reserved. - # Welcome to WeBWorK -WeBWorK is an open-source online homework system for math and sciences courses. WeBWorK is supported by the MAA and the NSF and comes with an Open Problem Library (OPL) of over 30,000 homework problems. Problems in the OPL target most lower division undergraduate math courses, some advanced courses and some other STEM subjects. Supported courses include college algebra, discrete mathematics, probability and statistics, single and multivariable calculus, differential equations, linear algebra and complex analysis. Find out more at the main WeBWorK [webpage](https://openwebwork.org). +WeBWorK is an open-source online homework system for math and sciences courses. WeBWorK is supported by the MAA and the +NSF and comes with an Open Problem Library (OPL) of over 30,000 homework problems. Problems in the OPL target most lower +division undergraduate math courses, some advanced courses and some other STEM subjects. Supported courses include +college algebra, discrete mathematics, probability and statistics, single and multivariable calculus, differential +equations, linear algebra and complex analysis. Find out more at the main WeBWorK [webpage](https://openwebwork.org). ## Information for Users -New users interested in getting started with their own WeBWorK server, or instructors looking to learn more about how to use WeBWorK in their classes, should take a look at one of the following resources: +New users interested in getting started with their own WeBWorK server, or instructors looking to learn more about how to +use WeBWorK in their classes, should take a look at one of the following resources: -* The [WeBWorK project home page](https://openwebwork.org/) - General information and resources including announcements of events and important project news -* [WeBWorK wiki](https://webwork.maa.org/wiki/Main_Page) - The main WeBWorK wiki -* [Installing WeBWorK](https://webwork.maa.org/wiki/Manual_Installation_Guides) - Installing WeBWorK -* [Instructors](https://webwork.maa.org/wiki/Instructors) - Information for Instructors -* [Problem Authors](https://webwork.maa.org/wiki/Authors) - Information for Problem Authors -* [Forum](http://webwork.maa.org/moodle/mod/forum/index.php?id=3) - The WeBWorK Forum for getting help from the community -* [Frequently Asked Questions](https://github.com/openwebwork/webwork2/wiki/Frequently-Asked-Questions) - A list of frequently asked questions. +- The [WeBWorK project home page](https://openwebwork.org/) - General information and resources including announcements + of events and important project news +- [WeBWorK wiki](https://wiki.openwebwork.org/wiki/Main_Page) - The main WeBWorK wiki +- [Installing WeBWorK](https://wiki.openwebwork.org/wiki/Manual_Installation_Guides) - Installing WeBWorK +- [Instructors](https://wiki.openwebwork.org/wiki/Instructors) - Information for Instructors +- [Problem Authors](https://wiki.openwebwork.org/wiki/Authors) - Information for Problem Authors +- [Forum](https://forums.openwebwork.org/mod/forum/index.php?id=3) - The WeBWorK Forum for getting help from the + community +- [Frequently Asked Questions](https://github.com/openwebwork/webwork2/wiki/Frequently-Asked-Questions) - A list of + frequently asked questions. ## Information for Downloading -* Installation manuals can be found at https://webwork.maa.org/wiki/Category:Installation_Manuals +- See the [installation manuals](https://wiki.openwebwork.org/wiki/Category:Installation_Manuals). ## Information For Developers -* People interested in developing new features for WeBWorK can start at https://webwork.maa.org/wiki/Category:Developers, or start a [discussion on GitHub](https://github.com/openwebwork/webwork2/discussions) to engage with the current developers. -* People interested in developing new problems for WeBWorK should visit [Problem Authors](http://webwork.maa.org/wiki/Authors). +- People interested in developing new features for WeBWorK can start at the wiki + [development page](https://wiki.openwebwork.org/wiki/Category:Developers), or start a + [discussion on GitHub](https://github.com/openwebwork/webwork2/discussions) to engage with the current developers. +- People interested in developing new problems for WeBWorK should visit the wiki + [problem authoring page](https://wiki.openwebwork.org/wiki/Authors). diff --git a/VERSION b/VERSION index 450fad3c87..0fd2da8154 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ -$WW_VERSION = '2.20'; +$WW_VERSION = '2.20+develop'; $WW_COPYRIGHT_YEARS = '1996-2025'; 1; diff --git a/assets/hardcopyThemes/basic.xml b/assets/hardcopyThemes/basic.xml index 46b8b8f7ab..34a859df84 100644 --- a/assets/hardcopyThemes/basic.xml +++ b/assets/hardcopyThemes/basic.xml @@ -3,7 +3,7 @@ This theme produces hardcopies with minimal page headers displaying the set -title and useername, and minimal problem numbering. +title and username, and minimal problem numbering. diff --git a/assets/hardcopyThemes/basicTwoCol.xml b/assets/hardcopyThemes/basicTwoCol.xml index ccb11b0dc9..44b1a455ee 100644 --- a/assets/hardcopyThemes/basicTwoCol.xml +++ b/assets/hardcopyThemes/basicTwoCol.xml @@ -3,7 +3,7 @@ This theme produces hardcopies with minimal page headers displaying the set -title and useername, and minimal problem numbering. With two columns. +title and username, and minimal problem numbering. With two columns. diff --git a/assets/pg/PGMLLab/PGML-lab.pg b/assets/pg/PGMLLab/PGML-lab.pg index b58c76614c..931fe40867 100644 --- a/assets/pg/PGMLLab/PGML-lab.pg +++ b/assets/pg/PGMLLab/PGML-lab.pg @@ -682,9 +682,9 @@ TEXT(tag( >> At the right >> Several lines combined. - >> right justfied + >> right justified - >> Or a whole paragaph + >> Or a whole paragraph that is pushed to the right >> Or two lines diff --git a/assets/pg/Student_Orientation/explorerfull.png b/assets/pg/Student_Orientation/explorerfull.png index 6b52703fcc..c791cefdaf 100644 Binary files a/assets/pg/Student_Orientation/explorerfull.png and b/assets/pg/Student_Orientation/explorerfull.png differ diff --git a/assets/pg/Student_Orientation/explorerpiece.png b/assets/pg/Student_Orientation/explorerpiece.png index a4fb755b36..c47d879cb7 100644 Binary files a/assets/pg/Student_Orientation/explorerpiece.png and b/assets/pg/Student_Orientation/explorerpiece.png differ diff --git a/assets/pg/Student_Orientation/mathInteraction.pg b/assets/pg/Student_Orientation/mathInteraction.pg index 3cf56a7111..f8f0c11fc5 100644 --- a/assets/pg/Student_Orientation/mathInteraction.pg +++ b/assets/pg/Student_Orientation/mathInteraction.pg @@ -26,7 +26,7 @@ Once focus is on a math expression, using the space bar will activate the "MathJ by right-clicking (Windows/Linux) or [|control|]*-clicking (MacOS) a piece of math. Try activating the MathJax menu now. It should look like the following. ->> [!MathJax contextual menu!]{'mathjaxmenu.png'} << +>> [!MathJax contextual menu!]{'mathjaxmenu.png'}{140} << There are many features that help you to engage with math content. Explore the menu options to survey what is available. @@ -36,9 +36,9 @@ vision disabilities see the content better. And it may help all users to see som a moment to explore these settings and select options that you would be comfortable with. (Of course you can change these settings at any time.) -Also in the main menu, there is an "Accessibility" submenu. In that menu, if accessibility is not already activated, -select "Activate". After activating this, you may need to refresh the web page to see the math expression again. Now you -have the option to see math content verbalized. To do this, place focus onto a math expression and hit [|enter|]*. +Also in the main menu, there is an "Accessibility" submenu. Accessibility is enabled by default, but you can also select +"Show Subtitles" in the "Speech" submenu. This allows you to see math content verbalized. To do this, place focus onto +a math expression and hit [|enter|]*. * At first, the entire expression is highlighted and there will be a verbal rendering of the expression. [!Speech string for the quadratic formula!]{'explorerfull.png'}{600} * Use the down arrow to navigate "down" into a smaller piece of the math expression. @@ -47,16 +47,16 @@ have the option to see math content verbalized. To do this, place focus onto a m you can see a verbalization for just this part of the expression above: [!Speech string for the radicand of the quadratic formula!]{'explorerpiece.png'}{600} * Return to the MathJax menu, Accessibility submenu, to explore options for how this explorer tool works. -* Under "Speech" you will find options to use MathSpeak, ClearSpeak, or ChromeVox rules. The default is to use -"MathSpeak verbose" rules, which try try to read math "literally" without context. For example, it reads [`(1,3)`] as -"left parenthesis 1 comma 3 right parenthesis". Other speech rules can produce more meaningful verbal renderings. For -example with the right ClearSpeak settings, the same math expression produces "the point with coordinates 1 comma 3" -or "the interval from 1 to 3 not including 1 or 3". +* Under "Speech" you will find options for MathSpeak and ClearSpeak rules. The default is to use "MathSpeak verbose" +rules, which try try to read math "literally" without context. For example, it reads [`(1,3)`] as "left parenthesis 1 +comma 3 right parenthesis". Other speech rules can produce more meaningful verbal renderings. For example with the right +ClearSpeak settings, the same math expression produces "the point with coordinates 1 comma 3" or "the interval from 1 to +3 not including 1 or 3". Some keyboard-navigating users might find it undesirable for each piece of math content to be tab-indexed. If this is -the case, then in the "Accessibility" sub menu you can uncheck "Include in Tab Order". Just note that in order to undo -this and make math content tabbable again, you will need to access the menu, and so you will need some way other than -tabbing to bring focus back to a piece of math content. +the case, then in the "Options" sub menu of the "Accessibility" submenu you can uncheck "Include in Tab Order" and +"Semantic Enrichment". Just note that in order to undo this and make math content tabbable again, you will need to +access the menu, and so you will need some way other than tabbing to bring focus back to a piece of math content. END_BODY $images = <dirname->dirname->to_string; @@ -51,7 +51,9 @@ my $latex_cmd = . shell_quote($ce->{webworkDirs}{assetsTex}) . ':' . shell_quote($ce->{pg}{directories}{assetsTex}) . ': ' . $ce->{externalPrograms}{latex2pdf} - . ' -interaction nonstopmode check_latex_exam.tex >> check_latex.nfo 2>&1'; + . ' -interaction nonstopmode check_latex_exam.tex >> check_latex.nfo 2>&1 &&' + . "TEXINPUTS=$ENV{WEBWORK_ROOT}/bin: $ce->{externalPrograms}{latex2pdf}" + . ' -interaction nonstopmode check_latex_standalone.tex > check_latex.nfo 2>&1'; if ((system $latex_cmd) >> 8) { if (open(my $fh, '<', "$temp_dir/check_latex.nfo")) { diff --git a/bin/check_latex_article.tex b/bin/check_latex_article.tex index 76036857ee..21d58de3e6 100644 --- a/bin/check_latex_article.tex +++ b/bin/check_latex_article.tex @@ -8,7 +8,7 @@ \usepackage{multicol} \usepackage{tcolorbox} -\usepackage[active,textmath,displaymath]{preview} % needed for dvipng +\usepackage[textmath,displaymath]{preview} % needed for dvipng \setlength{\columnsep}{.25in} \setlength{\columnseprule}{.4pt} diff --git a/bin/check_latex_exam.tex b/bin/check_latex_exam.tex index bd48c01ef5..384a8ba693 100644 --- a/bin/check_latex_exam.tex +++ b/bin/check_latex_exam.tex @@ -9,7 +9,7 @@ \usepackage{bidi} \fi -\usepackage[active,textmath,displaymath]{preview} % needed for dvipng +\usepackage[textmath,displaymath]{preview} % needed for dvipng \setlength{\columnsep}{.25in} \setlength{\columnseprule}{.4pt} diff --git a/bin/check_latex_standalone.tex b/bin/check_latex_standalone.tex new file mode 100644 index 0000000000..7f8daeecd6 --- /dev/null +++ b/bin/check_latex_standalone.tex @@ -0,0 +1,22 @@ +\documentclass{standalone} + +\usepackage[svgnames]{xcolor} +\usepackage{tikz} +\usepackage{pgfplots} +\usetikzlibrary{arrows.meta,plotmarks,calc,spath3} +\usepgfplotslibrary{fillbetween} +\pgfplotsset{compat = 1.18} + +\begin{document} + +\begin{tikzpicture} + \begin{axis} + \addplot[name path=pathA, domain=-3:3, draw=none, mark=triangle*] {(x^2)}; + \draw[{Stealth}-{Stealth}, spath/use=pathA]; + \draw ($(-1, 0) + (10pt, 10pt)$) -- ($(1, 3) - (10pt, 10pt)$); + \addplot[name path=pathB, domain=-3:3] {(-x^2 + 3)}; + \addplot[green, fill opacity=0.3] fill between[of=pathA and pathB]; + \end{axis} +\end{tikzpicture} + +\end{document} diff --git a/bin/check_modules.pl b/bin/check_modules.pl index 3b73cee2bf..e13ebfaa68 100755 --- a/bin/check_modules.pl +++ b/bin/check_modules.pl @@ -9,9 +9,37 @@ =head1 SYNOPSIS check_modules.pl [options] - Options: - -m|--modules Check that the perl modules needed by webwork2 can be loaded. - -p|--programs Check that the programs needed by webwork2 exist. +Options: + +=over 4 + +=item C<-m|--modules> + +Check that the perl modules needed by webwork2 can be loaded. + +=item C<-p|--programs> + +Check that the programs needed by webwork2 exist. + +=item C<-d|--distribution> + +Specify your linux distribution. Currently supported options are + +=over 4 + +=item C + +Tested on ubuntu 24. May work for other distributions using the apt package +manager + +=item C + +For RedHat Enterprise Linux and equivalents with the EPEL and CodeReady +Builder repositories enabled (e.g. Rocky Linux, Oracle Linux) + +=back + +=back Both programs and modules are checked if no options are given. @@ -30,98 +58,495 @@ =head1 DESCRIPTION use Getopt::Long qw(:config bundling); use Pod::Usage; -my @modulesList = qw( - Archive::Tar - Archive::Zip - Archive::Zip::SimpleZip - Benchmark - Carp - Class::Accessor - Crypt::JWT - Crypt::PK::RSA - Data::Dump - Data::Dumper - Data::Structure::Util - Data::UUID - Date::Format - Date::Parse - DateTime - DBI - Digest::MD5 - Digest::SHA - Email::Address::XS - Email::Sender::Transport::SMTP - Email::Stuffer - Errno - Exception::Class - File::Copy - File::Copy::Recursive - File::Fetch - File::Find - File::Find::Rule - File::Path - File::Spec - File::stat - File::Temp - Future::AsyncAwait - GD - GD::Barcode::QRcode - Getopt::Long - Getopt::Std - HTML::Entities - HTTP::Async - IO::File - Iterator - Iterator::Util - Locale::Maketext::Lexicon - Locale::Maketext::Simple - LWP::Protocol::https - MIME::Base32 - MIME::Base64 - Math::Random::Secure - Minion - Minion::Backend::SQLite - Mojolicious - Mojolicious::Plugin::NotYAMLConfig - Mojolicious::Plugin::RenderFile - Net::IP - Net::OAuth - Opcode - Pandoc - Perl::Tidy - PHP::Serialization - Pod::Simple::Search - Pod::Simple::XHTML - Pod::Usage - Pod::WSDL - Scalar::Util - SOAP::Lite - Socket - SQL::Abstract - String::ShellQuote - SVG - Text::CSV - Text::Wrap - Tie::IxHash - Time::HiRes - Time::Zone - Types::Serialiser - URI::Escape - UUID::Tiny - XML::LibXML - XML::Parser - XML::Parser::EasyTree - XML::Writer - YAML::XS +my %modulesList = ( + 'Archive::Tar' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Archive-Tar' + } + }, + 'Archive::Zip' => { + 'package' => { + 'ubuntu' => 'libarchive-zip-perl', + 'rhel' => 'perl-Archive-Zip' + } + }, + 'Archive::Zip::SimpleZip' => { + 'package' => { + 'rhel' => 'perl-Archive-Zip-SimpleZip' + } + }, + 'Benchmark' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Benchmark' + } + }, + 'Carp' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Carp' + } + }, + 'Class::Accessor' => { + 'package' => { + 'ubuntu' => 'libclass-accessor-perl', + 'rhel' => 'perl-Class-Accessor' + } + }, + 'Crypt::JWT' => { + 'package' => { + 'ubuntu' => 'libcrypt-jwt-perl', + 'rhel' => 'perl-Crypt-JWT' + } + }, + 'Crypt::PK::RSA' => { + 'package' => { + 'ubuntu' => 'libcryptx-perl', + 'rhel' => 'perl-CryptX' + } + }, + 'DBI' => { + 'package' => { + 'ubuntu' => 'libdbi-perl', + 'rhel' => 'perl-DBI' + } + }, + 'Data::Dump' => { + 'package' => { + 'ubuntu' => 'libdata-dump-perl', + 'rhel' => 'perl-Data-Dump' + } + }, + 'Data::Dumper' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Data-Dumper' + } + }, + 'Data::Structure::Util' => { + 'package' => { + 'ubuntu' => 'libdata-structure-util-perl' + } + }, + 'Data::UUID' => { + 'package' => { + 'ubuntu' => 'libossp-uuid-perl', + 'rhel' => 'perl-Data-UUID' + } + }, + 'Date::Format' => { + 'package' => { + 'ubuntu' => 'libtimedate-perl', + 'rhel' => 'perl-TimeDate' + } + }, + 'Date::Parse' => { + 'package' => { + 'ubuntu' => 'libtimedate-perl', + 'rhel' => 'perl-TimeDate' + } + }, + 'DateTime' => { + 'package' => { + 'ubuntu' => 'libdatetime-perl', + 'rhel' => 'perl-DateTime' + } + }, + 'Digest::MD5' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Digest-MD5' + } + }, + 'Digest::SHA' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Digest-SHA' + } + }, + 'Email::Address::XS' => { + 'package' => { + 'ubuntu' => 'libemail-address-xs-perl', + 'rhel' => 'perl-Email-Address-XS' + } + }, + 'Email::Sender::Transport::SMTP' => { + 'package' => { + 'ubuntu' => 'libemail-sender-perl', + 'rhel' => 'perl-Email-Sender' + } + }, + 'Email::Stuffer' => { + 'package' => { + 'ubuntu' => 'libemail-stuffer-perl' + } + }, + 'Errno' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Errno' + } + }, + 'Exception::Class' => { + 'package' => { + 'ubuntu' => 'libexception-class-perl', + 'rhel' => 'perl-Exception-Class' + } + }, + 'File::Copy' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-File-Copy' + } + }, + 'File::Copy::Recursive' => { + 'package' => { + 'ubuntu' => 'libfile-copy-recursive-perl', + 'rhel' => 'perl-File-Copy-Recursive' + } + }, + 'File::Fetch' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-File-Fetch' + } + }, + 'File::Find' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-File-Find' + } + }, + 'File::Find::Rule' => { + 'package' => { + 'ubuntu' => 'libfile-find-rule-perl', + 'rhel' => 'perl-File-Find-Rule' + } + }, + 'File::Path' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-File-Path' + } + }, + 'File::Spec' => { + 'package' => { + 'ubuntu' => 'perl-base', + 'rhel' => 'perl-PathTools' + } + }, + 'File::Temp' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-File-Temp' + } + }, + 'File::stat' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-File-stat' + } + }, + 'Future::AsyncAwait' => { + 'minversion' => '0.52', + 'package' => { + 'ubuntu' => 'libfuture-asyncawait-perl' + } + }, + 'GD' => { + 'package' => { + 'ubuntu' => 'libgd-perl', + 'rhel' => 'perl-GD' + } + }, + 'GD::Barcode::QRcode' => { + 'package' => { + 'ubuntu' => 'libgd-barcode-perl' + } + }, + 'Getopt::Long' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Getopt-Long' + } + }, + 'Getopt::Std' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Getopt-Std' + } + }, + 'HTML::Entities' => { + 'package' => { + 'ubuntu' => 'libhtml-parser-perl', + 'rhel' => 'perl-HTML-Parser' + } + }, + 'HTTP::Async' => { + 'package' => { + 'ubuntu' => 'libhttp-async-perl' + } + }, + 'IO::File' => { + 'package' => { + 'ubuntu' => 'perl-base', + 'rhel' => 'perl-IO' + } + }, + 'Iterator' => { + 'package' => { + 'ubuntu' => 'libiterator-perl', + } + }, + 'Iterator::Util' => { + 'package' => { + 'ubuntu' => 'libiterator-util-perl' + } + }, + 'LWP::Protocol::https' => { + 'minversion' => '6.06', + 'package' => { + 'ubuntu' => 'liblwp-protocol-https-perl', + 'rhel' => 'perl-LWP-Protocol-https' + } + }, + 'Locale::Maketext::Lexicon' => { + 'package' => { + 'ubuntu' => 'liblocale-maketext-lexicon-perl' + } + }, + 'Locale::Maketext::Simple' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Locale-Maketext-Simple' + } + }, + 'MIME::Base32' => { + 'package' => { + 'ubuntu' => 'libmime-base32-perl' + } + }, + 'MIME::Base64' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-MIME-Base64' + } + }, + 'Math::Random::Secure' => { + 'package' => { + 'ubuntu' => 'libmath-random-secure-perl', + 'rhel' => 'perl-Math-Random-Secure' + } + }, + 'Minion' => { + 'package' => { + 'ubuntu' => 'libminion-perl' + } + }, + 'Minion::Backend::SQLite' => { + 'package' => { + 'ubuntu' => 'libminion-backend-sqlite-perl' + } + }, + 'Mojolicious' => { + 'minversion' => '9.34', + 'package' => { + 'ubuntu' => 'libmojolicious-perl', + 'rhel' => 'perl-Mojolicious' + } + }, + 'Mojolicious::Plugin::NotYAMLConfig' => { + 'package' => { + 'ubuntu' => 'libmojolicious-perl', + 'rhel' => 'perl-Mojolicious' + } + }, + 'Mojolicious::Plugin::RenderFile' => { + 'package' => { + 'ubuntu' => 'libmojolicious-plugin-renderfile-perl' + } + }, + 'Net::IP' => { + 'package' => { + 'ubuntu' => 'libnet-ip-perl', + 'rhel' => 'perl-Net-IP' + } + }, + 'Net::OAuth' => { + 'package' => { + 'ubuntu' => 'libnet-oauth-perl', + 'rhel' => 'perl-Net-OAuth' + } + }, + 'Opcode' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Opcode' + } + }, + 'PHP::Serialization' => { + 'package' => { + 'ubuntu' => 'libphp-serialization-perl', + 'rhel' => 'perl-PHP-Serialization' + } + }, + 'Pandoc' => { + 'package' => { + 'ubuntu' => 'libpandoc-wrapper-perl' + } + }, + 'Perl::Critic' => { + 'package' => { + 'ubuntu' => 'libperl-critic-perl', + 'rhel' => 'perl-Perl-Critic' + } + }, + 'Perl::Tidy' => { + 'package' => { + 'ubuntu' => 'perltidy', + 'rhel' => 'perltidy' + } + }, + 'Pod::Simple::Search' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Pod-Simple' + } + }, + 'Pod::Simple::XHTML' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Pod-Simple' + } + }, + 'Pod::Usage' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Pod-Usage' + } + }, + 'Pod::WSDL' => { + 'package' => { + 'ubuntu' => 'libpod-wsdl-perl' + } + }, + 'SOAP::Lite' => { + 'package' => { + 'ubuntu' => 'libsoap-lite-perl', + 'rhel' => 'perl-SOAP-Lite' + } + }, + 'SQL::Abstract' => { + 'minversion' => '2', + 'package' => { + 'ubuntu' => 'libsql-abstract-perl', + 'rhel' => 'perl-SQL-Abstract' + } + }, + 'SVG' => { + 'package' => { + 'ubuntu' => 'libsvg-perl', + } + }, + 'Scalar::Util' => { + 'package' => { + 'ubuntu' => 'perl-base', + 'rhel' => 'perl-Scalar-List-Utils' + } + }, + 'Socket' => { + 'package' => { + 'ubuntu' => 'perl-base', + 'rhel' => 'perl-Socket' + } + }, + 'String::ShellQuote' => { + 'package' => { + 'ubuntu' => 'libstring-shellquote-perl', + 'rhel' => 'perl-String-ShellQuote' + } + }, + 'Text::CSV' => { + 'package' => { + 'ubuntu' => 'libtext-csv-perl', + 'rhel' => 'perl-Text-CSV' + } + }, + 'Text::Wrap' => { + 'package' => { + 'ubuntu' => 'perl-base', + 'rhel' => 'perl-Text-Tabs+Wrap' + } + }, + 'Tie::IxHash' => { + 'package' => { + 'ubuntu' => 'libtie-ixhash-perl', + 'rhel' => 'perl-Tie-IxHash' + } + }, + 'Time::HiRes' => { + 'package' => { + 'ubuntu' => 'perl', + 'rhel' => 'perl-Time-HiRes' + } + }, + 'Time::Zone' => { + 'package' => { + 'ubuntu' => 'libtimedate-perl', + 'rhel' => 'perl-TimeDate' + } + }, + 'Types::Serialiser' => { + 'package' => { + 'ubuntu' => 'libtypes-serialiser-perl', + 'rhel' => 'perl-Types-Serialiser' + } + }, + 'URI::Escape' => { + 'package' => { + 'ubuntu' => 'liburi-perl', + 'rhel' => 'perl-URI' + } + }, + 'UUID::Tiny' => { + 'package' => { + 'ubuntu' => 'libuuid-tiny-perl', + 'rhel' => 'perl-UUID-Tiny' + } + }, + 'XML::LibXML' => { + 'package' => { + 'ubuntu' => 'libxml-libxml-perl', + 'rhel' => 'perl-XML-LibXML' + } + }, + 'XML::Parser' => { + 'package' => { + 'ubuntu' => 'libxml-parser-perl', + 'rhel' => 'perl-XML-Parser' + } + }, + 'XML::Parser::EasyTree' => { + 'package' => { + 'ubuntu' => 'libxml-parser-easytree-perl' + } + }, + 'XML::Writer' => { + 'package' => { + 'ubuntu' => 'libxml-writer-perl', + 'rhel' => 'perl-XML-Writer' + } + }, + 'YAML::XS' => { + 'package' => { + 'ubuntu' => 'libyaml-libyaml-perl', + 'rhel' => 'perl-YAML-LibYAML' + } + } ); -my %moduleVersion = ( - 'Future::AsyncAwait' => 0.52, - 'IO::Socket::SSL' => 2.007, - 'LWP::Protocol::https' => 6.06, - 'Mojolicious' => 9.34, - 'SQL::Abstract' => 2.000000 -); +my %cpanm_package = ('ubuntu' => 'cpanminus', 'rhel' => 'perl-App-cpanminus'); my @programList = qw( convert @@ -141,19 +566,37 @@ =head1 DESCRIPTION dvipng ); -my ($test_modules, $test_programs, $show_help); +my ($test_modules, $test_programs, $packagetype, $show_help); GetOptions( - 'm|modules' => \$test_modules, - 'p|programs' => \$test_programs, - 'h|help' => \$show_help, + 'm|modules' => \$test_modules, + 'p|programs' => \$test_programs, + 'd|distribution=s' => \$packagetype, + 'h|help' => \$show_help, ); + pod2usage(2) if $show_help; +if ($packagetype && $packagetype ne 'rhel' && $packagetype ne 'ubuntu') { + die 'packagetype must be one of \'ubuntu\' or \'rhel\''; +} + +if (!$packagetype) { + if (determine_distribution()) { + say 'Distribution was not specified. Detected that the distribution is ' . $packagetype . ' or equivalent.'; + } else { + say 'Distribution was not specified and could not be detected. Use the -d option to specify your distribution.'; + } +} + +my %packagemgrcommand = ('ubuntu' => 'sudo apt install ', 'rhel' => 'sudo dnf install '); + $test_modules = $test_programs = 1 unless $test_programs || $test_modules; my @PATH = split(/:/, $ENV{PATH}); +my (@missing_packages, @missing_modules); + check_modules() if $test_modules; say '' if $test_modules && $test_programs; check_apps() if $test_programs; @@ -166,6 +609,45 @@ sub which { return; } +sub determine_distribution { + my %os_attrs; + + #code adapted from Sys::OsRelease + if (open my $fh, "<", '/etc/os-release') { + while (my $line = <$fh>) { + chomp $line; # remove trailing nl + if (substr($line, -1, 1) eq "\r") { + $line = substr($line, 0, -1); # remove trailing cr + } + + # skip comments and blank lines + if ($line =~ /^ \s+ #/x or $line =~ /^ \s+ $/x) { + next; + } + + # read attribute assignment lines + if ($line =~ /^ ([A-Z0-9_]+) = "(.*)" $/x + or $line =~ /^ ([A-Z0-9_]+) = '(.*)' $/x + or $line =~ /^ ([A-Z0-9_]+) = (.*) $/x) + { + next if $1 eq "_config"; # don't overwrite _config + $os_attrs{ lc($1) } = $2; + } + } + close $fh; + if ($os_attrs{'id'} =~ 'ubuntu' || ($os_attrs{'id_like'} && $os_attrs{'id_like'} =~ 'ubuntu')) { + $packagetype = 'ubuntu'; + return 1; + } elsif ($os_attrs{'id'} =~ 'fedora' || ($os_attrs{'id_like'} && $os_attrs{'id_like'} =~ 'fedora')) { + $packagetype = 'rhel'; + return 1; + } + } else { + return 0; + } + +} + sub check_modules { say "Checking for modules required by WeBWorK..."; @@ -181,27 +663,45 @@ sub check_modules { my $file = ($module =~ s|::|/|gr) . '.pm'; if ($@ =~ /Can't locate $file in \@INC/) { say "** $module not found in \@INC"; + if ($packagetype) { + if ($modulesList{$module}{package}{$packagetype}) { + push(@missing_packages, $modulesList{$module}{package}{$packagetype}); + } else { + push(@missing_modules, $module); + } + } } else { say "** $module found, but failed to load: $@"; } - } elsif (defined($moduleVersion{$module}) - && version->parse(${ $module . '::VERSION' }) < version->parse($moduleVersion{$module})) + } elsif (defined($modulesList{$module}{'minversion'}) + && version->parse(${ $module . '::VERSION' }) < version->parse($modulesList{$module}{'minversion'})) { $moduleNotFound = 1; - say "** $module found, but not version $moduleVersion{$module} or better"; + say "** $module found, but not version $modulesList{$module}{'minversion'} or better"; } else { say " $module found and loaded"; } use strict 'refs'; }; - for my $module (@modulesList) { + for my $module (sort keys(%modulesList)) { $checkModule->($module); } if ($moduleNotFound) { say ''; - say 'Some requred modules were not found, could not be loaded, or were not at the sufficient version.'; + say 'Some required modules were not found, could not be loaded, or were not at the sufficient version.'; + if (@missing_modules || @missing_packages) { + say 'You can try to install the missing modules with the following command(s):' . "\n"; + if (@missing_modules) { + say 'sudo cpanm ' . join(' ', @missing_modules) . "\n"; + } + if (@missing_packages) { + say $packagemgrcommand{$packagetype} . join(' ', @missing_packages) . "\n"; + } + say 'If the cpanm command is not installed, you can try installing it using the following command:' . "\n"; + say $packagemgrcommand{$packagetype} . $cpanm_package{$packagetype}; + } say 'Exiting as this is required to check the database driver and programs.'; exit 0; } @@ -246,8 +746,8 @@ sub check_apps { my $node_version_str = qx/node -v/; my ($node_version) = $node_version_str =~ m/v(\d+)\./; - say "\n**The version of node should be at least 18. You have version $node_version." - if $node_version < 18; + say "\n**The version of node should be at least 20. You have version $node_version." + if $node_version < 20; return; } diff --git a/bin/dev_scripts/PODtoHTML.pm b/bin/dev_scripts/PODtoHTML.pm deleted file mode 100644 index a922314011..0000000000 --- a/bin/dev_scripts/PODtoHTML.pm +++ /dev/null @@ -1,201 +0,0 @@ -package PODtoHTML; - -use strict; -use warnings; -use utf8; - -use Pod::Simple::Search; -use Mojo::Template; -use Mojo::DOM; -use Mojo::Collection qw(c); -use File::Path qw(make_path); -use File::Basename qw(dirname); -use IO::File; -use POSIX qw(strftime); - -use WeBWorK::Utils::PODParser; - -our @sections = ( - doc => 'Documentation', - bin => 'Scripts', - macros => 'Macros', - lib => 'Libraries', -); -our %macro_names = ( - answers => 'Answers', - contexts => 'Contexts', - core => 'Core', - deprecated => 'Deprecated', - graph => 'Graph', - math => 'Math', - misc => 'Miscellaneous', - parsers => 'Parsers', - ui => 'User Interface' -); - -sub new { - my ($invocant, %o) = @_; - my $class = ref $invocant || $invocant; - - my @section_list = ref($o{sections}) eq 'ARRAY' ? @{ $o{sections} } : @sections; - my $section_hash = {@section_list}; - my $section_order = [ map { $section_list[ 2 * $_ ] } 0 .. $#section_list / 2 ]; - delete $o{sections}; - - my $self = { - %o, - idx => {}, - section_hash => $section_hash, - section_order => $section_order, - macros_hash => {}, - }; - return bless $self, $class; -} - -sub convert_pods { - my $self = shift; - my $source_root = $self->{source_root}; - my $dest_root = $self->{dest_root}; - - my $regex = join('|', map {"^$_"} @{ $self->{section_order} }); - - my ($name2path, $path2name) = Pod::Simple::Search->new->inc(0)->limit_re(qr!$regex!)->survey($self->{source_root}); - for (keys %$path2name) { - print "Processing file: $_\n" if $self->{verbose} > 1; - $self->process_pod($_, $name2path); - } - - $self->write_index("$dest_root/index.html"); - - return; -} - -sub process_pod { - my ($self, $pod_path, $pod_files) = @_; - - my $pod_name; - - my ($subdir, $filename) = $pod_path =~ m|^$self->{source_root}/(?:(.*)/)?(.*)$|; - - my ($subdir_first, $subdir_rest) = ('', ''); - - if (defined $subdir) { - if ($subdir =~ m|/|) { - ($subdir_first, $subdir_rest) = $subdir =~ m|^([^/]*)/(.*)|; - } else { - $subdir_first = $subdir; - } - } - - $pod_name = (defined $subdir_rest ? "$subdir_rest/" : '') . $filename; - if ($filename =~ /\.pl$/) { - $filename =~ s/\.pl$/.html/; - } elsif ($filename =~ /\.pod$/) { - $pod_name =~ s/\.pod$//; - $filename =~ s/\.pod$/.html/; - } elsif ($filename =~ /\.pm$/) { - $pod_name =~ s/\.pm$//; - $pod_name =~ s|/+|::|g; - $filename =~ s/\.pm$/.html/; - } elsif ($filename !~ /\.html$/) { - $filename .= '.html'; - } - - $pod_name =~ s/^(\/|::)//; - - my $html_dir = $self->{dest_root} . (defined $subdir ? "/$subdir" : ''); - my $html_path = "$html_dir/$filename"; - my $html_rel_path = defined $subdir ? "$subdir/$filename" : $filename; - - $self->update_index($subdir, $html_rel_path, $pod_name); - make_path($html_dir); - my $html = $self->do_pod2html( - pod_path => $pod_path, - pod_name => $pod_name, - pod_files => $pod_files - ); - my $fh = IO::File->new($html_path, '>:encoding(UTF-8)') - or die "Failed to open file '$html_path' for writing: $!\n"; - print $fh $html; - - return; -} - -sub update_index { - my ($self, $subdir, $html_rel_path, $pod_name) = @_; - - $subdir =~ s|/.*$||; - my $idx = $self->{idx}; - my $sections = $self->{section_hash}; - if ($subdir eq 'macros') { - $idx->{macros} = []; - if ($pod_name =~ m!^(.+)/(.+)$!) { - push @{ $self->{macros_hash}{$1} }, [ $html_rel_path, $2 ]; - } else { - push @{ $idx->{doc} }, [ $html_rel_path, $pod_name ]; - } - } elsif (exists $sections->{$subdir}) { - push @{ $idx->{$subdir} }, [ $html_rel_path, $pod_name ]; - } else { - warn "no section for subdir '$subdir'\n"; - } - - return; -} - -sub write_index { - my ($self, $out_path) = @_; - - my $fh = IO::File->new($out_path, '>:encoding(UTF-8)') or die "Failed to open index '$out_path' for writing: $!\n"; - print $fh Mojo::Template->new(vars => 1)->render_file( - "$self->{template_dir}/category-index.mt", - { - title => 'POD for ' . ($self->{source_root} =~ s|^.*/||r), - base_url => $self->{dest_url}, - pod_index => $self->{idx}, - sections => $self->{section_hash}, - section_order => $self->{section_order}, - macros => $self->{macros_hash}, - macros_order => [ sort keys %{ $self->{macros_hash} } ], - macro_names => \%macro_names, - date => strftime('%a %b %e %H:%M:%S %Z %Y', localtime) - } - ); - - return; -} - -sub do_pod2html { - my ($self, %o) = @_; - - my $psx = WeBWorK::Utils::PODParser->new($o{pod_files}); - $psx->{source_root} = $self->{source_root}; - $psx->{verbose} = $self->{verbose}; - $psx->{assert_html_ext} = 1; - $psx->{base_url} = ($self->{dest_url} // '') . '/' . (($self->{source_root} // '') =~ s|^.*/||r); - $psx->output_string(\my $html); - $psx->html_header(''); - $psx->html_footer(''); - $psx->parse_file($o{pod_path}); - - my $dom = Mojo::DOM->new($html); - my $podIndexUL = $dom->at('ul[id="index"]'); - my $podIndex = $podIndexUL ? $podIndexUL->find('ul[id="index"] > li') : c(); - for (@$podIndex) { - $_->attr({ class => 'nav-item' }); - $_->at('a')->attr({ class => 'nav-link p-0' }); - for (@{ $_->find('ul') }) { - $_->attr({ class => 'nav flex-column w-100' }); - } - for (@{ $_->find('li') }) { - $_->attr({ class => 'nav-item' }); - $_->at('a')->attr({ class => 'nav-link p-0' }); - } - } - my $podHTML = $podIndexUL ? $podIndexUL->remove : $html; - - return Mojo::Template->new(vars => 1)->render_file("$self->{template_dir}/pod.mt", - { title => $o{pod_name}, base_url => dirname($psx->{base_url}), index => $podIndex, content => $podHTML }); -} - -1; diff --git a/bin/dev_scripts/generate-ww-pg-pod.pl b/bin/dev_scripts/generate-ww-pg-pod.pl index f1591ae485..d20902a171 100755 --- a/bin/dev_scripts/generate-ww-pg-pod.pl +++ b/bin/dev_scripts/generate-ww-pg-pod.pl @@ -9,17 +9,16 @@ =head1 SYNOPSIS generate-ww-pg-pod.pl [options] Options: - -p|--pg-root Directory containing a git clone of pg. - If this option is not set, then the environment - variable $PG_ROOT will be used if it is set. -o|--output-dir Directory to save the output files to. (required) -b|--base-url Base url location used on server. (default: /) This is needed for internal POD links to work correctly. -v|--verbose Increase the verbosity of the output. (Use multiple times for more verbosity.) -Note that --pg-root must be provided or the PG_ROOT environment variable set -if the POD for pg is desired. +Note that C must be set in the C file, or +if that file does not exist then the clone of the PG repository must be located +at C as defined in the C +file. =head1 DESCRIPTION @@ -30,37 +29,47 @@ =head1 DESCRIPTION use strict; use warnings; +my ($webwork_root, $pg_root); + +BEGIN { + use File::Basename qw(dirname); + use Cwd qw(abs_path); + use YAML::XS qw(LoadFile); + + $webwork_root = abs_path(dirname(dirname(dirname(__FILE__)))); + + # Load the configuration file to obtain the PG root directory. + my $config_file = "$webwork_root/conf/webwork2.mojolicious.yml"; + $config_file = "$webwork_root/conf/webwork2.mojolicious.dist.yml" unless -e $config_file; + my $config = LoadFile($config_file); + + $pg_root = $config->{pg_dir}; +} + use Getopt::Long qw(:config bundling); use Pod::Usage; -my ($pg_root, $output_dir, $base_url); +my ($output_dir, $base_url); my $verbose = 0; GetOptions( - 'p|pg-root=s' => \$pg_root, 'o|output-dir=s' => \$output_dir, 'b|base-url=s' => \$base_url, 'v|verbose+' => \$verbose ); -$pg_root = $ENV{PG_ROOT} if !$pg_root; - -pod2usage(2) unless $output_dir; +pod2usage(2) unless $output_dir && $pg_root && -d $pg_root; $base_url = "/" if !$base_url; use Mojo::Template; use IO::File; use File::Copy; -use File::Path qw(make_path remove_tree); -use File::Basename qw(dirname); -use Cwd qw(abs_path); - -use lib dirname(dirname(dirname(__FILE__))) . '/lib'; -use lib dirname(__FILE__); +use File::Path qw(make_path remove_tree); -use PODtoHTML; +use lib "$webwork_root/lib"; +use lib "$pg_root/lib"; -my $webwork_root = abs_path(dirname(dirname(dirname(__FILE__)))); +use WeBWorK::Utils::PODtoHTML; for my $dir ($webwork_root, $pg_root) { next unless $dir && -d $dir; @@ -73,10 +82,10 @@ =head1 DESCRIPTION write_index($index_fh); make_path("$output_dir/assets"); -copy("$webwork_root/htdocs/js/PODViewer/podviewer.css", "$output_dir/assets/podviewer.css"); -print "copying $webwork_root/htdocs/js/PODViewer/podviewer.css to $output_dir/assets/podviewer.css\n" if $verbose; -copy("$webwork_root/htdocs/js/PODViewer/podviewer.js", "$output_dir/assets/podviewer.js"); -print "copying $webwork_root/htdocs/js/PODViewer/podviewer.css to $output_dir/assets/podviewer.js\n" if $verbose; +copy("$pg_root/htdocs/js/PODViewer/podviewer.css", "$output_dir/assets/podviewer.css"); +print "copying $pg_root/htdocs/js/PODViewer/podviewer.css to $output_dir/assets/podviewer.css\n" if $verbose; +copy("$pg_root/htdocs/js/PODViewer/podviewer.js", "$output_dir/assets/podviewer.js"); +print "copying $pg_root/htdocs/js/PODViewer/podviewer.css to $output_dir/assets/podviewer.js\n" if $verbose; sub process_dir { my $source_dir = shift; @@ -89,12 +98,15 @@ sub process_dir { remove_tree($dest_dir); make_path($dest_dir); - my $htmldocs = PODtoHTML->new( - source_root => $source_dir, - dest_root => $dest_dir, - template_dir => "$webwork_root/bin/dev_scripts/pod-templates", - dest_url => $base_url, - verbose => $verbose + my $htmldocs = WeBWorK::Utils::PODtoHTML->new( + source_root => $source_dir, + dest_root => $dest_dir, + template_dir => "$pg_root/assets/pod-templates", + dest_url => $base_url, + home_url => $base_url, + home_url_link_name => 'WeBWorK POD Home', + page_url => $base_url . ($source_dir =~ s|^.*/||r), + verbose => $verbose ); $htmldocs->convert_pods; diff --git a/bin/dev_scripts/pod-templates/category-index.mt b/bin/dev_scripts/pod-templates/category-index.mt deleted file mode 100644 index a5d980d599..0000000000 --- a/bin/dev_scripts/pod-templates/category-index.mt +++ /dev/null @@ -1,95 +0,0 @@ - - -% - - - - <%= $title %> - - - - - - -% - - - % - % my ($index, $macro_index, $content, $macro_content) = ('', '', '', ''); - % for my $macro (@$macros_order) { - % my $new_index = begin - <%= $macro_names->{$macro} // $macro %> - % end - % $macro_index .= $new_index->(); - % my $new_content = begin -

<%= $macro_names->{$macro} // $macro %>

-
- % for my $file (sort { $a->[1] cmp $b->[1] } @{ $macros->{$macro} }) { - <%= $file->[1] %> - % } -
- % end - % $macro_content .= $new_content->(); - % } - % for my $section (@$section_order) { - % next unless defined $pod_index->{$section}; - % my $new_index = begin - <%= $sections->{$section} %> - % if ($section eq 'macros') { - - % } - % end - % $index .= $new_index->(); - % my $new_content = begin -

<%= $sections->{$section} %>

-
- % if ($section eq 'macros') { - <%= $macro_content =%> - % } else { - % for my $file (sort { $a->[1] cmp $b->[1] } @{ $pod_index->{$section} }) { - - <%= $file->[1] %> - - % } - % } -
- % end - % $content .= $new_content->(); - % } - % - -
-
- <%= $content =%> -

Generated <%= $date %>

-
-
- -% - diff --git a/bin/dev_scripts/pod-templates/main-index.mt b/bin/dev_scripts/pod-templates/main-index.mt index d9bfe39e8d..9c8c711588 100644 --- a/bin/dev_scripts/pod-templates/main-index.mt +++ b/bin/dev_scripts/pod-templates/main-index.mt @@ -4,8 +4,7 @@ - - + WeBWorK/PG POD diff --git a/bin/dev_scripts/pod-templates/pod.mt b/bin/dev_scripts/pod-templates/pod.mt deleted file mode 100644 index 0ea8e6c5b4..0000000000 --- a/bin/dev_scripts/pod-templates/pod.mt +++ /dev/null @@ -1,55 +0,0 @@ - - -% - - - - <%= $title %> - - - - - - -% - - - -
-
- <%= $content =%> -
-
- -% - diff --git a/bin/dev_scripts/run-perltidy.pl b/bin/dev_scripts/run-perltidy.pl index 37c9463353..02eb677058 100755 --- a/bin/dev_scripts/run-perltidy.pl +++ b/bin/dev_scripts/run-perltidy.pl @@ -65,8 +65,8 @@ =head1 OPTIONS # Validate options that were passed. my %options; my $err = Perl::Tidy::perltidy(argv => \@args, dump_options => \%options); -exit $err if $err; -die "The -pro option is not suppored by this script.\n" if defined $options{profile}; +exit $err if $err; +die "The -pro option is not supported by this script.\n" if defined $options{profile}; unshift(@args, '-bext=/') unless defined $options{'backup-file-extension'}; diff --git a/bin/dev_scripts/update-localization-files b/bin/dev_scripts/update-localization-files index 8ad0cc1c11..20d60a7ccc 100755 --- a/bin/dev_scripts/update-localization-files +++ b/bin/dev_scripts/update-localization-files @@ -45,7 +45,7 @@ if [ -z "$WEBWORK_ROOT" ]; then fi command -v xgettext.pl >/dev/null 2>&1 || { - echo >&2 "xgettext.pl needs to be installed. It is inlcuded in the perl package Locale::Maketext::Extract. Aborting."; + echo >&2 "xgettext.pl needs to be installed. It is included in the perl package Locale::Maketext::Extract. Aborting."; exit 1; } diff --git a/bin/upgrade-database-to-utf8mb4.pl b/bin/upgrade-database-to-utf8mb4.pl index 2d99c84ea6..9c1a1f9a25 100755 --- a/bin/upgrade-database-to-utf8mb4.pl +++ b/bin/upgrade-database-to-utf8mb4.pl @@ -32,7 +32,7 @@ =head1 DESCRIPTION Upgrade webwork course database tables from latin1 to utf8mb4. This script assumes that you have already properly configured the database to -work with the utf8mb4 character set. See L. +work with the utf8mb4 character set. See L. Also, make sure to upgrade the course via webwork2/admin "Upgrade Courses" before running this script for the course. @@ -81,7 +81,7 @@ =head1 OPTIONS this option is enabled then the second pass will change those back to the smaller text datatypes as defined in the webwork database schema. -This second pass is not strictly neccessary. The larger text datatypes should +This second pass is not strictly necessary. The larger text datatypes should still work with WeBWorK. This pass is not run by default. Note that running this script again will also diff --git a/conf/README.md b/conf/README.md index 45ebac0def..0331c407a7 100644 --- a/conf/README.md +++ b/conf/README.md @@ -190,7 +190,7 @@ sudo systemctl enable /opt/webwork/webwork2/conf/webwork2.service sudo systemctl start webwork2 ``` -### Deployment of the webwork2 job queue for all server arrangments +### Deployment of the webwork2 job queue for all server arrangements Some long running processes are not directly run by the webwork2 Mojolicious app. Particularly mass grade updates via LTI and sending of instructor emails. Instead these tasks are executed via the webwork2 Minion job queue. diff --git a/conf/authen_LTI.conf.dist b/conf/authen_LTI.conf.dist index 20196f4f49..b32287f517 100644 --- a/conf/authen_LTI.conf.dist +++ b/conf/authen_LTI.conf.dist @@ -213,7 +213,6 @@ $LTISendGradesEarlyThreshold = 'attempted'; # page, then a new mass passback job will begin. Set this to -1 to disable mass passback. $LTIMassUpdateInterval = 86400; - ################################################################################################ # Add an 'LTI' tab to the Course Configuration page ################################################################################################ @@ -255,15 +254,15 @@ $LTIMassUpdateInterval = 86400; # By default only admin users can modify the LTI secrets and lms_context_id. The following # permissions need to be modified to allow other users the permission to modify the values. -#$permissionLevels{'change_config_LTI{v1p1}{BasicConsumerSecret}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{PlatformID}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{ClientID}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{DeploymentID}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{PublicKeysetURL}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{AccessTokenURL}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{AccessTokenAUD}'} = "admin", -#$permissionLevels{'change_config_LTI{v1p3}{AuthReqURL}'} = "admin", -#$permissionLevels{'change_config_lms_context_id'} = "admin", +#$permissionLevels{'change_config_LTI{v1p1}{BasicConsumerSecret}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{PlatformID}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{ClientID}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{DeploymentID}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{PublicKeysetURL}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{AccessTokenURL}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{AccessTokenAUD}'} = "admin"; +#$permissionLevels{'change_config_LTI{v1p3}{AuthReqURL}'} = "admin"; +#$permissionLevels{'change_config_lms_context_id'} = "admin"; # Note that the lms_context_id is actually a database setting. It must be set for a course in # order for the instructor to utilize LTI content selection. This can also be set in the admin diff --git a/conf/authen_saml2.conf.dist b/conf/authen_saml2.conf.dist index a4403134a1..bf7a08e156 100644 --- a/conf/authen_saml2.conf.dist +++ b/conf/authen_saml2.conf.dist @@ -55,7 +55,7 @@ $saml2{twoFAOnlyWithBypass} = 0; # prevents users from attempting to login in to WeBWorK directly. $external_auth = 0; -# The $saml2{idps} hash contains names of identity proviers and their SAML2 +# The $saml2{idps} hash contains names of identity providers and their SAML2 # metadata URLs that are used by this server. Webwork will request the identity # provider's metadata from the URL of the $saml2{active_idp} during the # authentication process. Additional identity providers can also be added for a diff --git a/conf/defaults.config b/conf/defaults.config index b9c2448d99..1f37b4b7c7 100644 --- a/conf/defaults.config +++ b/conf/defaults.config @@ -73,7 +73,7 @@ $mail{feedbackRecipients} = [ # %% = literal percent sign # -$mail{feedbackSubjectFormat} = "[WWfeedback] course:%c user:%u set:%s prob:%p sec:%x rec:%r"; +$mail{feedbackSubjectFormat} = '[WWfeedback] course:%c user:%u{ set:%s}{ prob:%p}{ sec:%x}{ rec:%r}'; # feedbackVerbosity: # 0: send only the feedback comment and context link @@ -327,9 +327,6 @@ $webworkDirs{themes} = "$webworkDirs{htdocs}/themes"; # Location of localization directory. $webworkDirs{localize} = "$webworkDirs{root}/lib/WeBWorK/Localize"; -# URL of general WeBWorK documentation. -$webworkURLs{docs} = "https://webwork.maa.org"; - # URLs for new issues in Github. $webworkURLs{webwork2BugReporter} = "https://github.com/openwebwork/webwork2/issues/new"; $webworkURLs{OPLBugReporter} = "https://github.com/openwebwork/webwork-open-problem-library/issues/new"; @@ -343,14 +340,12 @@ $webworkURLs{wwSecurityAnnounce} = "https://groups.google.com/g/ww-security-anno $webworkSecListManagers = 'ww-security-announce+managers@googlegroups.com'; # URLs in the Wiki -$webworkURLs{WikiMain} = "https://webwork.maa.org/wiki/"; -$webworkURLs{SiteMap} = "https://webwork.maa.org/wiki/WeBWorK_Sites"; +$webworkURLs{WikiMain} = "https://wiki.openwebwork.org/wiki"; +$webworkURLs{SiteMap} = "https://wiki.openwebwork.org/wiki/WeBWorK_Sites"; # URL for help buttons on the PGProblemEditor pages: -$webworkURLs{MathObjectsHelpURL} ='https://webwork.maa.org/wiki/Category:MathObjects'; -$webworkURLs{PGLabHelpURL} ='https://demo.webwork.rochester.edu/webwork2/wikiExamples/MathObjectsLabs2/2?login_practice_user=true'; -$webworkURLs{PGMLHelpURL} ='https://demo.webwork.rochester.edu/webwork2/cervone_course/PGML/1?login_practice_user=true'; -$webworkURLs{AuthorHelpURL} ='https://webwork.maa.org/wiki/Category:Authors'; +$webworkURLs{MathObjectsHelpURL} = 'https://wiki.openwebwork.org/wiki/Category:MathObjects'; +$webworkURLs{AuthorHelpURL} = 'https://wiki.openwebwork.org/wiki/Category:Authors'; # Location of CSS # $webworkURLs{stylesheet} = "$webworkURLs{htdocs}/css/${defaultTheme}.css"; @@ -366,7 +361,7 @@ $webworkURLs{AuthorHelpURL} ='https://webwork.maa.org/wiki/Category:Au # The problemLibrary configuration data should now be set in localOverrides.conf # For configuration instructions, see: -# https://webwork.maa.org/wiki/Open_Problem_Library +# https://wiki.openwebwork.org/wiki/Open_Problem_Library # The directory containing the open problem library files. # Set the root to "" if no problem @@ -451,7 +446,6 @@ $courseDirs{mailmerge} = "$courseDirs{DATA}/mailmerge"; # course links that are regulated by webwork2 $courseLinks{Library} = [ $problemLibrary{root}, "$courseDirs{templates}/Library" ]; $courseLinks{Contrib} = [ $contribLibrary{root}, "$courseDirs{templates}/Contrib" ]; -$courseLinks{capaLibrary} = [ "$contribLibrary{root}/CAPA", "$courseDirs{templates}/capaLibrary" ]; $courseLinks{Student_Orientation} = [ "$webworkDirs{assets}/pg/Student_Orientation", "$courseDirs{templates}/Student_Orientation" ]; ################################################################################ @@ -567,12 +561,10 @@ $uneditableCourseFiles = [ # activated below gives access to all the directories in the National # Problem Library. # -$courseFiles{problibs} = { - Library => "OPL Directory", - Contrib => "Contrib", # remember to create link from Contrib to Contrib - # library directory - capaLibrary => "CAPA", # remember to create link from capaLibrary to CAPA - # in contrib +$courseFiles{problibs} = { + Library => "OPL Directory", + Contrib => "Contrib", # remember to create link from Contrib to Contrib + # library directory }; ################################################################################ @@ -674,14 +666,14 @@ $courseFiles{logs}{activity_log} = ''; # The default_copy_from_course is used by default when creating a new course. # Its templates folder, html folder, course.conf file, and simple.conf file # might be copied into a new course. This course might not be a true course; -# it might only have a directory structure and no presense in the database. +# it might only have a directory structure and no presence in the database. # If it is a real course, then also its title, institution, non-student users, # achievements, and sets can be copied. $siteDefaults{default_copy_from_course} ="modelCourse"; # Provide a list of model courses which are not real courses, but from which # the templates for a new course can be copied. This list helps exclude such -# non-real courses when that is appopriate. +# non-real courses when that is appropriate. $modelCoursesForCopy = [ "modelCourse" ]; ################################################################################ @@ -780,6 +772,13 @@ $authen{admin_module} = ['WeBWorK::Authen::Basic_TheLastOption']; modify_tags => "admin", edit_restricted_files => "admin", + # Permission to render problems using the WebworkWebservice. + # Users with only webservice_render_problem can render problems with a provided filename. + # Users with both permissions can also render problems with providing the problem source. + # Note the Problem Editor requires having both permissions. + webservice_render_problem => "login_proctor", + webservice_render_source => "login_proctor", + ##### Behavior of the interactive problem processor ##### show_correct_answers_before_answer_date => "ta", show_solutions_before_answer_date => "ta", @@ -917,7 +916,7 @@ $gatewayGracePeriod = 120; # database which is compared to the key stored in the session cookie. The # lifetime of the cookie is determined by the $sessionTimeout setting above. -# Note that the key database method is less secure as the key must be embeded in +# Note that the key database method is less secure as the key must be embedded in # the page and added as a url parameter in order to maintain the session. These # things can be accessed by malicious javascript. The session cookies are http # only cookies which can not be accessed via javascript. @@ -1109,7 +1108,7 @@ $pg{options}{showPGInfo} = 0; $pg{options}{showEvaluatedAnswers} = 1; # Catch translation warnings internally. This must be done since the translator is now run in a subprocess and do not -# propogate to the main process. So this really should never be set to 0. +# propagate to the main process. So this really should never be set to 0. $pg{options}{catchWarnings} = 1; ##### Settings for various display modes @@ -1147,7 +1146,6 @@ $pg{directories}{macrosPath} = [ $courseDirs{macros}, $pg{directories}{macros}, "$pg{directories}{macros}/answers", - "$pg{directories}{macros}/capa", "$pg{directories}{macros}/contexts", "$pg{directories}{macros}/core", "$pg{directories}{macros}/graph", @@ -1197,25 +1195,6 @@ $pg{specialPGEnvironmentVars}{latexImageSVGMethod} = "dvisvgm"; # convert file.ext1 file.ext2 $pg{specialPGEnvironmentVars}{latexImageConvertOptions} = {input => {density => 300}, output => {quality => 100}}; - # set the flags immediately above in the $pg{options} section above -- not here. - -# Locations of CAPA resources. (Only necessary if you need to use converted CAPA -# problems.) -################################################################################ -# "Special" PG environment variables. (Stuff that doesn't fit in anywhere else.) -################################################################################ - - $pg{specialPGEnvironmentVars}{CAPA_Tools} = "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_Tools/", - $pg{specialPGEnvironmentVars}{CAPA_MCTools} = "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_MCTools/", - $pg{specialPGEnvironmentVars}{CAPA_GraphicsDirectory} = "$courseDirs{templates}/Contrib/CAPA/CAPA_Graphics/", - $pg{specialPGEnvironmentVars}{CAPA_Graphics_URL} = "$webworkURLs{htdocs}/CAPA_Graphics/", - - push @{$pg{directories}{macrosPath}}, - "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_Tools", - "$courseDirs{templates}/Contrib/CAPA/macros/CAPA_MCTools"; - - # The link Contrib in the course templates directory should point to ../webwork-open-problem-library/Contrib - # The link webwork2/htdocs/CAPA_Graphics should point to ../webwork-open-problem-library/Contrib/CAPA/macros/CAPA_graphics # Size in pixels of dynamically-generated images, i.e. graphs. $pg{specialPGEnvironmentVars}{onTheFlyImageSize} = 400, @@ -1240,36 +1219,7 @@ $pg{specialPGEnvironmentVars}{convertFullWidthCharacters} = 0; $pg{specialPGEnvironmentVars}{problemPreamble} = { TeX => '', HTML=> '' }; $pg{specialPGEnvironmentVars}{problemPostamble} = { TeX => '', HTML=>'' }; -# this snippet checks to see if Moodle has already called MathJax -# $pg{specialPGEnvironmentVars}{problemPreamble} = { TeX => '', HTML=> < -# if (MathJax.Hub.Startup.params.config && MathJax.Hub.config.config.length) { -# MathJax.Hub.Config({ -# config: [], -# skipStartupTypeset: false -# }); -# } -# -# END_PREAMBLE - -# -# $pg{specialPGEnvironmentVars}{problemPostamble} = { TeX => '', HTML=> <\n!; -#$pg{specialPGEnvironmentVars}{problemPostamble}{HTML}= qq!\n!; - -# To have the problem body indented and boxed, uncomment: -# $pg{specialPGEnvironmentVars}{problemPreamble}{HTML} = '
-#
'; -# $pg{specialPGEnvironmentVars}{problemPostamble}{HTML} = '
-#
'; +# Note: problemPreamble and problemPostamble are depreciated, so don't use them. ##### PG modules to load @@ -1308,7 +1258,7 @@ ${pg}{modules} = [ [qw(Matrix)], [qw(Multiple)], [qw(PGrandom)], - [qw(Plots::Plot Plots::Axes Plots::Data Plots::Tikz Plots::JSXGraph Plots::GD)], + [qw(Plots::Plot Plots::Axes Plots::Data Plots::Tikz Plots::JSXGraph)], [qw(Regression)], [qw(Select)], [qw(Units)], diff --git a/conf/localOverrides.conf.dist b/conf/localOverrides.conf.dist index 78ea012bba..5a90bb90d3 100644 --- a/conf/localOverrides.conf.dist +++ b/conf/localOverrides.conf.dist @@ -64,7 +64,7 @@ $mail{feedbackRecipients} = [ # Should the studentID be included in the feedback email when feedbackVerbosity > 0: # The default is yes. Uncomment the line below to block it from being included. # Blocking it from being included is recommended if the studentID is "personal" -# informations whose privacy should be maintained (ex. a government issued ID number). +# information whose privacy should be maintained (ex. a government issued ID number). # The setting can also be made in the course.conf file for specific courses. #$blockStudentIDinFeedback = 1; @@ -149,7 +149,7 @@ $mail{feedbackRecipients} = [ # For configuration instructions, see: -# http://webwork.maa.org/wiki/Open_Problem_Library +# https://wiki.openwebwork.org/wiki/Open_Problem_Library # The directory containing the open problem library files. Set to "" if no problem # library is installed. # NationalProblemLibrary (NPL) has been renamed to OpenProblemLibrary (OPL) @@ -183,9 +183,8 @@ $mail{feedbackRecipients} = [ # Problem Library. #$courseFiles{problibs} = { - #Library => "OPL Directory", - #capaLibrary => "CAPA", - #Contrib => "Contrib", + #Library => "OPL Directory", + #Contrib => "Contrib", # the following are not really needed but you can # create links to your own private libraries this way. #rochesterLibrary => "Rochester", @@ -348,7 +347,7 @@ $mail{feedbackRecipients} = [ # also not present, it will just activate the "Preview My Answers" button. # A third option is "conservative". In this case, the enter key behaves like "preview" # when the "Submit" button is available and there are only finitely many -# attempts allowed. Otherise the enter key behaves like "submit". +# attempts allowed. Otherwise the enter key behaves like "submit". #$pg{options}{enterKey} = 'conservative'; ################################################################################ @@ -402,7 +401,7 @@ $mail{feedbackRecipients} = [ # Alternate locations -- this allows you to place temporary files in a location # that is not backed up and is the recommended set up for most installations. -# See http://webwork.maa.org/wiki/Store_WeBWorK%27s_temporary_files_in_a_separate_directory_or_partition +# See https://wiki.openwebwork.org/wiki/Store_WeBWorK's_temporary_files_in_a_separate_directory_or_partition # for more information. Note that the wwtmp directory (or partition) should be # created under Apache's main server document root which is usually # /var/www/html. If this is in a different location on your system, edit the @@ -428,32 +427,13 @@ $mail{feedbackRecipients} = [ # To enable Rserve (the R statistical server) in WeBWorK, uncomment the # following line. The R server needs to be installed and running in order for -# this to work. See http://webwork.maa.org/wiki/R_in_WeBWorK for more info. +# this to work. See https://wiki.openwebwork.org/wiki/R_in_WeBWorK for more info. #$pg{specialPGEnvironmentVars}{Rserve} = {host => "localhost"}; # use this setting when running Rserve in a docker container. #$pg{specialPGEnvironmentVars}{Rserve} = {host => "r"}; - -################################################################################ -# Serving Opaque client questions to moodle -################################################################################ - - -# this snippet checks to see if Moodle has already called MathJax -# $pg{specialPGEnvironmentVars}{problemPreamble} = { TeX => '', HTML=> < -# if (MathJax.Hub.Startup.params.config && MathJax.Hub.config.config.length) { -# MathJax.Hub.Config({ -# config: [], -# skipStartupTypeset: false -# }); -# } -# -# END_PREAMBLE - ################################################################################ # Authentication ################################################################################ @@ -558,7 +538,7 @@ $mail{feedbackRecipients} = [ # database which is compared to the key stored in the session cookie. The # lifetime of the cookie is determined by the $sessionTimeout setting below. -# Note that the key database method is less secure as the key must be embeded in +# Note that the key database method is less secure as the key must be embedded in # the page and added as a url parameter in order to maintain the session. These # things can be accessed by malicious javascript. The session cookies are http # only cookies which can not be accessed via javascript. diff --git a/conf/site.conf.dist b/conf/site.conf.dist index 9c6b7ddfae..e42553ddb4 100644 --- a/conf/site.conf.dist +++ b/conf/site.conf.dist @@ -178,7 +178,7 @@ if ( $database_host eq "localhost" ) { $database_dsn="DBI:$database_driver:database=$database_name;host=$database_host;port=$database_port"; } -# The default storange engine to use is set here: +# The default storage engine to use is set here: $database_storage_engine = 'myisam'; ######################### @@ -290,7 +290,7 @@ $mail{tls_allowed} = 0; # Set maxAttachmentSize to the maximum number of megabytes to allow for the size of # files attached to feedback emails. Note that this should be set to match the # limitations of the email server chosen above, and should be set to a value greater -# than zero or no attatchments will work. This is not intended to be a configuration +# than zero or no attachments will work. This is not intended to be a configuration # option to disable attachments. $mail{maxAttachmentSize} = 10; @@ -301,7 +301,7 @@ $mail{maxAttachmentSize} = 10; # This is the Minion backend that will be used by the job queue. # The corresponding perl package for this backend must be installed. -# Some availabled backends are: +# Some available backends are: # Minion::Backend::Pg (use 'Pg' below) # Minion::Backend::mysql (use 'mysql' below) # Minion::Backend::SQLite (use 'SQLite' below) @@ -322,7 +322,7 @@ $job_queue{database_dsn} = "sqlite:$webwork_dir/DATA/webwork2_job_queue.db"; # The problemLibrary configuration data should now be set in localOverrides.conf # For configuration instructions, see: -# http://webwork.maa.org/wiki/National_Problem_Library +# https://wiki.openwebwork.org/wiki/Open_Problem_Library # The directory containing the Open Problem Library files. # Set the root to "" if no problem # library is installed. Use version 2.0 for the NPL and use the version 2.5 for the OPL. diff --git a/conf/webwork2.mojolicious.dist.yml b/conf/webwork2.mojolicious.dist.yml index 637f733820..8281187895 100644 --- a/conf/webwork2.mojolicious.dist.yml +++ b/conf/webwork2.mojolicious.dist.yml @@ -15,7 +15,7 @@ pg_dir: /opt/webwork/pg # Setting MIN_HTML_ERRORS to 1 will minimize the data provided on HTML error # pages, which some security reviews request, as in particular the older output -# provided backtrace information which could help idenfify the code and version +# provided backtrace information which could help identify the code and version # of the code being used on the server. The useful information will be in the # Mojolicious webwork2.log file, with a UID displayed also in the HTML error # page to help match up records. @@ -72,6 +72,16 @@ JSON_ERROR_LOG: 0 # /pg_files: # Access-Control-Allow-Origin: '*' +# The extra_ssl_headers option is much like the extra_headers option above, +# except that these headers are only added to responses to secure SSL requests. +# The example below adds the Strict-Transport-Security header to responses to +# all SSL requests. Note that like the extra_headers option above, headers can +# be added to only specific paths as well (but only if the request is secure). + +#extra_ssl_headers: +# '.*': +# Strict-Transport-Security: 'max-age=31536000; includeSubDomains; preload' + # The user and group to run the server as. These are only used when the # webwork2 app is in production mode and run as the root user. This means that # these settings are not used when proxying via another web server like apache2 @@ -241,8 +251,21 @@ hardcopy: preserve_temp_files: 0 # Set this to 1 to allow the html2xml and render_rpc endpoints to disable -# cookies and thus skip two factor authentication. This should never be enabled -# for a typical webwork server. This should only be enabled if you want to -# allow serving content via these endpoints to links in external websites with -# usernames and passwords embedded in them such as for PreTeXt textbooks. +# cookies and thus skip two factor authentication for all courses. To disable +# cookies for a single course, set this to a hash whose keys are the course +# IDs with a value of 1. Further to only disable cookies for specific users +# in a course, set the course ID to a hash whose keys are user IDs with a +# value of 1. For example: +# allow_unsecured_rpc: +# # Disable cookies for full PreTeXt course. +# PreTeXt: 1 +# # Disable cookies for specific users in a course. +# courseID: +# user1ID: 1 +# user2ID: 1 +# +# This should never be enabled for a typical webwork server. This should only be +# enabled if you want to allow serving content via these endpoints to links in +# external websites with usernames and passwords embedded in them such as for +# PreTeXt textbooks. allow_unsecured_rpc: 0 diff --git a/courses.dist/modelCourse/templates/achievements/achievement_readme.txt b/courses.dist/modelCourse/templates/achievements/achievement_readme.txt index 6d9a6513dd..a650312914 100644 --- a/courses.dist/modelCourse/templates/achievements/achievement_readme.txt +++ b/courses.dist/modelCourse/templates/achievements/achievement_readme.txt @@ -1,13 +1,13 @@ This folder contains achievement evaluators. Their job is to test whether or not an achievement has been earned. The code is run every time a - student submits an answer to a homework question as long as the achievement - is unearned. + student submits an answer to a homework question as long as the achievement + is unearned. - -The code should be written in perl and should return 1 if the achievement - was earned and 0 if it was not earned. + -The code should be written in perl and should return 1 if the achievement + was earned and 0 if it was not earned. -Any perl code in preamble.at will be run before the content of any - achievement evaluator. + achievement evaluator. You have access to a variety of variables: - $problem : the problem data (changes to this variable will not be saved!) @@ -19,31 +19,31 @@ - $problem->num_correct : the number of correct attempts - $problem->num_incorrect : the number of incorrect attempts - $problem->max_attempts : the maximum number of allowed attempts - + - $set : the set data (changes to this variable will not be saved!) This variable contains the set data. it is a hash pointer with the following values. (not all values shown) - $set->open_date : when the set was open - $set->due_date : when the set is due - - - @setProblems : the problem data for all the problems from this set. + + - @setProblems : the problem data for all the problems from this set. (changes to this variable will not be saved!) This is an array of problem hashes. Each element of the array has the save hash keys as the $problem variable above - $counter : the users counter associated to this achievement (changes to this variable *will* be saved!) - If this achievement has a counter associated to it - (i.e. solve 20 problems) then this is where you store - the students counter for this achievement. - This variable will initally start as '' + If this achievement has a counter associated to it + (i.e. solve 20 problems) then this is where you store + the students counter for this achievement. + This variable will initially start as '' - $maxCounter : the goal for the $counter variable for this achievement (changes to this variable will not be saved!) - If this achievement has a counter associated to it then this variable - contains the goal for the counter. Your achievement should return 1 - when $counter >= $maxCounter. These two variables are used to show a - progress bar for the achievement. + If this achievement has a counter associated to it then this variable + contains the goal for the counter. Your achievement should return 1 + when $counter >= $maxCounter. These two variables are used to show a + progress bar for the achievement. - $tags : this contains the metadata for the problem stored in a hash. This includes DBsubject DBchapter and DBsection Note: These values are not super stable and are likely to change @@ -59,31 +59,31 @@ see the update. So when depending on other achievements place make sure they are run first. - - $localData : this is a hash which stores data for this user and + - $localData : this is a hash which stores data for this user and achievement (changes to this variable *will* be saved!) - This hash will persist from evaluation to evaluation. You can - store whatever you like in here and it can be accessed next time - this evaluator is run. Two things to keep in mind. First, The data - in this hash will *not* be accessible by other achievements. Second, - the first time a variable is accessed it will have the value ''. + This hash will persist from evaluation to evaluation. You can + store whatever you like in here and it can be accessed next time + this evaluator is run. Two things to keep in mind. First, The data + in this hash will *not* be accessible by other achievements. Second, + the first time a variable is accessed it will have the value ''. - $globalData : this is a hash which stores data for all achievements (changes to this variable *will* be saved!) This hash will persist from evaluation to evaluation and, like - $localData, you can store whatever you like in here. This data - will be accessable from *every* achievement and is unique to the + $localData, you can store whatever you like in here. This data + will be accessible from *every* achievement and is unique to the user. There are three variables stored in this hash that are - maintained by the system. - - $globalData->completeSets : This is the number of sets which + maintained by the system. + - $globalData->completeSets : This is the number of sets which the student has earned 100% on - - $globalData->complete Problems : This is the number of problems + - $globalData->complete Problems : This is the number of problems which the student has earned 100% on - $globalData->prev_level_points : This is the number of points to reach current level which is used with level progress bar. - Warning: The achievements are always evaluated in the order they + Warning: The achievements are always evaluated in the order they are listed the Instructors achievement editor page. To make matters - more complicated, achievements which have already been earned are - not evaluated at all. The up-shot of this is that when modifying - variables in $globalData you need to either write your code so it - doesnt matter which order the evaluators are run, or you need to - pay very close attention to which evaluators are run and when. + more complicated, achievements which have already been earned are + not evaluated at all. The up-shot of this is that when modifying + variables in $globalData you need to either write your code so it + doesn't matter which order the evaluators are run, or you need to + pay very close attention to which evaluators are run and when. diff --git a/courses.dist/modelCourse/templates/capaLibrary b/courses.dist/modelCourse/templates/capaLibrary deleted file mode 120000 index 4678d8df5c..0000000000 --- a/courses.dist/modelCourse/templates/capaLibrary +++ /dev/null @@ -1 +0,0 @@ -../../../libraries/webwork-open-problem-library/Contrib/CAPA \ No newline at end of file diff --git a/courses.dist/modelCourse/templates/setDemo/c4s5p2.pg b/courses.dist/modelCourse/templates/setDemo/c4s5p2.pg index 6eb9981877..439f88f27f 100644 --- a/courses.dist/modelCourse/templates/setDemo/c4s5p2.pg +++ b/courses.dist/modelCourse/templates/setDemo/c4s5p2.pg @@ -1,5 +1,5 @@ #DESCRIPTION -#KEYOWRDS('integrals', 'substitution') +#KEYWORDS('integrals', 'substitution') # Integrals - \int_0^{$x1} x(x^2 ?{$a})^5 dx # Substitution #ENDDESCRIPTION diff --git a/courses.dist/modelCourse/templates/setDemo/prob0837.pg b/courses.dist/modelCourse/templates/setDemo/prob0837.pg deleted file mode 100644 index bd39f44c66..0000000000 --- a/courses.dist/modelCourse/templates/setDemo/prob0837.pg +++ /dev/null @@ -1,64 +0,0 @@ -DOCUMENT(); - -loadMacros( "PGbasicmacros.pl", - "PGauxiliaryFunctions.pl", - "PGchoicemacros.pl", - "PGanswermacros.pl", - "PGgraphmacros.pl", - "PG_CAPAmacros.pl" -); - -# machine translated from CAPA. -# This is probaly not a good model for elegant PG code. -## ************************************** -## -## Projectile motion. -## By F. Wolfs, WOLFS@NSRL31.NSRL.Rochester.edu -## No unauthorized commercial use -## Imported Files -## ${CAPA_Tools}Problem -## ${CAPA_GraphicsDirectory}Gtype08/prob37.eps -## Values needing defined: -## prob_val (number, e.g. /LET prob_val=1) -## prob_try (number, e.g. /LET prob_try=5) -## -## Last modified 07/08/97 -## by: Patrick D. Freivald, patrick@freivald.org -## -## ************************************** -## -$L = random( 2.0 , 10.0 , 0.2 ) ; -$h = random( 0.5 , 0.5 * $L , 0.1 ) ; -$Theta = random( 35.0 , 60.0 , 1.0 ) ; -$v0_sq = $smallg * $L / ( 2.0 * cos( $Theta * $degrad ) * cos( $Theta * $degrad ) * ( tan( $Theta * $degrad ) - $h / $L ) ) ; -$v0 = pow( $v0_sq , 0.5 ) ; -## -CAPA_import( " ${CAPA_Tools}Problem " ); -TEXT(CAPA_EV (<<'END_OF_TEXT')); -A basketball player throws the ball at a \{ spf( $Theta , "%0.0f" ) \}\{ $deg_u \} angle above the horizontal to a hoop which is located a horizontal distance \{ CAPA_tex( '/*L/*' , 'L' ) \} = \{ spf( $L , "%0.1f" ) \} \{ $m_u \} from the point of release and at a height \{ CAPA_tex( '/*h/*' , 'h' ) \} = \{ spf( $h , "%0.1f" ) \} \{ $m_u \} above it. What is the required speed if the basketball is to reach the hoop? -\{ CAPA_web( '' , '\noindent {\centerline{\epsfxsize = 2.4 in \epsffile{${CAPA_GraphicsDirectory}Gtype08/prob37.eps}}}' , '' ) \} -END_OF_TEXT - -## - -TEXT("$BR$BR",ans_rule(30),"$BR"); -ANS( CAPA_ans( $v0 , 'format' => "%0.2e" , 'sig' => '3 PLUS 13', 'reltol' => 1 , 'wgt' => $prob_val , 'tries' => $prob_try , 'unit' => 'm/s' ) ); -ENDDOCUMENT(); -##################### - -###Error: $smallg not defined in this file -###Error: $degrad not defined in this file -###Error: $degrad not defined in this file -###Error: $degrad not defined in this file -###Error: $deg_u not defined in this file -###Error: $m_u not defined in this file -###Error: $m_u not defined in this file -###Error: $prob_val not defined in this file -###Error: $prob_try not defined in this file - -##################### - - -################################################# -## Processing time = 0 secs ( 0.56 usr 0.00 sys = 0.56 cpu) -################################################# diff --git a/courses.dist/modelCourse/templates/setDemo/screenHeaderFile1.pg b/courses.dist/modelCourse/templates/setDemo/screenHeaderFile1.pg index ea6c0bef30..a4a9dec9d6 100644 --- a/courses.dist/modelCourse/templates/setDemo/screenHeaderFile1.pg +++ b/courses.dist/modelCourse/templates/setDemo/screenHeaderFile1.pg @@ -18,7 +18,7 @@ $PAR $BBOLD 1. Simple numerical problem. $EBOLD A simple problem requiring a numerical answer. It illustrates how one can allow WeBWorK to calculate answers from formulas (e.g. an answer such as sqrt(3^2 +4^2) can be entered instead of the answer 5.). It also shows an example of feedback on the correctness of each answer, rather than grading the entire problem. $PAR -$BBOLD 2. Graphs and limits. $EBOLD The graph in this example is constructed on the fly. From the graph a student is supposed to determine the values and limits of the function at various points. The immediate feedback on this problem is particularly useful, since students often make unconcious mistakes. +$BBOLD 2. Graphs and limits. $EBOLD The graph in this example is constructed on the fly. From the graph a student is supposed to determine the values and limits of the function at various points. The immediate feedback on this problem is particularly useful, since students often make unconscious mistakes. $PAR $BBOLD 3. Derivatives. $EBOLD An example of checking answers which are formulas, rather than numbers. $PAR @@ -26,7 +26,7 @@ $BBOLD 4. Anti-derivatives. $EBOLD This example will accept any anti-derivative, $PAR $BBOLD 5. Answers with units. $EBOLD Try entering the answer to this question in meters (m) and also centimeters (cm). $PAR -$BBOLD 6. A physics example. $EBOLD Includes a static picture. +$BBOLD 6. A physics example. $EBOLD Includes a static picture. $PAR $BBOLD 7. More graphics. $EBOLD An example of on-the-fly graphics. Select the graph of f, it's derivative and it's second derivatives. $PAR @@ -65,12 +65,12 @@ For most problems when entering numerical answers, you can if you wish enter elementary expressions such as 2^3 instead of 8, sin(3*pi/2) instead of -1, e^(ln(2)) instead of 2, (2+tan(3))*(4-sin(5))^6-7/8 instead of 27620.3413, etc. -$PAR - Here's the +$PAR + Here's the \{ htmlLink(qq!http://webwork.maa.org/wiki/Available_Functions!,"list of the functions") \} - which WeBWorK understands. + which WeBWorK understands. -Along with the \{htmlLink(qq!http://webwork.maa.org/wiki/Units!, "list of units")\} which WeBWorK understands. This can be useful in +Along with the \{htmlLink(qq!http://webwork.maa.org/wiki/Units!, "list of units")\} which WeBWorK understands. This can be useful in physics problems. END_TEXT diff --git a/docker-config/idp/README.md b/docker-config/idp/README.md index 586b9d9953..90da62cd62 100644 --- a/docker-config/idp/README.md +++ b/docker-config/idp/README.md @@ -27,7 +27,7 @@ the port as needed. A docker service that implements a SAML2 identity provider is provided in the `docker-compose.yml.dist` file. To start this identity provider along with the rest of webwork2, add the `--profile saml2dev` argument to docker compose as in -the following exmaple. +the following example. ```bash docker compose --profile saml2dev up @@ -165,7 +165,7 @@ identity provider is accessible to webwork2. The user was verified by the identity provider but did not have a corresponding user account in the Webwork course. The Webwork user account needs to be created -separately as the Saml2 autentication module does not do user provisioning. +separately as the Saml2 authentication module does not do user provisioning. ### The WeBWorK service provider does not appear in the service provider Federation tab diff --git a/htdocs/generate-assets.js b/htdocs/generate-assets.js index 81ee6c7b10..f264601394 100755 --- a/htdocs/generate-assets.js +++ b/htdocs/generate-assets.js @@ -2,7 +2,8 @@ /* eslint-env node */ -const yargs = require('yargs'); +const yargs = require('yargs/yargs'); +const { hideBin } = require('yargs/helpers'); const chokidar = require('chokidar'); const path = require('path'); const { minify } = require('terser'); @@ -14,7 +15,7 @@ const postcss = require('postcss'); const rtlcss = require('rtlcss'); const cssMinify = require('cssnano'); -const argv = yargs +const argv = yargs(hideBin(process.argv)) .usage('$0 Options') .version(false) .alias('help', 'h') @@ -110,7 +111,11 @@ const processFile = async (file, _details) => { // This works for both sass/scss files and css files. let result; try { - result = sass.compile(filePath, { sourceMap: argv.enableSourcemaps }); + result = sass.compile(filePath, { + sourceMap: argv.enableSourcemaps, + // Silence warnings about bootstrap usage of deprecated sass methods. + silenceDeprecations: ['import', 'global-builtin', 'color-functions'] + }); } catch (e) { console.log(`\x1b[31mIn ${file}:`); console.log(`${e.message}\x1b[0m`); diff --git a/htdocs/js/ActionTabs/actiontabs.js b/htdocs/js/ActionTabs/actiontabs.js index 50c43da164..0662a455c7 100644 --- a/htdocs/js/ActionTabs/actiontabs.js +++ b/htdocs/js/ActionTabs/actiontabs.js @@ -6,6 +6,7 @@ actionLink.addEventListener('show.bs.tab', () => { if (takeAction) takeAction.value = actionLink.textContent; if (currentAction) currentAction.value = actionLink.dataset.action; + takeAction.formNoValidate = actionLink.dataset.noValidate ? true : false; }); }); diff --git a/htdocs/js/GatewayQuiz/gateway.js b/htdocs/js/GatewayQuiz/gateway.js index e1241e0a94..ee4024bd7f 100644 --- a/htdocs/js/GatewayQuiz/gateway.js +++ b/htdocs/js/GatewayQuiz/gateway.js @@ -188,6 +188,41 @@ if (actuallySubmit) return; + const inputs = Array.from(document.querySelectorAll('input, select')); + + // All problem numbers are represented by a probstatus hidden input. Use those to determine the problem + // numbers of problems in the test. Note that problem numbering displayed on the page will not match these + // numbers in the cases that the test definition has non-consecutive numbering or that problem order is + // randomized. But the problem numbering will always match the quiz prefix numbering. + const problems = []; + for (const input of inputs.filter((i) => /^probstatus\d*/.test(i.name))) { + problems[parseInt(input.name.replace('probstatus', ''))] = {}; + } + + // Determine which questions have been answered. Note that there can be multiple inputs for a + // given question (for example for checkbox or radio answers). + for (const input of inputs.filter( + (i) => /Q\d{4}_/.test(i.name) && !/^MaThQuIlL_/.test(i.name) && !/^previous_/.test(i.name) + )) { + const answered = + input.type === 'radio' || input.type === 'checkbox' ? !!input.checked : /\S/.test(input.value); + const match = /Q(\d{4})_/.exec(input.name); + const problemNumber = parseInt(match?.[1] ?? '0'); + if (!(input.name in problems[problemNumber])) problems[problemNumber][input.name] = answered; + else if (answered) problems[problemNumber][input.name] = 1; + } + + // Determine if there are any unanswered questions in each problem. + let numProblemsWithUnanswered = 0; + for (const problem of problems) { + // Skip problem 0 and any problems that don't exist in the test + // due to non-consecutive numbering in the test definition. + if (!problem) continue; + + if (!Object.keys(problem).length || !Object.values(problem).every((answered) => answered)) + ++numProblemsWithUnanswered; + } + // Prevent the gwquiz form from being submitted until after confirmation. evt.preventDefault(); @@ -219,8 +254,25 @@ const modalBody = document.createElement('div'); modalBody.classList.add('modal-body'); - const modalBodyContent = document.createElement('div'); + if (numProblemsWithUnanswered) { + const modalSecondaryContent = document.createElement('div'); + modalSecondaryContent.classList.add('mb-3'); + modalSecondaryContent.textContent = + (numProblemsWithUnanswered > 1 + ? submitAnswers.dataset.unansweredQuestionsMessage + ? submitAnswers.dataset.unansweredQuestionsMessage.replace('%d', numProblemsWithUnanswered) + : `There are ${numProblemsWithUnanswered} problems with unanswered questions.` + : (submitAnswers.dataset.unansweredQuestionMessage ?? + 'There is a problem with unanswered questions.')) + + ' ' + + (submitAnswers.dataset.returnToTestMessage ?? + 'Are you sure you want to grade the test? ' + + 'Select "No" if you would like to return to the test to enter more answers.'); + modalBody.append(modalSecondaryContent); + } + + const modalBodyContent = document.createElement('div'); modalBodyContent.textContent = submitAnswers.dataset.confirmDialogMessage; modalBody.append(modalBodyContent); diff --git a/htdocs/js/GatewayQuiz/gateway.scss b/htdocs/js/GatewayQuiz/gateway.scss index f7d450dff6..bb294426eb 100644 --- a/htdocs/js/GatewayQuiz/gateway.scss +++ b/htdocs/js/GatewayQuiz/gateway.scss @@ -1,13 +1,5 @@ /* gateway styles */ -div.gwMessage { - background-color: #ffeeaa; - box-shadow: 3px 3px 3px darkgray; - margin: 0 0 1rem 0; - padding: 0.25rem; - border-radius: 3px; -} - #gwTimer { position: sticky; width: 15em; @@ -60,7 +52,12 @@ table.attemptResults { border: 1px solid #ddd; border-radius: 3px; - h2 { + [data-bs-theme='dark'] & { + border-color: #555; + background-color: var(--bs-primary-bg-subtle, 'black'); + } + + h2.gw-problem-number { display: inline-block; font-size: 16px; margin-right: 5px; @@ -85,12 +82,17 @@ table.attemptResults { } colgroup.page { - border-left: solid 1pt black; - border-right: solid 1pt black; + border-left: solid 1pt var(--bs-emphasis-color, black); + border-right: solid 1pt var(--bs-emphasis-color, black); } .page.active { background-color: #ffeeaa; + + [data-bs-theme='dark'] & { + color: white; + background-color: #80690a; + } } } @@ -98,8 +100,9 @@ div.gwDivider { margin: 0px 0px 10px 0px; } -/* Override the pg style so that the problem-content is not offset in gateway quizzes. */ +/* Override the pg style so that the problem-content is not offset in gateway quizzes and force a light color scheme. */ .problem-content { + color-scheme: light; padding: unset; background-color: unset; border: unset; diff --git a/htdocs/js/MathJaxConfig/bs-color-scheme.js b/htdocs/js/MathJaxConfig/bs-color-scheme.js new file mode 100644 index 0000000000..589775edfa --- /dev/null +++ b/htdocs/js/MathJaxConfig/bs-color-scheme.js @@ -0,0 +1,87 @@ +if (MathJax.loader) MathJax.loader.checkVersion('[bs-color-scheme]', '4.1.1', 'extension'); + +const switchToBSStyle = (obj, key = '@media (prefers-color-scheme: dark)') => { + obj["[data-bs-theme='dark']"] = obj[key]; + delete obj[key]; + obj["[data-bs-theme='light']"] = structuredClone(obj); +}; + +for (const [immediate, extension, ready] of [ + [ + MathJax._.ui?.dialog, + 'core', + () => { + const { DraggableDialog } = MathJax._.ui.dialog.DraggableDialog; + switchToBSStyle(DraggableDialog.styles); + } + ], + [ + MathJax._.a11y?.explorer, + 'a11y/explorer', + () => { + const Region = MathJax._.a11y.explorer.Region; + for (const region of ['LiveRegion', 'HoverRegion', 'ToolTip']) { + if (':root' in Region[region].style.styles) { + Region[region].style.styles["[data-bs-theme='light']"] = Region[region].style.styles[':root']; + + // The variable --mjx-bg1-color is defined to be 'rgba(var(--mjx-bg-blue), var(--mjx-bg-alpha))'. + // I suspect this is a typo as the variable -mjx-bg-alpha is not defined anywhere. In any case this + // change is needed to get the correct background color on the focused element in the explorer. + Region[region].style.styles["[data-bs-theme='light']"]['--mjx-bg1-color'] = + 'rgba(var(--mjx-bg-blue), var(--mjx-bg1-alpha))'; + } + Region[region].style.styles["[data-bs-theme='dark']"] = + Region[region].style.styles['@media (prefers-color-scheme: dark)']; + if (':root' in Region[region].style.styles["[data-bs-theme='dark']"]) { + Object.assign( + Region[region].style.styles["[data-bs-theme='dark']"], + Region[region].style.styles["[data-bs-theme='dark']"][':root'] + ); + delete Region[region].style.styles["[data-bs-theme='dark']"][':root']; + } + Region[region].style.styles['@media (prefers-color-scheme: dark)'] = {}; + } + Region.LiveRegion.style.styles['@media (prefers-color-scheme: dark)']['mjx-ignore'] = { ignore: 1 }; + MathJax.startup.extendHandler((handler) => { + switchToBSStyle( + handler.documentClass.speechStyles, + '@media (prefers-color-scheme: dark) /* explorer */' + ); + return handler; + }); + } + ], + [ + MathJax._.output?.chtml, + 'output/chtml', + () => { + const { CHTML } = MathJax._.output.chtml_ts; + switchToBSStyle(CHTML.commonStyles); + const { ChtmlMaction } = MathJax._.output.chtml.Wrappers.maction; + switchToBSStyle(ChtmlMaction.styles, '@media (prefers-color-scheme: dark) /* chtml maction */'); + } + ], + [ + MathJax._.output?.svg, + 'output/svg', + () => { + const { SVG } = MathJax._.output.svg_ts; + switchToBSStyle(SVG.commonStyles); + const { SvgMaction } = MathJax._.output.svg.Wrappers.maction; + switchToBSStyle(SvgMaction.styles, '@media (prefers-color-scheme: dark) /* svg maction */'); + } + ] +]) { + if (immediate) { + ready(); + } else { + const config = MathJax.config.loader; + config[extension] ??= {}; + config[extension].extraLoads ??= []; + const check = config[extension].checkReady; + config[extension].checkReady = async () => { + if (check) await check(); + return ready(); + }; + } +} diff --git a/htdocs/js/MathJaxConfig/mathjax-config.js b/htdocs/js/MathJaxConfig/mathjax-config.js index 937f33393f..2b42f0928f 100644 --- a/htdocs/js/MathJaxConfig/mathjax-config.js +++ b/htdocs/js/MathJaxConfig/mathjax-config.js @@ -1,7 +1,10 @@ if (!window.MathJax) { window.MathJax = { - tex: { packages: { '[+]': ['noerrors'] } }, - loader: { load: ['input/asciimath', '[tex]/noerrors'] }, + tex: { packages: { '[+]': webworkConfig?.showMathJaxErrors ? [] : ['noerrors'] } }, + loader: { + load: ['input/asciimath', '[tex]/noerrors', '[bs-color-scheme]'], + paths: { 'bs-color-scheme': webworkConfig?.mathJaxBSColorSchemeUrl ?? './bs-color-scheme.js' } + }, startup: { ready() { const AM = MathJax.InputJax.AsciiMath.AM; @@ -98,24 +101,6 @@ if (!window.MathJax) { AM.symbols.splice(i, 0, { input: trigger, ...newTriggers[trigger].symbols }); } - // The following is a workaround for a bug in MathJax when the math renderer is changed. - // Note that this should be removed when we have upgraded to MathJax 4. - const { STATE } = MathJax._.core.MathItem; - const { Menu } = MathJax._.ui.menu.Menu; - const { mathjax } = MathJax._.mathjax; - Menu.prototype.rerender = function (start = STATE.TYPESET) { - this.rerenderStart = Math.min(start, this.rerenderStart); - if (!Menu.loading) { - if (this.rerenderStart <= STATE.COMPILED) this.document.reset({ inputJax: [] }); - MathJax.startup.promise.then(() => { - mathjax.handleRetriesFor(() => { - this.document.rerender(this.rerenderStart); - this.rerenderStart = STATE.LAST; - }); - }); - } - }; - return MathJax.startup.defaultReady(); } }, diff --git a/htdocs/js/PGCodeMirror/pgeditor.scss b/htdocs/js/PGCodeMirror/pgeditor.scss index 3f1cd895c1..384adc6d17 100644 --- a/htdocs/js/PGCodeMirror/pgeditor.scss +++ b/htdocs/js/PGCodeMirror/pgeditor.scss @@ -1,5 +1,5 @@ .code-mirror-editor { - border: 1px solid #ddd; + border: 1px solid var(--ww-layout-border-color, #ddd); min-height: 400px; overflow: auto; resize: vertical; @@ -25,7 +25,7 @@ // This style is used if the CodeMirror editor is disabled in localOverrides.conf. .text-area-editor { - border: 1px solid #ddd; + border: 1px solid var(--ww-layout-border-color, #ddd); padding: 2px; height: 550px; min-height: 400px; diff --git a/htdocs/js/PGProblemEditor/pgproblemeditor.js b/htdocs/js/PGProblemEditor/pgproblemeditor.js index 286840cc16..9f8f0162d7 100644 --- a/htdocs/js/PGProblemEditor/pgproblemeditor.js +++ b/htdocs/js/PGProblemEditor/pgproblemeditor.js @@ -1,5 +1,43 @@ (() => { + const renderURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/render_rpc`; + + for (const pgmlLabButton of document.querySelectorAll('.pgml-lab')) { + pgmlLabButton.addEventListener('click', (e) => { + e.preventDefault(); + const form = document.createElement('form'); + form.style.display = 'none'; + form.target = 'PGML'; + form.action = renderURL; + form.method = 'post'; + + const inputs = [ + ['courseID', document.getElementsByName('courseID')[0]?.value], + ['displayMode', document.getElementById('action_view_displayMode_id')?.value ?? 'MathJax'], + ['fileName', 'PGMLLab/PGML-lab.pg'], + ['uriEncodedProblemSource', pgmlLabButton.dataset.source] + ]; + + const user = document.getElementsByName('user')[0]; + if (user) inputs.push(['user', user.value]); + const sessionKey = document.getElementsByName('key')[0]; + if (sessionKey) inputs.push(['key', sessionKey.value]); + + for (const [name, value] of inputs) { + const input = document.createElement('input'); + input.name = name; + input.value = value; + input.type = 'hidden'; + form.append(input); + } + + document.body.append(form); + form.submit(); + form.remove(); + }); + } + const fileChooserForm = document.forms['pg-editor-file-chooser']; + if (fileChooserForm) { const newProblemRadio = document.getElementById('new_problem'); @@ -161,6 +199,15 @@ ?.addEventListener('change', () => (deleteBackupCheck.checked = true)); } + const renderArea = document.getElementById('pgedit-render-area'); + + const scrollToRenderArea = () => { + // Scroll to the top of the render window if the current scroll position is below that. + const renderAreaRect = renderArea.getBoundingClientRect(); + const topBarHeight = document.querySelector('.webwork-logo')?.getBoundingClientRect().height ?? 0; + if (renderAreaRect.top < topBarHeight) window.scrollBy(0, renderAreaRect.top - topBarHeight); + }; + // Send a request to the server to perltidy the current PG code in the CodeMirror editor. const tidyPGCode = () => { const request_object = { courseID: document.getElementsByName('courseID')[0]?.value }; @@ -199,7 +246,7 @@ if (webworkConfig?.pgCodeMirror) webworkConfig.pgCodeMirror.source = data.result_data.tidiedPGCode; else document.getElementById('problemContents').value = data.result_data.tidiedPGCode; saveTempFile(); - showMessage('Successfuly perltidied code.', true); + showMessage('Successfully perltidied code.', true); } }) .catch((err) => showMessage(`Error: ${err?.message ?? err}`)); @@ -235,15 +282,43 @@ .catch((err) => showMessage(`Error: ${err?.message ?? err}`)); }; + // Send a request to the server to run the PG critic in the CodeMirror editor. + const runPGCritic = () => { + const request_object = { courseID: document.getElementsByName('courseID')[0]?.value }; + + const user = document.getElementsByName('user')[0]; + if (user) request_object.user = user.value; + const sessionKey = document.getElementsByName('key')[0]; + if (sessionKey) request_object.key = sessionKey.value; + + request_object.rpc_command = 'runPGCritic'; + request_object.pgCode = + webworkConfig?.pgCodeMirror?.source ?? document.getElementById('problemContents')?.value ?? ''; + + fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) }) + .then((response) => response.json()) + .then((data) => { + if (data.error) throw new Error(data.error); + if (!data.result_data) throw new Error('An invalid response was received.'); + renderArea.innerHTML = data.result_data.html; + scrollToRenderArea(); + }) + .catch((err) => showMessage(`Error: ${err?.message ?? err}`)); + }; + document.getElementById('take_action')?.addEventListener('click', async (e) => { - if (document.getElementById('current_action')?.value === 'format_code') { + if (document.getElementById('current_action')?.value === 'code_maintenance') { e.preventDefault(); - if (document.querySelector('input[name="action.format_code"]:checked').value == 'tidyPGCode') { + if (document.querySelector('input[name="action.code_maintenance"]:checked').value === 'tidyPGCode') { tidyPGCode(); } else if ( - document.querySelector('input[name="action.format_code"]:checked').value == 'convertCodeToPGML' + document.querySelector('input[name="action.code_maintenance"]:checked').value === 'convertCodeToPGML' ) { convertCodeToPGML(); + } else if ( + document.querySelector('input[name="action.code_maintenance"]:checked').value === 'runPGCritic' + ) { + runPGCritic(); } return; } @@ -305,8 +380,6 @@ } }); - const renderURL = `${webworkConfig?.webwork_url ?? '/webwork2'}/render_rpc`; - const renderArea = document.getElementById('pgedit-render-area'); const fileType = document.getElementsByName('file_type')[0]?.value; // This is either the div containing the CodeMirror editor or the problemContents textarea in the case that @@ -350,6 +423,7 @@ const iframe = document.createElement('iframe'); iframe.title = 'Rendered content'; iframe.id = 'pgedit-render-iframe'; + iframe.style.colorScheme = 'light'; // Adjust the height of the iframe when the window is resized and when the iframe loads. const adjustIFrameHeight = () => { @@ -382,6 +456,7 @@ requestData.set('send_pg_flags', 1); requestData.set(button.name, button.value); requestData.set('set_id', document.getElementsByName('hidden_set_id')[0]?.value ?? 'Unknown Set'); + requestData.set('showMathJaxErrors', 1); await renderProblem(requestData); @@ -390,11 +465,7 @@ } adjustIFrameHeight(); - - // Scroll to the top of the render window if the current scroll position is below that. - const renderAreaRect = renderArea.getBoundingClientRect(); - const topBarHeight = document.querySelector('.webwork-logo')?.getBoundingClientRect().height ?? 0; - if (renderAreaRect.top < topBarHeight) window.scrollBy(0, renderAreaRect.top - topBarHeight); + scrollToRenderArea(); }); const render = () => @@ -473,7 +544,8 @@ displayMode: document.getElementById('action_view_displayMode_id')?.value ?? 'MathJax', language: document.querySelector('input[name="hidden_language"]')?.value ?? 'en', send_pg_flags: 1, - view_problem_debugging_info: 1 + view_problem_debugging_info: 1, + showMathJaxErrors: 1 }) ).then(() => resolve()); }); @@ -616,37 +688,4 @@ rendering = false; } }; - - const pgmlLabButton = document.getElementById('pgml-lab'); - pgmlLabButton?.addEventListener('click', () => { - const form = document.createElement('form'); - form.style.display = 'none'; - form.target = 'PGML'; - form.action = renderURL; - form.method = 'post'; - - const inputs = [ - ['courseID', document.getElementsByName('courseID')[0]?.value], - ['displayMode', document.getElementById('action_view_displayMode_id')?.value ?? 'MathJax'], - ['fileName', 'PGMLLab/PGML-lab.pg'], - ['uriEncodedProblemSource', pgmlLabButton.dataset.source] - ]; - - const user = document.getElementsByName('user')[0]; - if (user) inputs.push(['user', user.value]); - const sessionKey = document.getElementsByName('key')[0]; - if (sessionKey) inputs.push(['key', sessionKey.value]); - - for (const [name, value] of inputs) { - const input = document.createElement('input'); - input.name = name; - input.value = value; - input.type = 'hidden'; - form.append(input); - } - - document.body.append(form); - form.submit(); - form.remove(); - }); })(); diff --git a/htdocs/js/PODViewer/podviewer.css b/htdocs/js/PODViewer/podviewer.css deleted file mode 100644 index e4f17811d2..0000000000 --- a/htdocs/js/PODViewer/podviewer.css +++ /dev/null @@ -1,66 +0,0 @@ -.main-index-header, -.pod-header { - height: 65px; - top: 0; - left: 0; - right: 0; - z-index: 2; -} - -#sidebar { - --bs-offcanvas-width: 300px; - overflow-y: auto; -} - -#sidebar ul.nav ul.nav li { - border-left: 1px solid #e1e4e8; - padding-left: 10px; -} - -#sidebar ul.nav ul.nav li:hover { - border-left: 6px solid #e1e4e8; - padding-left: 5px; -} - -.main-index-container, -.pod-page-container { - margin-top: 65px; -} - -@media only screen and (min-width: 768px) { - #sidebar { - height: calc(100vh - 65px); - width: 300px; - } - - .pod-page-container { - margin-left: 300px; - } -} - -#_podtop_ pre { - border: 1px solid #ccc; - border-radius: 5px; - background: #f6f6f6; - padding: 0.75rem; -} - -#_podtop_, -#_podtop_ *[id] { - scroll-margin-top: calc(65px + 1rem); -} - -@media only screen and (max-width: 768px) { - .pod-header { - height: 100px; - } - - .pod-page-container { - margin-top: 100px; - } - - #_podtop_, - #_podtop_ *[id] { - scroll-margin-top: calc(100px + 1rem); - } -} diff --git a/htdocs/js/PODViewer/podviewer.js b/htdocs/js/PODViewer/podviewer.js deleted file mode 100644 index 795093205a..0000000000 --- a/htdocs/js/PODViewer/podviewer.js +++ /dev/null @@ -1,8 +0,0 @@ -(() => { - const offcanvas = bootstrap.Offcanvas.getOrCreateInstance(document.getElementById('sidebar')); - for (const link of document.querySelectorAll('#sidebar .nav-link')) { - // The timeout is to workaround an issue in Chrome. If the offcanvas hides before the window scrolls to the - // fragment in the page, scrolling stops before it gets there. - link.addEventListener('click', () => setTimeout(() => offcanvas.hide(), 500)); - } -})(); diff --git a/htdocs/js/ProblemGrader/problemgrader.js b/htdocs/js/ProblemGrader/problemgrader.js index 1e33408bbf..ada3727ecc 100644 --- a/htdocs/js/ProblemGrader/problemgrader.js +++ b/htdocs/js/ProblemGrader/problemgrader.js @@ -1,6 +1,45 @@ 'use strict'; (() => { + const setPointInputValue = (pointInput, score) => + (pointInput.value = parseFloat( + (Math.round((score * pointInput.max) / 100 / pointInput.step) * pointInput.step).toFixed(2) + )); + + // Update problem score if point value changes and is a valid value. + for (const pointInput of document.querySelectorAll('.problem-points')) { + pointInput.addEventListener('input', () => { + const userId = pointInput.id.replace(/\.points$/, ''); + if (pointInput.checkValidity()) { + const scoreInput = document.getElementById(`${userId}.score`); + if (scoreInput) { + scoreInput.classList.remove('is-invalid'); + scoreInput.value = Math.round((100 * pointInput.value) / pointInput.max); + } + pointInput.classList.remove('is-invalid'); + } else { + pointInput.classList.add('is-invalid'); + } + }); + } + + // Update problem points if score changes and is a valid value. + for (const scoreInput of document.querySelectorAll('.problem-score')) { + scoreInput.addEventListener('input', () => { + const userId = scoreInput.id.replace(/\.score$/, ''); + if (scoreInput.checkValidity()) { + const pointInput = document.getElementById(`${userId}.points`); + if (pointInput) { + pointInput.classList.remove('is-invalid'); + pointInput.value = setPointInputValue(pointInput, scoreInput.value); + } + scoreInput.classList.remove('is-invalid'); + } else { + scoreInput.classList.add('is-invalid'); + } + }); + } + const userSelect = document.getElementById('student_selector'); if (!userSelect) return; @@ -15,7 +54,8 @@ problemSeed: selectedUser.dataset.problemSeed, set_id: document.getElementsByName('hidden_set_id')[0]?.value, probNum: document.getElementsByName('hidden_problem_id')[0]?.value, - processAnswers: 1 + processAnswers: 1, + WWcorrectAns: 1 }; if (selectedUser.dataset.versionId) ro.version_id = selectedUser.dataset.versionId; diff --git a/htdocs/js/ProblemGrader/singleproblemgrader.js b/htdocs/js/ProblemGrader/singleproblemgrader.js index 002c5b7f0d..9c9f16fbe9 100644 --- a/htdocs/js/ProblemGrader/singleproblemgrader.js +++ b/htdocs/js/ProblemGrader/singleproblemgrader.js @@ -125,6 +125,7 @@ version_id: saveData.versionId, problem_id: saveData.problemId, status: parseInt(scoreInput.value) / 100, + ...(saveData.saveSubStatus === '1' ? { sub_status: parseInt(scoreInput.value) / 100 } : {}), mark_graded: true }), signal: controller.signal @@ -216,4 +217,141 @@ } }); } + + const settingStoreID = `WW.${document.getElementsByName('courseID')[0]?.value ?? 'unknownCourse'}.${ + document.getElementsByName('user')[0]?.value ?? 'unknownUser' + }.problem_grader`; + let gradersOpen = localStorage.getItem(`${settingStoreID}.open`) === 'true'; + + const graderCollapses = []; + + for (const grader of document.querySelectorAll('.problem-grader')) { + const problemId = grader.id.replace('problem-grader-'); + + grader.classList.add('accordion'); + + const accordionItem = document.createElement('div'); + accordionItem.classList.add('accordion-item'); + + const accordionHeader = document.createElement('h2'); + accordionHeader.classList.add('accordion-header'); + + const accordionButton = document.createElement('button'); + accordionButton.classList.add('accordion-button'); + accordionButton.type = 'button'; + accordionButton.textContent = grader.dataset.graderTitle ?? 'Problem Grader'; + accordionButton.dataset.bsToggle = 'collapse'; + accordionButton.dataset.bsTarget = `#problem-grader-collapse-${problemId}`; + accordionButton.setAttribute('aria-controls', `#problem-grader-collapse-${problemId}`); + accordionButton.setAttribute('aria-expanded', gradersOpen); + if (!gradersOpen) accordionButton.classList.add('collapsed'); + + accordionHeader.append(accordionButton); + + const accordionCollapse = document.createElement('div'); + accordionCollapse.classList.add('accordion-collapse', 'collapse'); + accordionCollapse.id = `problem-grader-collapse-${problemId}`; + accordionCollapse.dataset.bsParent = `problem-grader-${problemId}`; + if (gradersOpen) accordionCollapse.classList.add('show'); + + const accordionBody = grader.querySelector('.problem-grader-table'); + accordionBody.classList.add('accordion-body'); + accordionCollapse.append(accordionBody); + + accordionItem.append(accordionHeader, accordionCollapse); + grader.append(accordionItem); + + const graderCollapse = new bootstrap.Collapse(accordionCollapse, { toggle: false }); + graderCollapses.push(graderCollapse); + + grader.classList.remove('d-none'); + + // Expand or collapse all problem graders on the page when any one of them is expanded or collapsed. + let transitioning = false; + accordionCollapse.addEventListener('show.bs.collapse', () => { + if (transitioning) return; + transitioning = true; + for (const grader of graderCollapses) { + if (grader !== graderCollapse) grader.show(); + } + transitioning = false; + }); + accordionCollapse.addEventListener('hide.bs.collapse', () => { + if (transitioning) return; + transitioning = true; + for (const grader of graderCollapses) { + if (grader !== graderCollapse) grader.hide(); + } + transitioning = false; + }); + + // Make sure that the "Reveal" button in feedback is not shown if a feedback button is used while the problem + // grader is open. However, also make sure that the "Reveal" button is shown for any feedback button that is + // not used while the problem grader is open. + + const unrevealedFeedbackBtns = []; + + for (const feedbackBtn of document.querySelectorAll('.ww-feedback-btn')) { + const container = document.createElement('div'); + container.innerHTML = feedbackBtn.dataset.bsContent; + const button = container.querySelector('.reveal-correct-btn'); + if (!button) continue; + + button.nextElementSibling?.classList.remove('d-none'); + button.remove(); + + const fragment = new DocumentFragment(); + fragment.append(container); + + unrevealedFeedbackBtns.push([feedbackBtn, fragment.firstElementChild.innerHTML]); + + const handler = () => { + const index = unrevealedFeedbackBtns.findIndex((data) => data[0] === feedbackBtn); + if (index !== -1) { + if (gradersOpen) { + unrevealedFeedbackBtns.splice(index, 1); + feedbackBtn.removeEventListener('shown.bs.popover', handler); + } else { + bootstrap.Popover.getInstance(feedbackBtn) + ?.tip?.querySelector('.reveal-correct-btn') + ?.addEventListener( + 'click', + () => { + unrevealedFeedbackBtns.splice(index, 1); + feedbackBtn.removeEventListener('shown.bs.popover', handler); + }, + { once: true } + ); + } + } + }; + + feedbackBtn.addEventListener('shown.bs.popover', handler); + } + + const removeRevealButtons = () => { + for (const data of unrevealedFeedbackBtns) { + const feedbackPopover = bootstrap.Popover.getInstance(data[0]); + feedbackPopover?.setContent({ '.popover-body': data[1] }); + } + }; + + if (gradersOpen) removeRevealButtons(); + + // In addition to removing and putting back the feedback "Reveal" buttons as needed, + // preserve the collapsed/expanded status of the problem graders in local storage. + accordionCollapse.addEventListener('shown.bs.collapse', () => { + localStorage.setItem(`${settingStoreID}.open`, 'true'); + gradersOpen = true; + removeRevealButtons(); + }); + accordionCollapse.addEventListener('hidden.bs.collapse', () => { + gradersOpen = false; + localStorage.setItem(`${settingStoreID}.open`, 'false'); + for (const data of unrevealedFeedbackBtns) { + const feedbackPopover = bootstrap.Popover.getInstance(data[0]); + feedbackPopover?.setContent({ '.popover-body': data[0].dataset.bsContent }); + } + }); + } })(); diff --git a/htdocs/js/ProblemSetDetail/problemsetdetail.js b/htdocs/js/ProblemSetDetail/problemsetdetail.js index 93661d6739..1b9be297ee 100644 --- a/htdocs/js/ProblemSetDetail/problemsetdetail.js +++ b/htdocs/js/ProblemSetDetail/problemsetdetail.js @@ -467,4 +467,26 @@ const input = document.getElementById(btn.dataset.seedInput); if (input) btn.addEventListener('click', () => (input.value = Math.floor(Math.random() * 10000))); } + + // Handle mixed select/number input fields. + for (const numericSelect of document.querySelectorAll('.mixed-numeric-select')) { + const select = numericSelect.querySelector('select'); + const numberInput = numericSelect.querySelector('input'); + let currentNumberValue = numberInput.value !== '' ? numberInput.value : numberInput.min; + + const setNumericState = () => { + if (select.value === 'numeric') { + numberInput.value = currentNumberValue; + numberInput.disabled = false; + numberInput.required = true; + } else { + if (numberInput.value !== '') currentNumberValue = numberInput.value; + numberInput.value = ''; + numberInput.disabled = true; + numberInput.required = false; + } + }; + select.addEventListener('change', setNumericState); + setNumericState(); + } })(); diff --git a/htdocs/js/ProblemSetList/problemsetlist.js b/htdocs/js/ProblemSetList/problemsetlist.js index ca9f334853..8bd082360a 100644 --- a/htdocs/js/ProblemSetList/problemsetlist.js +++ b/htdocs/js/ProblemSetList/problemsetlist.js @@ -7,12 +7,12 @@ for (const id of ids) elements.push(document.getElementById(id)); for (const element of elements) { if (element?.id.endsWith('_err_msg')) { - element?.classList.remove('d-none'); - } else { - element?.classList.add('is-invalid'); + element.classList.remove('d-none'); + } else if (element) { + element.classList.add('is-invalid'); if (!(element.id in event_listeners)) { event_listeners[element.id] = hide_errors([], elements); - element?.addEventListener('change', event_listeners[element.id]); + element.addEventListener('change', event_listeners[element.id]); } } } @@ -23,17 +23,17 @@ for (const id of ids) elements.push(document.getElementById(id)); for (const element of elements) { if (element?.id.endsWith('_err_msg')) { - element?.classList.add('d-none'); + element.classList.add('d-none'); if (element.id === 'select_set_err_msg' && 'set_table_id' in event_listeners) { document .getElementById('set_table_id') ?.removeEventListener('change', event_listeners.set_table_id); delete event_listeners.set_table_id; } - } else { - element?.classList.remove('is-invalid'); + } else if (element) { + element.classList.remove('is-invalid'); if (element.id in event_listeners) { - element?.removeEventListener('change', event_listeners[element.id]); + element.removeEventListener('change', event_listeners[element.id]); delete event_listeners[element.id]; } } @@ -139,16 +139,32 @@ filter_select?.addEventListener('change', filterElementToggle); // This will make the popup menu alternate between a single selection and a multiple selection menu. - const importAmtSelect = document.getElementById('import_amt_select'); - if (importAmtSelect) { - importAmtSelect.addEventListener('change', () => { - const numSelect = document.problemsetlist['action.import.number']; - const number = parseInt(numSelect.options[numSelect.selectedIndex].value); - document.problemsetlist['action.import.source'].size = number; - document.problemsetlist['action.import.source'].multiple = number > 1 ? true : false; - document.problemsetlist['action.import.name'].value = number > 1 ? '(taken from filenames)' : ''; - document.problemsetlist['action.import.name'].readOnly = number > 1 ? true : false; - document.problemsetlist['action.import.name'].disabled = number > 1 ? true : false; + const numSelect = document.problemsetlist['action.import.number']; + if (numSelect) { + numSelect.addEventListener('change', () => { + const number = parseInt(numSelect.options[numSelect.selectedIndex]?.value ?? '1'); + const importSourceSelect = document.problemsetlist['action.import.source']; + if (importSourceSelect) { + importSourceSelect.size = number; + if (number === 1) { + if (!importSourceSelect.value) importSourceSelect.options[0].selected = true; + importSourceSelect.options[0].textContent = + importSourceSelect.dataset.selectSingleText ?? 'Select filename below'; + importSourceSelect.multiple = false; + } else { + importSourceSelect.options[0].textContent = + importSourceSelect.dataset.selectMultipleText ?? 'Select filename below'; + importSourceSelect.multiple = true; + importSourceSelect.options[0].selected = false; + } + } + const importNameInput = document.problemsetlist['action.import.name']; + if (importNameInput) { + importNameInput.value = + number > 1 ? (importNameInput.dataset.multipleFilesText ?? '(taken from filenames)') : ''; + importNameInput.readOnly = number > 1 ? true : false; + importNameInput.disabled = number > 1 ? true : false; + } }); } @@ -174,10 +190,15 @@ 'zh-HK': 'yyyy/L/d ah:mm' }; - // Initialize the date/time picker for the import form. + // Initialize the date/time picker for the import form and common date editor. + const dateInputs = []; const importDateShift = document.getElementById('import_date_shift'); - if (importDateShift) { - luxon.Settings.defaultLocale = importDateShift.dataset.locale ?? 'en'; + if (importDateShift) dateInputs.push(importDateShift); + const commonDateInput = document.getElementById('common-date'); + if (commonDateInput) dateInputs.push(commonDateInput); + + for (const dateInput of dateInputs) { + luxon.Settings.defaultLocale = dateInput.dataset.locale ?? 'en'; // Compute the time difference between a time in the browser timezone and the same time in the course timezone. // flatpickr gives the time in the browser's timezone, and this is used to adjust to the course timezone. @@ -189,17 +210,17 @@ new Date(dateTime.toLocaleString('en-US')).getTime() - new Date( dateTime.toLocaleString('en-US', { - timeZone: importDateShift.dataset.timezone ?? 'America/New_York' + timeZone: dateInput.dataset.timezone ?? 'America/New_York' }) ).getTime() ); }; - let fallbackDate = importDateShift.value - ? new Date(parseInt(importDateShift.value) * 1000 - timezoneAdjustment(parseInt(importDateShift.value))) + let fallbackDate = dateInput.value + ? new Date(parseInt(dateInput.value) * 1000 - timezoneAdjustment(parseInt(dateInput.value))) : new Date(); - const fp = flatpickr(importDateShift.parentNode, { + const fp = flatpickr(dateInput.parentNode, { allowInput: true, enableTime: true, minuteIncrement: 1, @@ -216,15 +237,15 @@ disableMobile: true, wrap: true, plugins: [ - new confirmDatePlugin({ confirmText: importDateShift.dataset.doneText, showAlways: true }), + new confirmDatePlugin({ confirmText: dateInput.dataset.doneText, showAlways: true }), new ShortcutButtonsPlugin({ button: [ { - label: importDateShift.dataset.todayText ?? 'Today', + label: dateInput.dataset.todayText ?? 'Today', attributes: { class: 'btn btn-sm btn-secondary ms-auto me-1 mb-1' } }, { - label: importDateShift.dataset.nowText ?? 'Now', + label: dateInput.dataset.nowText ?? 'Now', attributes: { class: 'btn btn-sm btn-secondary mx-auto mb-1' } } ], @@ -251,6 +272,10 @@ // Make the alternate input left-to-right even for right-to-left languages. this.altInput.dir = 'ltr'; + + // Move the id of the now hidden input onto the added input so the labels still work. + this.altInput.id = this.input.id; + this.input.removeAttribute('id'); }, parseDate(datestr, format) { // Deal with the case of a unix timestamp. The timezone needs to be adjusted back as this is for @@ -278,11 +303,46 @@ } }); - importDateShift.nextElementSibling.addEventListener('keydown', (e) => { + dateInput.nextElementSibling.addEventListener('keydown', (e) => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); fp.open(); } }); } + + if (commonDateInput) { + document.getElementById('apply-common-date')?.addEventListener('click', () => { + const dateTypeInput = document.getElementById('set-date-choice'); + if (!dateTypeInput?.value) { + show_errors(['choose_date_type_err_msg'], [dateTypeInput]); + return; + } + + if (!commonDateInput.value) { + show_errors( + ['choose_common_date_err_msg'], + [commonDateInput.parentNode?._flatpickr?.input, commonDateInput.parentNode?._flatpickr?.altInput] + ); + return; + } + + const selectedSets = Array.from(document.getElementsByName('apply_date_sets')).filter((c) => c.checked); + if (!selectedSets.length) { + show_errors(['select_set_err_msg'], []); + event_listeners.set_table_id = hide_errors( + ['set_table_id'], + [document.getElementById('select_set_err_msg')] + ); + document.getElementById('set_table_id')?.addEventListener('change', event_listeners.set_table_id); + } + + for (const set of selectedSets) { + const inputPicker = document.getElementsByName(`set.${set.value}.${dateTypeInput.value}`)[0]?.parentNode + ?._flatpickr; + inputPicker?.setDate(commonDateInput.value, true); + inputPicker?.close(); // The picker isn't actually open, but this triggers the onClose handler. + } + }); + } })(); diff --git a/htdocs/js/RenderProblem/renderproblem.js b/htdocs/js/RenderProblem/renderproblem.js index ec4503a64a..f3bb2bbebb 100644 --- a/htdocs/js/RenderProblem/renderproblem.js +++ b/htdocs/js/RenderProblem/renderproblem.js @@ -69,6 +69,7 @@ iframe = document.createElement('iframe'); iframe.id = `${renderArea.id}_iframe`; iframe.style.border = 'none'; + iframe.style.colorScheme = 'light'; while (renderArea.firstChild) renderArea.firstChild.remove(); renderArea.append(iframe); diff --git a/htdocs/js/SampleProblemViewer/documentation-search.js b/htdocs/js/SampleProblemViewer/documentation-search.js deleted file mode 100644 index 5e61bc64ec..0000000000 --- a/htdocs/js/SampleProblemViewer/documentation-search.js +++ /dev/null @@ -1,76 +0,0 @@ -(async () => { - const searchBox = document.getElementById('search-box'); - const resultList = document.getElementById('result-list'); - if (!resultList || !searchBox) return; - - const webwork2URL = webworkConfig?.webwork_url ?? '/webwork2'; - - let searchData; - try { - const result = await fetch(`${webwork2URL}/sampleproblems/search_data`); - searchData = await result.json(); - } catch (e) { - console.log(e); - return; - } - - const miniSearch = new MiniSearch({ - fields: ['filename', 'name', 'description', 'terms', 'macros', 'subjects'], - storeFields: ['type', 'filename', 'dir', 'description'] - }); - miniSearch.addAll(searchData); - - const searchMacrosCheck = document.getElementById('search-macros'); - const searchSampleProblemsCheck = document.getElementById('search-sample-problems'); - - document.getElementById('clear-search-button')?.addEventListener('click', () => { - searchBox.value = ''; - while (resultList.firstChild) resultList.firstChild.remove(); - }); - - const searchDocumentation = () => { - const searchMacros = searchMacrosCheck?.checked; - const searchSampleProblems = searchSampleProblemsCheck?.checked; - - while (resultList.firstChild) resultList.firstChild.remove(); - - if (!searchBox.value) return; - - for (const result of miniSearch.search(searchBox.value, { prefix: true })) { - if ( - (searchSampleProblems && result.type === 'sample problem') || - (searchMacros && result.type === 'macro') - ) { - const link = document.createElement('a'); - link.classList.add('list-group-item', 'list-group-item-action'); - link.href = `${webwork2URL}/${ - result.type === 'sample problem' ? 'sampleproblems' : result.type === 'macro' ? 'pod' : '' - }/${result.dir}/${result.filename.replace('.pg', '')}`; - - const linkText = document.createElement('span'); - linkText.classList.add('h4'); - linkText.textContent = `${result.filename} (${result.type})`; - link.append(linkText); - - if (result.description) { - const summary = document.createElement('div'); - summary.textContent = result.description; - link.append(summary); - } - - resultList.append(link); - } - } - - if (resultList.children.length == 0) { - const item = document.createElement('div'); - item.classList.add('alert', 'alert-info'); - item.innerHTML = 'No results found'; - resultList.append(item); - } - }; - - searchBox.addEventListener('keyup', searchDocumentation); - searchMacrosCheck?.addEventListener('change', searchDocumentation); - searchSampleProblemsCheck?.addEventListener('change', searchDocumentation); -})(); diff --git a/htdocs/js/SetMaker/setmaker.js b/htdocs/js/SetMaker/setmaker.js index 581c165371..566774c053 100644 --- a/htdocs/js/SetMaker/setmaker.js +++ b/htdocs/js/SetMaker/setmaker.js @@ -79,6 +79,17 @@ const countLine = document.getElementById('library_count_line'); + const settingStoreID = `WW.${document.getElementsByName('hidden_course_id')[0]?.value ?? 'unknownCourse'}.${ + document.getElementsByName('user')[0]?.value ?? 'unknownUser' + }.setmaker`; + const includeOPLInitialStatus = includeOPL?.checked; + const includeContribInitialStatus = includeContrib?.checked; + if (includeOPL) + includeOPL.checked = localStorage.getItem(`${settingStoreID}.includeOPLChecked`) !== 'false' ? true : false; + if (includeContrib) + includeContrib.checked = + localStorage.getItem(`${settingStoreID}.includeContribChecked`) !== 'false' ? true : false; + const lib_update = async (who, what) => { const child = { subject: 'chapter', chapter: 'section', section: 'count' }; @@ -200,11 +211,22 @@ libraryChapter?.addEventListener('change', () => lib_update('section', 'get')); librarySubject?.addEventListener('change', () => lib_update('chapter', 'get')); librarySection?.addEventListener('change', () => lib_update('count', 'clear')); - includeOPL?.addEventListener('change', () => lib_update('count', 'clear')); - includeContrib?.addEventListener('change', () => lib_update('count', 'clear')); + includeOPL?.addEventListener('change', () => { + localStorage.setItem(`${settingStoreID}.includeOPLChecked`, includeOPL.checked); + lib_update('count', 'clear'); + }); + includeContrib?.addEventListener('change', () => { + localStorage.setItem(`${settingStoreID}.includeContribChecked`, includeContrib.checked); + lib_update('count', 'clear'); + }); levels.forEach((level) => level.addEventListener('change', () => lib_update('count', 'clear'))); libraryKeywords?.addEventListener('change', () => lib_update('count', 'clear')); + // If the local storage status of the checks are different than what they + // were when the page loaded, then the count needs to be updated. + if (includeOPL?.checked !== includeOPLInitialStatus || includeContrib?.checked !== includeContribInitialStatus) + lib_update('count', 'clear'); + // Set up the advanced view selects to submit the form when changed. const libraryBrowserForm = document.forms['library_browser_form']; if (libraryBrowserForm) { diff --git a/htdocs/js/System/color-scheme.js b/htdocs/js/System/color-scheme.js new file mode 100644 index 0000000000..cf0164193a --- /dev/null +++ b/htdocs/js/System/color-scheme.js @@ -0,0 +1,75 @@ +'use strict'; + +(() => { + const getPreferredTheme = () => { + const storedTheme = localStorage.getItem('WW.color-scheme'); + if (storedTheme) return storedTheme; + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + }; + + let flatpickrDarkTheme; + + const setTheme = (theme) => { + const themeValue = + theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme; + document.documentElement.setAttribute('data-bs-theme', themeValue); + + if (!flatpickrDarkTheme) flatpickrDarkTheme = document.getElementById('flatpickr-dark-theme'); + if (flatpickrDarkTheme) { + if (themeValue === 'dark') document.head.append(flatpickrDarkTheme); + else flatpickrDarkTheme.remove(); + } + }; + + setTheme(getPreferredTheme()); + + const showActiveTheme = (theme, focus = false) => { + const themeSwitcher = document.getElementById('color-scheme-chooser'); + if (!themeSwitcher) return; + + const activeThemeIcon = themeSwitcher.querySelector('.theme-icon-active'); + const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`); + + for (const element of document.querySelectorAll('[data-bs-theme-value]')) { + element.classList.remove('active'); + element.setAttribute('aria-pressed', 'false'); + } + + btnToActive.classList.add('active'); + btnToActive.setAttribute('aria-pressed', 'true'); + activeThemeIcon.classList.remove('fa-sun', 'fa-moon', 'fa-circle-half-stroke'); + activeThemeIcon.classList.add( + theme === 'light' ? 'fa-sun' : theme === 'dark' ? 'fa-moon' : 'fa-circle-half-stroke' + ); + themeSwitcher.setAttribute( + 'aria-label', + `${themeSwitcher.title} (${ + themeSwitcher.dataset[`${btnToActive.dataset.bsThemeValue}Text`] ?? btnToActive.dataset.bsThemeValue + })` + ); + + if (focus) themeSwitcher.focus(); + }; + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = localStorage.getItem('WW.color-scheme'); + if (storedTheme !== 'light' && storedTheme !== 'dark') { + const preferredTheme = getPreferredTheme(); + setTheme(preferredTheme); + showActiveTheme(preferredTheme); + } + }); + + window.addEventListener('DOMContentLoaded', () => { + showActiveTheme(getPreferredTheme()); + + for (const toggle of document.querySelectorAll('[data-bs-theme-value]')) { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value'); + localStorage.setItem('WW.color-scheme', theme); + setTheme(theme); + showActiveTheme(theme, true); + }); + } + }); +})(); diff --git a/htdocs/js/System/system.js b/htdocs/js/System/system.js index 634f07a87c..4b32aca942 100644 --- a/htdocs/js/System/system.js +++ b/htdocs/js/System/system.js @@ -74,7 +74,8 @@ // FIXME: These are really general purpose tooltips and not just in the homework sets editor. So the class name // should be chosen to better reflect this. document.querySelectorAll('.set-id-tooltip').forEach((el) => { - if (el.dataset.bsTitle) new bootstrap.Tooltip(el, { fallbackPlacements: [] }); + if (el.dataset.bsTitle) + new bootstrap.Tooltip(el, { fallbackPlacements: el.dataset.fallbackPlacements?.split(' ') || [] }); }); // Hardcopy tooltips shown on the Problem Sets page. diff --git a/htdocs/js/System/system.scss b/htdocs/js/System/system.scss index c6a9468d58..29d6276f95 100644 --- a/htdocs/js/System/system.scss +++ b/htdocs/js/System/system.scss @@ -3,7 +3,7 @@ table caption { font-weight: bold; font-size: larger; - color: black; + color: var(--bs-emphasis-color, black); } .help-popup { @@ -20,6 +20,10 @@ table caption { .required-field { color: #dc3545; + + [data-bs-theme='dark'] & { + color: #f85149; + } } .visually-hidden-focusable:active, @@ -28,7 +32,6 @@ table caption { } $masthead-height: 70px !default; -$layout-divider-color: #aaa !default; $site-nav-width: 250px !default; /* Banner */ @@ -40,7 +43,7 @@ $site-nav-width: 250px !default; display: flex; height: $masthead-height; background-color: var(--bs-primary, #038); - border-bottom: 1px solid $layout-divider-color; + border-bottom: 1px solid var(--ww-layout-divider-color, #aaa); margin: 0; padding: 0; z-index: 20; @@ -63,7 +66,8 @@ $site-nav-width: 250px !default; display: flex; align-items: center; justify-content: space-between; - padding: 5px 0; + padding: 5px 0.5rem; + gap: 0.25rem; background-color: var(--ww-logo-background-color, #104aad); z-index: 20; width: $site-nav-width; @@ -83,18 +87,18 @@ $site-nav-width: 250px !default; } } - a, - span { + a { display: inline-block; - margin-right: 0.5rem; } } .institution-logo { display: flex; flex-grow: 1; + gap: 2rem; align-items: center; - padding: 8px 0; + justify-content: space-between; + padding: 0; max-height: $masthead-height - 1px; @media only screen and (max-width: 768px) { @@ -108,8 +112,14 @@ $site-nav-width: 250px !default; a { display: block; - margin-left: 0.5rem; - margin-right: 0.5rem; + } + + #color-scheme-chooser { + --bs-btn-color: var(--ww-primary-foreground-color, white) !important; + --bs-btn-hover-color: var(--ww-color-chooser-hover-color, #ccc); + --bs-btn-active-color: var(--ww-color-chooser-hover-color, #ccc); + --bs-btn-focus-shadow-rgb: var(--ww-color-chooser-focus-outline-color-rgb, 255, 255, 255); + text-decoration: none; } } @@ -118,16 +128,11 @@ $site-nav-width: 250px !default; height: $masthead-height - 1px; padding: 4px 10px 4px 0; color: var(--ww-primary-foreground-color, white); - text-align: right; font-size: 0.85em; font-weight: normal; a { color: black; - - &:first-child { - margin-bottom: 5px; - } } } } @@ -144,7 +149,7 @@ $site-nav-width: 250px !default; overflow-y: auto; transition-property: left, border-right-width; transition-duration: 0.3s; - border-right: 1px solid $layout-divider-color; + border-right: 1px solid var(--ww-layout-divider-color, #aaa); padding: 2px; &.toggle-width { @@ -176,7 +181,7 @@ $site-nav-width: 250px !default; .info-box { border-radius: 0; border: none; - border-top: 1px solid $layout-divider-color; + border-top: 1px solid var(--ww-layout-divider-color, #aaa); } .nav { @@ -208,7 +213,7 @@ $site-nav-width: 250px !default; padding-right: 0; li a:hover { - background: #e1e1e1; + background: var(--ww-site-nav-link-hover-background-color, #e1e1e1); } ul.nav { @@ -268,22 +273,15 @@ $site-nav-width: 250px !default; } #toggle-sidebar { - #toggle-sidebar-icon i { - padding: 0.25rem; - border-radius: 5px; - color: rgba(255, 255, 255, 0.85); - transition: - color 0.15s ease-in-out, - background-color 0.15s ease-in-out, - border-color 0.15s ease-in-out; - - &:hover { - color: #fff; - } - } + --bs-navbar-color: rgba(var(--ww-toggle-sidebar-icon-color-rgb, 255, 255, 255), 0.85); + --bs-navbar-toggler-border-radius: 0.375rem; + --bs-navbar-toggler-focus-width: 0.25rem; + --bs-navbar-toggler-padding-x: 0.25rem; + --bs-navbar-toggler-padding-y: 0.25rem; + --bs-navbar-toggler-transition: box-shadow 0.15s ease-in-out; - &:focus #toggle-sidebar-icon i { - outline: 1px solid var(--bs-link-hover-color); + &:hover { + --bs-navbar-color: var(--ww-toggle-sidebar-icon-hover-color, #fff); } } @@ -297,6 +295,12 @@ $site-nav-width: 250px !default; margin-bottom: 10px; align-items: center; + [data-bs-theme='dark'] & { + box-shadow: + inset 0 0 3px 2px #000, + 0 0 2px 1px #fff; + } + .progress-bar { box-shadow: inset 0 0 3px 2px #000; height: 100%; @@ -329,6 +333,7 @@ $site-nav-width: 250px !default; /* Show me another */ div.showMeAnotherBox { + color: #212529; background-color: #ede275; border-radius: 5px; border: 2px solid #fdd017; @@ -344,7 +349,7 @@ div.showMeAnotherBox { padding-left: 0.5rem; min-height: 38px; align-items: center; - border: 1px solid #e6e6e6; + border: 1px solid var(--ww-layout-border-color, #e6e6e6); border-radius: 4px; } } @@ -362,10 +367,6 @@ h1.page-title { } } -h2.page-title { - border-bottom: 1px solid #ccc; -} - .problem-sub-header { margin-top: 0.25rem; font-weight: bold; @@ -373,13 +374,6 @@ h2.page-title { line-height: 1.4; } -.Warnings { - code { - white-space: normal; - color: inherit; - } -} - .error-output { word-wrap: break-word; color: #d63384; @@ -387,6 +381,10 @@ h2.page-title { direction: ltr; font-family: monospace; font-size: 9pt; + + [data-bs-theme='dark'] & { + color: var(--bs-danger-text-emphasis); + } } /* Question nav section */ @@ -396,10 +394,10 @@ h2.page-title { gap: 0.5rem; align-content: space-between; justify-content: space-between; - z-index: 20; + z-index: 19; position: sticky; top: $masthead-height; - background-color: white; + background-color: var(--bs-body-bg, white); margin-bottom: 1rem; padding: 0.25rem; margin-left: 0; @@ -449,6 +447,10 @@ h2.page-title { width: 60%; padding: 10px; text-align: left; + + [data-bs-theme='dark'] & { + background-color: #292900; + } } /* Home Page */ @@ -457,7 +459,7 @@ ul.courses-list { margin: 0; a { - border: 1px solid #e6e6e6; + border: 1px solid var(--ww-layout-border-color, #e6e6e6); display: block; padding: 0.5em; margin-bottom: 0.5em; @@ -465,6 +467,11 @@ ul.courses-list { width: 95%; font-weight: bold; + [data-bs-theme='dark'] & { + background: var(--bs-primary-bg-subtle, black); + color: var(--bs-primary-text-emphasis, white); + } + &:hover { text-decoration: none; background: var(--bs-primary, #038); @@ -493,11 +500,28 @@ ul.courses-list { td { white-space: nowrap; min-width: 20px; + + &.correct { + color: #060; + } + + &.incorrect { + color: #600; + } + + [data-bs-theme='dark'] & { + &.correct { + color: #0b0; + } + + &.incorrect { + color: #f66; + } + } } .table-rule { - border-top: 3px solid #d5d5d5; - padding-top: 5px; + border-top: 3px solid var(--ww-layout-divider-color); } .essay, @@ -583,7 +607,7 @@ ul.courses-list { .info-box { padding: 0.5em; border-radius: 8px; - border: 1px solid #e6e6e6; + border: 1px solid var(--ww-layout-border-color, #e6e6e6); h2, h3, @@ -660,6 +684,10 @@ ul.courses-list { background-color: #f5f5f5; margin-top: 10px; margin-bottom: 0; + + [data-bs-theme='dark'] & { + background-color: var(--bs-primary-bg-subtle, 'black'); + } } .lb-mlt-group { @@ -710,6 +738,14 @@ div.AuthorComment { a { color: #555; } + + [data-bs-theme='dark'] & { + color: #c6c6c6; + + a { + color: #999; + } + } } input.changed[type='text'] { @@ -740,6 +776,11 @@ input.changed[type='text'] { border-spacing: 2px; border-color: gray; border-radius: 0.25rem; + + [data-bs-theme='dark'] & { + background-color: #4a4a4a; + border-color: #939393; + } } .submit-buttons-container { @@ -760,28 +801,39 @@ input.changed[type='text'] { font-style: italic; color: #ca5000; background-color: inherit; + + [data-bs-theme='dark'] & { + color: #ca8253; + } } /* Text colors for Auditing, Current, and Dropped students */ .Audit { font-style: normal; color: purple; - background-color: inherit; } .Enrolled { font-weight: normal; - color: black; - background-color: inherit; } .Drop { font-style: italic; color: #555; - background-color: inherit; } .Observer { font-style: normal; color: green; - background-color: inherit; +} + +[data-bs-theme='dark'] { + .Audit { + color: #f400f4; + } + .Drop { + color: #958888; + } + .Observer { + color: #04a404; + } } /* Styles for the PGProblemEditor Page */ @@ -793,7 +845,7 @@ input.changed[type='text'] { } #pgedit-render-area { - border: 1px solid #ddd; + border: 1px solid var(--ww-layout-border-color, #ddd); min-height: 400px; height: 600px; resize: vertical; @@ -854,6 +906,14 @@ input.changed[type='text'] { .table { --bs-table-bg: #f5f5f5; } + + [data-bs-theme='dark'] & { + background-color: var(--bs-primary-bg-subtle, 'black'); + + .table { + --bs-table-bg: var(--bs-primary-bg-subtle, 'black'); + } + } } .pdr_placeholder { @@ -908,6 +968,10 @@ input.changed[type='text'] { .rpc_render_area_container { background-color: #f5f5f5; + + [data-bs-theme='dark'] & { + background-color: var(--bs-primary-bg-subtle, 'black'); + } } .rpc_render_area iframe { @@ -943,6 +1007,21 @@ input.changed[type='text'] { color: inherit; background-color: #88ecff; } + + [data-bs-theme='dark'] & { + &.correct { + color: black; + } + + &.incorrect { + color: white; + background-color: #bf5454; + } + + &.unattempted { + color: black; + } + } } } @@ -953,6 +1032,10 @@ input.changed[type='text'] { font-weight: bold; color: inherit; border-radius: 0; + + &:focus-visible { + box-shadow: 0 0 0 0.25rem var(--ww-course-config-tab-link-focus-outline-color, #00338840); + } } &:not(.active) { @@ -964,12 +1047,30 @@ input.changed[type='text'] { color: inherit; } + [data-bs-theme='dark'] & { + &:not(.active) { + background-color: #565656; + } + + &:not(.active):hover { + background-color: #414141; + } + } + &:focus { z-index: 2; } } } +/* Stats */ + +[data-bs-theme='dark'] .stats-image { + text { + fill: white; + } +} + /* File manager */ .file-manager-btn { margin-bottom: 0.25rem; @@ -988,25 +1089,55 @@ input.changed[type='text'] { /* Problem graders */ -span.needs-grading, -td.needs-grading { - background-color: #fff3cd; +#problem-grader-form { + .needs-grading { + background-color: #fff3cd; - div { - font-weight: bold; + [data-bs-theme='dark'] & { + background-color: #261d00; + } + + div { + font-weight: bold; + } } -} -span.alt-source, -td.alt-source { - background-color: #e6e7e9; -} + .alt-source { + background-color: #e6e7e9; -#problem-grader-form { - .past-answer:not(:last-child) { - border-bottom: 1px solid #d5d5d5; - margin-bottom: 2px; - padding-bottom: 5px; + [data-bs-theme='dark'] & { + background-color: #555; + } + } + + .problem-grader-legend-key span { + border: 1px solid var(--ww-layout-border-color); + } + + .past-answer { + &:not(:last-child) { + border-bottom: 1px solid var(--bs-table-border-color); + margin-bottom: 2px; + padding-bottom: 5px; + } + + &.correct { + color: #060; + } + + &.incorrect { + color: #600; + } + + [data-bs-theme='dark'] & { + &.correct { + color: #0b0; + } + + &.incorrect { + color: #f66; + } + } } .restricted-width-col { @@ -1018,6 +1149,17 @@ td.alt-source { } } +.problem-grader.accordion { + .accordion-header { + .accordion-button { + --bs-accordion-btn-padding-x: 0.75rem; + --bs-accordion-btn-padding-y: 0.375rem; + --bs-accordion-btn-bg: var(--bs-primary, #038); + --bs-accordion-btn-color: var(--ww-primary-foreground-color, white); + } + } +} + .problem-grader-table { .col-fixed { width: 11rem; @@ -1054,3 +1196,13 @@ td.alt-source { width: 100%; } } + +mjx-help-background { + z-index: 1055; +} + +[data-bs-theme='dark'] .flatpickr-confirm { + svg { + fill: white; + } +} diff --git a/htdocs/js/TagWidget/tagwidget.js b/htdocs/js/TagWidget/tagwidget.js index 7961a17ca7..3ac04cd62b 100644 --- a/htdocs/js/TagWidget/tagwidget.js +++ b/htdocs/js/TagWidget/tagwidget.js @@ -48,7 +48,7 @@ // Load the library taxonomy from the JSON file. const response = await fetch(tagWidgetScript.dataset.taxonomy).catch( - (err) => `Could not load the OPL taxonomy from the server: ${err.messsage ?? err}` + (err) => `Could not load the OPL taxonomy from the server: ${err.message ?? err}` ); if (typeof response === 'string') return showMessage(response); if (!response.ok) return showMessage('Could not load the OPL taxonomy from the server.'); diff --git a/htdocs/js/UserList/userlist.js b/htdocs/js/UserList/userlist.js index 617594371f..483dbc1e19 100644 --- a/htdocs/js/UserList/userlist.js +++ b/htdocs/js/UserList/userlist.js @@ -58,7 +58,7 @@ } } else { element?.classList.remove('is-invalid'); - if (element.id in event_listeners) { + if (element && element.id in event_listeners) { element?.removeEventListener('change', event_listeners[element.id]); delete event_listeners[element.id]; } diff --git a/htdocs/package-lock.json b/htdocs/package-lock.json index 93decee0cd..d85d7fcdae 100644 --- a/htdocs/package-lock.json +++ b/htdocs/package-lock.json @@ -7,35 +7,35 @@ "name": "webwork.javascript_package_manager", "license": "GPL-2.0+", "dependencies": { - "@fortawesome/fontawesome-free": "^6.5.2", - "@openwebwork/pg-codemirror-editor": "^0.0.5", - "bootstrap": "~5.3.3", + "@fortawesome/fontawesome-free": "^7.0.0", + "@openwebwork/pg-codemirror-editor": "^0.0.9", + "bootstrap": "~5.3.7", "flatpickr": "^4.6.13", - "iframe-resizer": "^4.3.11", + "iframe-resizer": "^4.4.2", "jquery": "^3.7.1", - "jquery-ui-dist": "^1.13.2", - "luxon": "^3.4.4", - "mathjax": "^3.2.2", + "jquery-ui-dist": "^1.13.3", + "luxon": "^3.7.1", + "mathjax": "^4.1.1", "minisearch": "^7.1.2", "shortcut-buttons-flatpickr": "^0.4.0", - "sortablejs": "^1.15.2" + "sortablejs": "^1.15.6" }, "devDependencies": { - "autoprefixer": "^10.4.19", - "chokidar": "^3.6.0", - "cssnano": "^6.1.2", - "postcss": "^8.4.38", - "prettier": "^3.2.5", - "rtlcss": "^4.1.1", - "sass": "^1.75.0", - "terser": "^5.30.4", - "yargs": "^17.7.2" + "autoprefixer": "^10.4.21", + "chokidar": "^4.0.3", + "cssnano": "^7.1.0", + "postcss": "^8.5.6", + "prettier": "^3.6.2", + "rtlcss": "^4.3.0", + "sass": "^1.90.0", + "terser": "^5.43.1", + "yargs": "^18.0.0" } }, "node_modules/@codemirror/autocomplete": { - "version": "6.18.6", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz", - "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", + "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -45,9 +45,9 @@ } }, "node_modules/@codemirror/commands": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz", - "integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz", + "integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==", "license": "MIT", "dependencies": { "@codemirror/language": "^6.0.0", @@ -70,9 +70,9 @@ } }, "node_modules/@codemirror/lang-html": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz", - "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==", + "version": "6.4.11", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", + "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.0.0", @@ -83,7 +83,7 @@ "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/css": "^1.1.0", - "@lezer/html": "^1.3.0" + "@lezer/html": "^1.3.12" } }, "node_modules/@codemirror/lang-javascript": { @@ -116,9 +116,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz", - "integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==", + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", + "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -130,9 +130,9 @@ } }, "node_modules/@codemirror/lint": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz", - "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==", + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz", + "integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.0.0", @@ -173,9 +173,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.37.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz", - "integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==", + "version": "6.38.8", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.8.tgz", + "integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==", "license": "MIT", "dependencies": { "@codemirror/state": "^6.5.0", @@ -185,26 +185,23 @@ } }, "node_modules/@fortawesome/fontawesome-free": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.2.tgz", - "integrity": "sha512-hRILoInAx8GNT5IMkrtIt9blOdrqHOnPBH+k70aWUAqPZPgopb9G5EQJFpaBx/S8zp2fC+mPW349Bziuk1o28Q==", - "hasInstallScript": true, + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.0.tgz", + "integrity": "sha512-X48nISrSOa89zu2VMljC4XaRf8NmgTwQBVHfS2Nu5G00ZwM31oOVrAtGxZF3b6wDYf9lJsf/Eq4cCSFKIkOWPQ==", + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", "engines": { "node": ">=6" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -212,55 +209,50 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@lezer/common": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", - "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.4.0.tgz", + "integrity": "sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==", "license": "MIT" }, "node_modules/@lezer/css": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.2.1.tgz", - "integrity": "sha512-2F5tOqzKEKbCUNraIXc0f6HKeyKlmMWJnBB0i4XW6dJgssrZO/YlZ2pY5xgyqDleqqhiNJ3dQhbrV2aClZQMvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz", + "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -269,18 +261,18 @@ } }, "node_modules/@lezer/highlight": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", - "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", "license": "MIT", "dependencies": { - "@lezer/common": "^1.0.0" + "@lezer/common": "^1.3.0" } }, "node_modules/@lezer/html": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz", - "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz", + "integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -289,9 +281,9 @@ } }, "node_modules/@lezer/javascript": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz", - "integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", "license": "MIT", "dependencies": { "@lezer/common": "^1.2.0", @@ -300,9 +292,9 @@ } }, "node_modules/@lezer/lr": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", - "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.4.tgz", + "integrity": "sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==", "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" @@ -325,27 +317,33 @@ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", "license": "MIT" }, + "node_modules/@mathjax/mathjax-newcm-font": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@mathjax/mathjax-newcm-font/-/mathjax-newcm-font-4.1.1.tgz", + "integrity": "sha512-LeV5AWzoR7k/k2tg5mW0Ad3Jr9oK9guW/zBUIP8aoiIZcZIhvAV9dlbtUSqSe1wgEBUP1KOcJXcrE/NxOqkxlQ==", + "license": "Apache-2.0" + }, "node_modules/@openwebwork/codemirror-lang-pg": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@openwebwork/codemirror-lang-pg/-/codemirror-lang-pg-0.0.3.tgz", - "integrity": "sha512-ZKtb2r0Ck6tVz44wwMKY7w/82P470whIzM5C8pi2GiBlnFWmkQcadmOaCBz31FELY1SrKE3AO2TmMrwUt2EKPA==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@openwebwork/codemirror-lang-pg/-/codemirror-lang-pg-0.0.4.tgz", + "integrity": "sha512-lNA9PVTRDNWfmL87ux3zbFQfih+6tXKJdz+yA1CPbHWaNuNY+OK9dur+Ul5H6Hi6flGWlcE674/eMmkelLRAng==", "license": "MIT", "dependencies": { - "@codemirror/language": "^6.11.0", - "@lezer/highlight": "^1.2.1", - "@lezer/lr": "^1.4.2" + "@codemirror/language": "^6.11.3", + "@lezer/highlight": "^1.2.3", + "@lezer/lr": "^1.4.4" } }, "node_modules/@openwebwork/pg-codemirror-editor": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@openwebwork/pg-codemirror-editor/-/pg-codemirror-editor-0.0.5.tgz", - "integrity": "sha512-ue4aciJzF7PPdQwWvYQkSf7h3pqOSM21fXyQ1vXRNndiQ7TCNX6FBI5JalMWDzi7CttGR+Mj+PgffmADwmKIMg==", + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@openwebwork/pg-codemirror-editor/-/pg-codemirror-editor-0.0.9.tgz", + "integrity": "sha512-6uy28r0ejOzJOC9vkgCu6tx9Zyi6ZpYWmqsk4sJlPamOicOiVNL5riu7pb4aIxmbdZWw4pXsGGilzYB38bnYVA==", "license": "MIT", "dependencies": { - "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-html": "^6.4.11", "@codemirror/lang-xml": "^6.1.0", - "@codemirror/theme-one-dark": "^6.1.2", - "@openwebwork/codemirror-lang-pg": "^0.0.3", + "@codemirror/theme-one-dark": "^6.1.3", + "@openwebwork/codemirror-lang-pg": "^0.0.4", "@replit/codemirror-emacs": "^6.1.0", "@replit/codemirror-vim": "^6.3.0", "cm6-theme-basic-dark": "^0.2.0", @@ -356,17 +354,328 @@ "cm6-theme-nord": "^0.2.0", "cm6-theme-solarized-dark": "^0.2.0", "cm6-theme-solarized-light": "^0.2.0", - "codemirror": "^6.0.1", - "codemirror-lang-mt": "^0.0.3", - "codemirror-lang-perl": "^0.1.6", - "style-mod": "^4.1.2", + "codemirror": "^6.0.2", + "codemirror-lang-mt": "^0.0.4", + "codemirror-lang-perl": "^0.1.7", + "style-mod": "^4.1.3", "thememirror": "^2.0.1" } }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "peer": true, "funding": { "type": "opencollective", @@ -400,10 +709,11 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -412,46 +722,35 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dev": true, "funding": [ { @@ -467,12 +766,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -485,25 +785,17 @@ "postcss": "^8.1.0" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/bootstrap": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", - "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", + "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", "funding": [ { "type": "github", @@ -514,6 +806,7 @@ "url": "https://opencollective.com/bootstrap" } ], + "license": "MIT", "peerDependencies": { "@popperjs/core": "^2.11.8" } @@ -523,6 +816,8 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -531,9 +826,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "funding": [ { @@ -549,11 +844,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -566,13 +862,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/caniuse-api": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.0.0", "caniuse-lite": "^1.0.0", @@ -581,9 +879,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001723", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz", - "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==", + "version": "1.0.30001759", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", + "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", "dev": true, "funding": [ { @@ -602,41 +900,34 @@ "license": "CC-BY-4.0" }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" } }, "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, + "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=12" + "node": ">=20" } }, "node_modules/cm6-theme-basic-dark": { @@ -751,61 +1042,45 @@ } }, "node_modules/codemirror-lang-mt": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/codemirror-lang-mt/-/codemirror-lang-mt-0.0.3.tgz", - "integrity": "sha512-OC2qG6GQI96BTgKzD4XVJd8fLOTyeB0pb7gy41BHjqot2gES6Bi/3esIgTygYUxw/SspMNSZnQZdWHPmD7/YYA==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/codemirror-lang-mt/-/codemirror-lang-mt-0.0.4.tgz", + "integrity": "sha512-8jKq4H0JG/mZQwz8TaV1KP1PBL14UKj9icpIB2ZwQ05e+MlvvJbt4Q6DoSXHghbP++4frzDkgRgIDZjMJ3I0+Q==", "license": "MIT", "dependencies": { "@codemirror/lang-css": "^6.3.1", - "@codemirror/lang-html": "^6.4.9", - "@codemirror/lang-javascript": "^6.2.3", - "@codemirror/language": "^6.11.0", - "@lezer/highlight": "^1.2.1", - "@lezer/lr": "^1.4.2" + "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/language": "^6.11.3", + "@lezer/highlight": "^1.2.3", + "@lezer/lr": "^1.4.4" } }, "node_modules/codemirror-lang-perl": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/codemirror-lang-perl/-/codemirror-lang-perl-0.1.6.tgz", - "integrity": "sha512-cYBmCQa7/itIRNx1AHfn9OQkInJQpL0sqCoikJXhQZwYNOHFSMd0L16pofEOU/1/f+s7CPA+XucUrNr/f1qigQ==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/codemirror-lang-perl/-/codemirror-lang-perl-0.1.7.tgz", + "integrity": "sha512-GxGVpHIUVzVnsJDd7zpkm5S+t+mgFI+XAY4jOmocaUMRuCsPzLLbYX9VJ6LkFY00bJDwrtKSS503lSsocX46xQ==", "license": "MIT", "dependencies": { - "@codemirror/language": "^6.11.0", - "@lezer/highlight": "^1.2.1", - "@lezer/lr": "^1.4.2" + "@codemirror/language": "^6.11.3", + "@lezer/highlight": "^1.2.3", + "@lezer/lr": "^1.4.4" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=16" } }, "node_modules/crelt": { @@ -819,6 +1094,7 @@ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", "dev": true, + "license": "ISC", "engines": { "node": "^14 || ^16 || >=18" }, @@ -827,10 +1103,11 @@ } }, "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -843,12 +1120,13 @@ } }, "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, + "license": "MIT", "dependencies": { - "mdn-data": "2.0.30", + "mdn-data": "2.12.2", "source-map-js": "^1.0.1" }, "engines": { @@ -856,10 +1134,11 @@ } }, "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -872,6 +1151,7 @@ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -880,79 +1160,82 @@ } }, "node_modules/cssnano": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", - "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.0.tgz", + "integrity": "sha512-Pu3rlKkd0ZtlCUzBrKL1Z4YmhKppjC1H9jo7u1o4qaKqyhvixFgu5qLyNIAOjSTg9DjVPtUqdROq2EfpVMEe+w==", "dev": true, + "license": "MIT", "dependencies": { - "cssnano-preset-default": "^6.1.2", - "lilconfig": "^3.1.1" + "cssnano-preset-default": "^7.0.8", + "lilconfig": "^3.1.3" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/cssnano-preset-default": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", - "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.8.tgz", + "integrity": "sha512-d+3R2qwrUV3g4LEMOjnndognKirBZISylDZAF/TPeCWVjEwlXS2e4eN4ICkoobRe7pD3H6lltinKVyS1AJhdjQ==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^4.0.2", - "postcss-calc": "^9.0.1", - "postcss-colormin": "^6.1.0", - "postcss-convert-values": "^6.1.0", - "postcss-discard-comments": "^6.0.2", - "postcss-discard-duplicates": "^6.0.3", - "postcss-discard-empty": "^6.0.3", - "postcss-discard-overridden": "^6.0.2", - "postcss-merge-longhand": "^6.0.5", - "postcss-merge-rules": "^6.1.1", - "postcss-minify-font-values": "^6.1.0", - "postcss-minify-gradients": "^6.0.3", - "postcss-minify-params": "^6.1.0", - "postcss-minify-selectors": "^6.0.4", - "postcss-normalize-charset": "^6.0.2", - "postcss-normalize-display-values": "^6.0.2", - "postcss-normalize-positions": "^6.0.2", - "postcss-normalize-repeat-style": "^6.0.2", - "postcss-normalize-string": "^6.0.2", - "postcss-normalize-timing-functions": "^6.0.2", - "postcss-normalize-unicode": "^6.1.0", - "postcss-normalize-url": "^6.0.2", - "postcss-normalize-whitespace": "^6.0.2", - "postcss-ordered-values": "^6.0.2", - "postcss-reduce-initial": "^6.1.0", - "postcss-reduce-transforms": "^6.0.2", - "postcss-svgo": "^6.0.3", - "postcss-unique-selectors": "^6.0.4" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" + "cssnano-utils": "^5.0.1", + "postcss-calc": "^10.1.1", + "postcss-colormin": "^7.0.4", + "postcss-convert-values": "^7.0.6", + "postcss-discard-comments": "^7.0.4", + "postcss-discard-duplicates": "^7.0.2", + "postcss-discard-empty": "^7.0.1", + "postcss-discard-overridden": "^7.0.1", + "postcss-merge-longhand": "^7.0.5", + "postcss-merge-rules": "^7.0.6", + "postcss-minify-font-values": "^7.0.1", + "postcss-minify-gradients": "^7.0.1", + "postcss-minify-params": "^7.0.4", + "postcss-minify-selectors": "^7.0.5", + "postcss-normalize-charset": "^7.0.1", + "postcss-normalize-display-values": "^7.0.1", + "postcss-normalize-positions": "^7.0.1", + "postcss-normalize-repeat-style": "^7.0.1", + "postcss-normalize-string": "^7.0.1", + "postcss-normalize-timing-functions": "^7.0.1", + "postcss-normalize-unicode": "^7.0.4", + "postcss-normalize-url": "^7.0.1", + "postcss-normalize-whitespace": "^7.0.1", + "postcss-ordered-values": "^7.0.2", + "postcss-reduce-initial": "^7.0.4", + "postcss-reduce-transforms": "^7.0.1", + "postcss-svgo": "^7.1.0", + "postcss-unique-selectors": "^7.0.4" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/cssnano-utils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", - "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", + "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", "dev": true, + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/csso": { @@ -960,6 +1243,7 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "license": "MIT", "dependencies": { "css-tree": "~2.2.0" }, @@ -973,6 +1257,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "license": "MIT", "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -986,13 +1271,29 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -1012,13 +1313,15 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -1030,10 +1333,11 @@ } }, "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -1044,22 +1348,25 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.747", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz", - "integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==", - "dev": true + "version": "1.5.183", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.183.tgz", + "integrity": "sha512-vCrDBYjQCAEefWGjlK3EpoSKfKbT10pR4XXPdn65q7snuNOZnthoVpBfZPykmDapOKfoD+MMIPG8ZjKyyc9oHA==", + "dev": true, + "license": "ISC" }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -1068,10 +1375,11 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1081,6 +1389,8 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1091,13 +1401,15 @@ "node_modules/flatpickr": { "version": "4.6.13", "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz", - "integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==" + "integrity": "sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==", + "license": "MIT" }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -1106,94 +1418,68 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/iframe-resizer": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/iframe-resizer/-/iframe-resizer-4.3.11.tgz", - "integrity": "sha512-5QtnsmfH11GDsuC7Gxd/eNzojudX3346Gb0E+Ku8ln8AtfSq+cWCZtnhCrthrtE7f1CI2/kwHkZ9G4sFYzHP7A==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/iframe-resizer/-/iframe-resizer-4.4.2.tgz", + "integrity": "sha512-2SupFCq9V9osWac4q+PodF0E9QdWY5A9VdCpKrrE7HlDrcIsaTp7D6k14mkGXWoWMS9jCavYusik25wTc0YB2Q==", + "hasInstallScript": true, + "license": "GPL-3.0", "engines": { "node": ">=0.8.0" }, "funding": { "type": "individual", - "url": "https://github.com/davidjbradshaw/iframe-resizer/blob/master/FUNDING.md" + "url": "https://iframe-resizer.com//pricing" } }, "node_modules/immutable": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", - "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1206,6 +1492,8 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", + "optional": true, "engines": { "node": ">=0.12.0" } @@ -1213,21 +1501,24 @@ "node_modules/jquery": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "license": "MIT" }, "node_modules/jquery-ui-dist": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.2.tgz", - "integrity": "sha512-oVDRd1NLtTbBwpRKAYdIRgpWVDzeBhfy7Gu0RmY6JEaZtmBq6kDn1pm5SgDiAotrnDS+RoTRXO6xvcNTxA9tOA==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.3.tgz", + "integrity": "sha512-qeTR3SOSQ0jgxaNXSFU6+JtxdzNUSJKgp8LCzVrVKntM25+2YBJW1Ea8B2AwjmmSHfPLy2dSlZxJQN06OfVFhg==", + "license": "MIT", "dependencies": { "jquery": ">=1.8.0 <4.0.0" } }, "node_modules/lilconfig": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", - "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" }, @@ -1239,32 +1530,55 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.uniq": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg==", + "license": "MIT", "engines": { "node": ">=12" } }, "node_modules/mathjax": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-3.2.2.tgz", - "integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-4.1.1.tgz", + "integrity": "sha512-NyvA8c39LUUM/m+oCg7sfA13hmw7yGkre5kiRWN9qzChCyhce39lecnbjgMA/oEUgq9Vyetk6u78apwcIXpW/A==", + "license": "Apache-2.0", + "dependencies": { + "@mathjax/mathjax-newcm-font": "^4.1.1" + } }, "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } }, "node_modules/minisearch": { "version": "7.1.2", @@ -1273,9 +1587,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -1291,26 +1605,27 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, "node_modules/normalize-range": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1320,6 +1635,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -1328,16 +1644,19 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, + "license": "MIT", + "optional": true, "engines": { "node": ">=8.6" }, @@ -1346,9 +1665,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -1364,396 +1683,427 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", + "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", "dev": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12 || ^20.9 || >=22.0" }, "peerDependencies": { - "postcss": "^8.2.2" + "postcss": "^8.4.38" } }, "node_modules/postcss-colormin": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", - "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.4.tgz", + "integrity": "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-convert-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", - "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.6.tgz", + "integrity": "sha512-MD/eb39Mr60hvgrqpXsgbiqluawYg/8K4nKsqRsuDX9f+xN1j6awZCUv/5tLH8ak3vYp/EMXwdcnXvfZYiejCQ==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-comments": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", - "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz", + "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==", "dev": true, + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.1.0" + }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-duplicates": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", - "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", + "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", "dev": true, + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-empty": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", - "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", + "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", "dev": true, + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-discard-overridden": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", - "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", + "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", "dev": true, + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-merge-longhand": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", - "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", + "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.1.1" + "stylehacks": "^7.0.5" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-merge-rules": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", - "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.6.tgz", + "integrity": "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.2", - "postcss-selector-parser": "^6.0.16" + "cssnano-utils": "^5.0.1", + "postcss-selector-parser": "^7.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-font-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", - "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", + "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-gradients": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", - "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", + "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", "dev": true, + "license": "MIT", "dependencies": { "colord": "^2.9.3", - "cssnano-utils": "^4.0.2", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-params": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", - "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.4.tgz", + "integrity": "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "cssnano-utils": "^4.0.2", + "browserslist": "^4.25.1", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-minify-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", - "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", + "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", "dev": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.16" + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-charset": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", - "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", + "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-display-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", - "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", + "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-positions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", - "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", + "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", - "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", + "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-string": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", - "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", + "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", - "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", + "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-unicode": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", - "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.4.tgz", + "integrity": "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", - "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", + "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-normalize-whitespace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", - "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", + "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-ordered-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", - "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", + "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", "dev": true, + "license": "MIT", "dependencies": { - "cssnano-utils": "^4.0.2", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-reduce-initial": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", - "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.4.tgz", + "integrity": "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-reduce-transforms": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", - "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", + "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -1763,47 +2113,51 @@ } }, "node_modules/postcss-svgo": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", - "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.0.tgz", + "integrity": "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==", "dev": true, + "license": "MIT", "dependencies": { "postcss-value-parser": "^4.2.0", - "svgo": "^3.2.0" + "svgo": "^4.0.0" }, "engines": { - "node": "^14 || ^16 || >= 18" + "node": "^18.12.0 || ^20.9.0 || >= 18" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-unique-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", - "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz", + "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==", "dev": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.16" + "postcss-selector-parser": "^7.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -1815,31 +2169,25 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/rtlcss": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", - "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", "dev": true, + "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0", @@ -1854,13 +2202,14 @@ } }, "node_modules/sass": { - "version": "1.75.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.75.0.tgz", - "integrity": "sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==", + "version": "1.90.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", + "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "dev": true, + "license": "MIT", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -1868,6 +2217,9 @@ }, "engines": { "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, "node_modules/sax": { @@ -1875,6 +2227,7 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" } @@ -1882,27 +2235,31 @@ "node_modules/shortcut-buttons-flatpickr": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/shortcut-buttons-flatpickr/-/shortcut-buttons-flatpickr-0.4.0.tgz", - "integrity": "sha512-JKmT4my3Hm1e18OvG4Q6RcFhN4WRqqpTMkHrvZ7fup/dp6aTIWGVCHdRYtASkp/FCzDlJh6iCLQ/VcwwNpAMoQ==" + "integrity": "sha512-JKmT4my3Hm1e18OvG4Q6RcFhN4WRqqpTMkHrvZ7fup/dp6aTIWGVCHdRYtASkp/FCzDlJh6iCLQ/VcwwNpAMoQ==", + "license": "MIT" }, "node_modules/sortablejs": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", - "integrity": "sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.6.tgz", + "integrity": "sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==", + "license": "MIT" }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -1912,35 +2269,44 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-json-comments": { @@ -1948,6 +2314,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -1956,46 +2323,48 @@ } }, "node_modules/style-mod": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", - "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", "license": "MIT" }, "node_modules/stylehacks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", - "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.6.tgz", + "integrity": "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg==", "dev": true, + "license": "MIT", "dependencies": { - "browserslist": "^4.23.0", - "postcss-selector-parser": "^6.0.16" + "browserslist": "^4.25.1", + "postcss-selector-parser": "^7.1.0" }, "engines": { - "node": "^14 || ^16 || >=18.0" + "node": "^18.12.0 || ^20.9.0 || >=22.0" }, "peerDependencies": { - "postcss": "^8.4.31" + "postcss": "^8.4.32" } }, "node_modules/svgo": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", - "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", "dev": true, + "license": "MIT", "dependencies": { - "commander": "^7.2.0", + "commander": "^11.1.0", "css-select": "^5.1.0", - "css-tree": "^2.3.1", + "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "sax": "^1.5.0" }, "bin": { - "svgo": "bin/svgo" + "svgo": "bin/svgo.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=16" }, "funding": { "type": "opencollective", @@ -2003,13 +2372,14 @@ } }, "node_modules/terser": { - "version": "5.30.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", - "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -2024,7 +2394,8 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thememirror": { "version": "2.0.1", @@ -2042,6 +2413,8 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -2050,9 +2423,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -2068,9 +2441,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -2083,7 +2457,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/w3c-keyname": { "version": "2.2.8", @@ -2092,17 +2467,18 @@ "license": "MIT" }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -2113,43 +2489,45 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, + "license": "ISC", "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } } }, "dependencies": { "@codemirror/autocomplete": { - "version": "6.18.6", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz", - "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", + "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", "requires": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -2158,9 +2536,9 @@ } }, "@codemirror/commands": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz", - "integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz", + "integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==", "requires": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", @@ -2181,9 +2559,9 @@ } }, "@codemirror/lang-html": { - "version": "6.4.9", - "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz", - "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==", + "version": "6.4.11", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", + "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", "requires": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", @@ -2193,7 +2571,7 @@ "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/css": "^1.1.0", - "@lezer/html": "^1.3.0" + "@lezer/html": "^1.3.12" } }, "@codemirror/lang-javascript": { @@ -2224,9 +2602,9 @@ } }, "@codemirror/language": { - "version": "6.11.1", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz", - "integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==", + "version": "6.11.3", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz", + "integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==", "requires": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -2237,9 +2615,9 @@ } }, "@codemirror/lint": { - "version": "6.8.5", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz", - "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==", + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz", + "integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==", "requires": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", @@ -2276,9 +2654,9 @@ } }, "@codemirror/view": { - "version": "6.37.2", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz", - "integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==", + "version": "6.38.8", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.38.8.tgz", + "integrity": "sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==", "requires": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -2287,18 +2665,17 @@ } }, "@fortawesome/fontawesome-free": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.5.2.tgz", - "integrity": "sha512-hRILoInAx8GNT5IMkrtIt9blOdrqHOnPBH+k70aWUAqPZPgopb9G5EQJFpaBx/S8zp2fC+mPW349Bziuk1o28Q==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.0.tgz", + "integrity": "sha512-X48nISrSOa89zu2VMljC4XaRf8NmgTwQBVHfS2Nu5G00ZwM31oOVrAtGxZF3b6wDYf9lJsf/Eq4cCSFKIkOWPQ==" }, "@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, @@ -2308,16 +2685,10 @@ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true }, - "@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true - }, "@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.5", @@ -2325,15 +2696,15 @@ } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2341,14 +2712,14 @@ } }, "@lezer/common": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", - "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.4.0.tgz", + "integrity": "sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==" }, "@lezer/css": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.2.1.tgz", - "integrity": "sha512-2F5tOqzKEKbCUNraIXc0f6HKeyKlmMWJnBB0i4XW6dJgssrZO/YlZ2pY5xgyqDleqqhiNJ3dQhbrV2aClZQMvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.3.0.tgz", + "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==", "requires": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", @@ -2356,17 +2727,17 @@ } }, "@lezer/highlight": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", - "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", + "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", "requires": { - "@lezer/common": "^1.0.0" + "@lezer/common": "^1.3.0" } }, "@lezer/html": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz", - "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.12.tgz", + "integrity": "sha512-RJ7eRWdaJe3bsiiLLHjCFT1JMk8m1YP9kaUbvu2rMLEoOnke9mcTVDyfOslsln0LtujdWespjJ39w6zo+RsQYw==", "requires": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", @@ -2374,9 +2745,9 @@ } }, "@lezer/javascript": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz", - "integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", + "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", "requires": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.1.3", @@ -2384,9 +2755,9 @@ } }, "@lezer/lr": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", - "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.4.tgz", + "integrity": "sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==", "requires": { "@lezer/common": "^1.0.0" } @@ -2406,25 +2777,30 @@ "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==" }, + "@mathjax/mathjax-newcm-font": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@mathjax/mathjax-newcm-font/-/mathjax-newcm-font-4.1.1.tgz", + "integrity": "sha512-LeV5AWzoR7k/k2tg5mW0Ad3Jr9oK9guW/zBUIP8aoiIZcZIhvAV9dlbtUSqSe1wgEBUP1KOcJXcrE/NxOqkxlQ==" + }, "@openwebwork/codemirror-lang-pg": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@openwebwork/codemirror-lang-pg/-/codemirror-lang-pg-0.0.3.tgz", - "integrity": "sha512-ZKtb2r0Ck6tVz44wwMKY7w/82P470whIzM5C8pi2GiBlnFWmkQcadmOaCBz31FELY1SrKE3AO2TmMrwUt2EKPA==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@openwebwork/codemirror-lang-pg/-/codemirror-lang-pg-0.0.4.tgz", + "integrity": "sha512-lNA9PVTRDNWfmL87ux3zbFQfih+6tXKJdz+yA1CPbHWaNuNY+OK9dur+Ul5H6Hi6flGWlcE674/eMmkelLRAng==", "requires": { - "@codemirror/language": "^6.11.0", - "@lezer/highlight": "^1.2.1", - "@lezer/lr": "^1.4.2" + "@codemirror/language": "^6.11.3", + "@lezer/highlight": "^1.2.3", + "@lezer/lr": "^1.4.4" } }, "@openwebwork/pg-codemirror-editor": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@openwebwork/pg-codemirror-editor/-/pg-codemirror-editor-0.0.5.tgz", - "integrity": "sha512-ue4aciJzF7PPdQwWvYQkSf7h3pqOSM21fXyQ1vXRNndiQ7TCNX6FBI5JalMWDzi7CttGR+Mj+PgffmADwmKIMg==", + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@openwebwork/pg-codemirror-editor/-/pg-codemirror-editor-0.0.9.tgz", + "integrity": "sha512-6uy28r0ejOzJOC9vkgCu6tx9Zyi6ZpYWmqsk4sJlPamOicOiVNL5riu7pb4aIxmbdZWw4pXsGGilzYB38bnYVA==", "requires": { - "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-html": "^6.4.11", "@codemirror/lang-xml": "^6.1.0", - "@codemirror/theme-one-dark": "^6.1.2", - "@openwebwork/codemirror-lang-pg": "^0.0.3", + "@codemirror/theme-one-dark": "^6.1.3", + "@openwebwork/codemirror-lang-pg": "^0.0.4", "@replit/codemirror-emacs": "^6.1.0", "@replit/codemirror-vim": "^6.3.0", "cm6-theme-basic-dark": "^0.2.0", @@ -2435,13 +2811,130 @@ "cm6-theme-nord": "^0.2.0", "cm6-theme-solarized-dark": "^0.2.0", "cm6-theme-solarized-light": "^0.2.0", - "codemirror": "^6.0.1", - "codemirror-lang-mt": "^0.0.3", - "codemirror-lang-perl": "^0.1.6", - "style-mod": "^4.1.2", + "codemirror": "^6.0.2", + "codemirror-lang-mt": "^0.0.4", + "codemirror-lang-perl": "^0.1.7", + "style-mod": "^4.1.3", "thememirror": "^2.0.1" } }, + "@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "optional": true, + "requires": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1", + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + } + }, + "@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "dev": true, + "optional": true + }, + "@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "dev": true, + "optional": true + }, + "@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "dev": true, + "optional": true + }, "@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -2461,56 +2954,37 @@ "requires": {} }, "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true }, "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true }, "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true }, "autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", "dev": true, "requires": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" } }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", @@ -2518,9 +2992,9 @@ "dev": true }, "bootstrap": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", - "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", + "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", "requires": {} }, "braces": { @@ -2528,20 +3002,21 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "optional": true, "requires": { "fill-range": "^7.1.1" } }, "browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" } }, "buffer-from": { @@ -2563,36 +3038,29 @@ } }, "caniuse-lite": { - "version": "1.0.30001723", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001723.tgz", - "integrity": "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==", + "version": "1.0.30001759", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", + "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", "dev": true }, "chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" } }, "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" } }, "cm6-theme-basic-dark": { @@ -2658,43 +3126,28 @@ } }, "codemirror-lang-mt": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/codemirror-lang-mt/-/codemirror-lang-mt-0.0.3.tgz", - "integrity": "sha512-OC2qG6GQI96BTgKzD4XVJd8fLOTyeB0pb7gy41BHjqot2gES6Bi/3esIgTygYUxw/SspMNSZnQZdWHPmD7/YYA==", + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/codemirror-lang-mt/-/codemirror-lang-mt-0.0.4.tgz", + "integrity": "sha512-8jKq4H0JG/mZQwz8TaV1KP1PBL14UKj9icpIB2ZwQ05e+MlvvJbt4Q6DoSXHghbP++4frzDkgRgIDZjMJ3I0+Q==", "requires": { "@codemirror/lang-css": "^6.3.1", - "@codemirror/lang-html": "^6.4.9", - "@codemirror/lang-javascript": "^6.2.3", - "@codemirror/language": "^6.11.0", - "@lezer/highlight": "^1.2.1", - "@lezer/lr": "^1.4.2" + "@codemirror/lang-html": "^6.4.11", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/language": "^6.11.3", + "@lezer/highlight": "^1.2.3", + "@lezer/lr": "^1.4.4" } }, "codemirror-lang-perl": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/codemirror-lang-perl/-/codemirror-lang-perl-0.1.6.tgz", - "integrity": "sha512-cYBmCQa7/itIRNx1AHfn9OQkInJQpL0sqCoikJXhQZwYNOHFSMd0L16pofEOU/1/f+s7CPA+XucUrNr/f1qigQ==", - "requires": { - "@codemirror/language": "^6.11.0", - "@lezer/highlight": "^1.2.1", - "@lezer/lr": "^1.4.2" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/codemirror-lang-perl/-/codemirror-lang-perl-0.1.7.tgz", + "integrity": "sha512-GxGVpHIUVzVnsJDd7zpkm5S+t+mgFI+XAY4jOmocaUMRuCsPzLLbYX9VJ6LkFY00bJDwrtKSS503lSsocX46xQ==", "requires": { - "color-name": "~1.1.4" + "@codemirror/language": "^6.11.3", + "@lezer/highlight": "^1.2.3", + "@lezer/lr": "^1.4.4" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -2702,9 +3155,9 @@ "dev": true }, "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true }, "crelt": { @@ -2720,9 +3173,9 @@ "requires": {} }, "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", "dev": true, "requires": { "boolbase": "^1.0.0", @@ -2733,19 +3186,19 @@ } }, "css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, "requires": { - "mdn-data": "2.0.30", + "mdn-data": "2.12.2", "source-map-js": "^1.0.1" } }, "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", "dev": true }, "cssesc": { @@ -2755,57 +3208,57 @@ "dev": true }, "cssnano": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", - "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.0.tgz", + "integrity": "sha512-Pu3rlKkd0ZtlCUzBrKL1Z4YmhKppjC1H9jo7u1o4qaKqyhvixFgu5qLyNIAOjSTg9DjVPtUqdROq2EfpVMEe+w==", "dev": true, "requires": { - "cssnano-preset-default": "^6.1.2", - "lilconfig": "^3.1.1" + "cssnano-preset-default": "^7.0.8", + "lilconfig": "^3.1.3" } }, "cssnano-preset-default": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", - "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.8.tgz", + "integrity": "sha512-d+3R2qwrUV3g4LEMOjnndognKirBZISylDZAF/TPeCWVjEwlXS2e4eN4ICkoobRe7pD3H6lltinKVyS1AJhdjQ==", "dev": true, "requires": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "css-declaration-sorter": "^7.2.0", - "cssnano-utils": "^4.0.2", - "postcss-calc": "^9.0.1", - "postcss-colormin": "^6.1.0", - "postcss-convert-values": "^6.1.0", - "postcss-discard-comments": "^6.0.2", - "postcss-discard-duplicates": "^6.0.3", - "postcss-discard-empty": "^6.0.3", - "postcss-discard-overridden": "^6.0.2", - "postcss-merge-longhand": "^6.0.5", - "postcss-merge-rules": "^6.1.1", - "postcss-minify-font-values": "^6.1.0", - "postcss-minify-gradients": "^6.0.3", - "postcss-minify-params": "^6.1.0", - "postcss-minify-selectors": "^6.0.4", - "postcss-normalize-charset": "^6.0.2", - "postcss-normalize-display-values": "^6.0.2", - "postcss-normalize-positions": "^6.0.2", - "postcss-normalize-repeat-style": "^6.0.2", - "postcss-normalize-string": "^6.0.2", - "postcss-normalize-timing-functions": "^6.0.2", - "postcss-normalize-unicode": "^6.1.0", - "postcss-normalize-url": "^6.0.2", - "postcss-normalize-whitespace": "^6.0.2", - "postcss-ordered-values": "^6.0.2", - "postcss-reduce-initial": "^6.1.0", - "postcss-reduce-transforms": "^6.0.2", - "postcss-svgo": "^6.0.3", - "postcss-unique-selectors": "^6.0.4" + "cssnano-utils": "^5.0.1", + "postcss-calc": "^10.1.1", + "postcss-colormin": "^7.0.4", + "postcss-convert-values": "^7.0.6", + "postcss-discard-comments": "^7.0.4", + "postcss-discard-duplicates": "^7.0.2", + "postcss-discard-empty": "^7.0.1", + "postcss-discard-overridden": "^7.0.1", + "postcss-merge-longhand": "^7.0.5", + "postcss-merge-rules": "^7.0.6", + "postcss-minify-font-values": "^7.0.1", + "postcss-minify-gradients": "^7.0.1", + "postcss-minify-params": "^7.0.4", + "postcss-minify-selectors": "^7.0.5", + "postcss-normalize-charset": "^7.0.1", + "postcss-normalize-display-values": "^7.0.1", + "postcss-normalize-positions": "^7.0.1", + "postcss-normalize-repeat-style": "^7.0.1", + "postcss-normalize-string": "^7.0.1", + "postcss-normalize-timing-functions": "^7.0.1", + "postcss-normalize-unicode": "^7.0.4", + "postcss-normalize-url": "^7.0.1", + "postcss-normalize-whitespace": "^7.0.1", + "postcss-ordered-values": "^7.0.2", + "postcss-reduce-initial": "^7.0.4", + "postcss-reduce-transforms": "^7.0.1", + "postcss-svgo": "^7.1.0", + "postcss-unique-selectors": "^7.0.4" } }, "cssnano-utils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", - "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", + "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", "dev": true, "requires": {} }, @@ -2836,6 +3289,13 @@ } } }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "optional": true + }, "dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -2863,9 +3323,9 @@ } }, "domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, "requires": { "dom-serializer": "^2.0.0", @@ -2874,15 +3334,15 @@ } }, "electron-to-chromium": { - "version": "1.4.747", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.747.tgz", - "integrity": "sha512-+FnSWZIAvFHbsNVmUxhEqWiaOiPMcfum1GQzlWCg/wLigVtshOsjXHyEFfmt6cFK6+HkS3QOJBv6/3OPumbBfw==", + "version": "1.5.183", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.183.tgz", + "integrity": "sha512-vCrDBYjQCAEefWGjlK3EpoSKfKbT10pR4XXPdn65q7snuNOZnthoVpBfZPykmDapOKfoD+MMIPG8ZjKyyc9oHA==", "dev": true }, "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "entities": { @@ -2892,9 +3352,9 @@ "dev": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true }, "fill-range": { @@ -2902,6 +3362,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "optional": true, "requires": { "to-regex-range": "^5.0.1" } @@ -2917,65 +3378,42 @@ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } + "get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true }, "iframe-resizer": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/iframe-resizer/-/iframe-resizer-4.3.11.tgz", - "integrity": "sha512-5QtnsmfH11GDsuC7Gxd/eNzojudX3346Gb0E+Ku8ln8AtfSq+cWCZtnhCrthrtE7f1CI2/kwHkZ9G4sFYzHP7A==" + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/iframe-resizer/-/iframe-resizer-4.4.2.tgz", + "integrity": "sha512-2SupFCq9V9osWac4q+PodF0E9QdWY5A9VdCpKrrE7HlDrcIsaTp7D6k14mkGXWoWMS9jCavYusik25wTc0YB2Q==" }, "immutable": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", - "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "dev": true, + "optional": true }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "optional": true, "requires": { "is-extglob": "^2.1.1" } @@ -2984,7 +3422,8 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "dev": true, + "optional": true }, "jquery": { "version": "3.7.1", @@ -2992,17 +3431,17 @@ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" }, "jquery-ui-dist": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.2.tgz", - "integrity": "sha512-oVDRd1NLtTbBwpRKAYdIRgpWVDzeBhfy7Gu0RmY6JEaZtmBq6kDn1pm5SgDiAotrnDS+RoTRXO6xvcNTxA9tOA==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.3.tgz", + "integrity": "sha512-qeTR3SOSQ0jgxaNXSFU6+JtxdzNUSJKgp8LCzVrVKntM25+2YBJW1Ea8B2AwjmmSHfPLy2dSlZxJQN06OfVFhg==", "requires": { "jquery": ">=1.8.0 <4.0.0" } }, "lilconfig": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", - "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true }, "lodash.memoize": { @@ -3018,42 +3457,57 @@ "dev": true }, "luxon": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz", - "integrity": "sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==" + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.1.tgz", + "integrity": "sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg==" }, "mathjax": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-3.2.2.tgz", - "integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-4.1.1.tgz", + "integrity": "sha512-NyvA8c39LUUM/m+oCg7sfA13hmw7yGkre5kiRWN9qzChCyhce39lecnbjgMA/oEUgq9Vyetk6u78apwcIXpW/A==", + "requires": { + "@mathjax/mathjax-newcm-font": "^4.1.1" + } }, "mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "dev": true }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "optional": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, "minisearch": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.2.tgz", "integrity": "sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==" }, "nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true }, - "node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true }, "normalize-range": { @@ -3072,263 +3526,267 @@ } }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, "picomatch": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true + "dev": true, + "optional": true }, "postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "requires": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" } }, "postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", + "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.2.0" } }, "postcss-colormin": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", - "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.4.tgz", + "integrity": "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw==", "dev": true, "requires": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", "colord": "^2.9.3", "postcss-value-parser": "^4.2.0" } }, "postcss-convert-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", - "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.6.tgz", + "integrity": "sha512-MD/eb39Mr60hvgrqpXsgbiqluawYg/8K4nKsqRsuDX9f+xN1j6awZCUv/5tLH8ak3vYp/EMXwdcnXvfZYiejCQ==", "dev": true, "requires": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" } }, "postcss-discard-comments": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", - "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz", + "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==", "dev": true, - "requires": {} + "requires": { + "postcss-selector-parser": "^7.1.0" + } }, "postcss-discard-duplicates": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", - "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", + "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", "dev": true, "requires": {} }, "postcss-discard-empty": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", - "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", + "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", "dev": true, "requires": {} }, "postcss-discard-overridden": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", - "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", + "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", "dev": true, "requires": {} }, "postcss-merge-longhand": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", - "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", + "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.1.1" + "stylehacks": "^7.0.5" } }, "postcss-merge-rules": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", - "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.6.tgz", + "integrity": "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ==", "dev": true, "requires": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.2", - "postcss-selector-parser": "^6.0.16" + "cssnano-utils": "^5.0.1", + "postcss-selector-parser": "^7.1.0" } }, "postcss-minify-font-values": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", - "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", + "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-minify-gradients": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", - "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", + "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", "dev": true, "requires": { "colord": "^2.9.3", - "cssnano-utils": "^4.0.2", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" } }, "postcss-minify-params": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", - "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.4.tgz", + "integrity": "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw==", "dev": true, "requires": { - "browserslist": "^4.23.0", - "cssnano-utils": "^4.0.2", + "browserslist": "^4.25.1", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" } }, "postcss-minify-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", - "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", + "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.16" + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.0" } }, "postcss-normalize-charset": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", - "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", + "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", "dev": true, "requires": {} }, "postcss-normalize-display-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", - "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", + "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-positions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", - "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", + "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-repeat-style": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", - "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", + "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-string": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", - "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", + "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-timing-functions": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", - "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", + "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-unicode": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", - "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.4.tgz", + "integrity": "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g==", "dev": true, "requires": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-url": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", - "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", + "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-normalize-whitespace": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", - "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", + "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-ordered-values": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", - "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", + "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", "dev": true, "requires": { - "cssnano-utils": "^4.0.2", + "cssnano-utils": "^5.0.1", "postcss-value-parser": "^4.2.0" } }, "postcss-reduce-initial": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", - "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.4.tgz", + "integrity": "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q==", "dev": true, "requires": { - "browserslist": "^4.23.0", + "browserslist": "^4.25.1", "caniuse-api": "^3.0.0" } }, "postcss-reduce-transforms": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", - "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", + "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0" } }, "postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", "dev": true, "requires": { "cssesc": "^3.0.0", @@ -3336,22 +3794,22 @@ } }, "postcss-svgo": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", - "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.0.tgz", + "integrity": "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==", "dev": true, "requires": { "postcss-value-parser": "^4.2.0", - "svgo": "^3.2.0" + "svgo": "^4.0.0" } }, "postcss-unique-selectors": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", - "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz", + "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.16" + "postcss-selector-parser": "^7.1.0" } }, "postcss-value-parser": { @@ -3361,30 +3819,21 @@ "dev": true }, "prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true }, "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true }, "rtlcss": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.1.1.tgz", - "integrity": "sha512-/oVHgBtnPNcggP2aVXQjSy6N1mMAfHg4GSag0QtZBlD5bdDgAHwr4pydqJGd+SUCu9260+Pjqbjwtvu7EMH1KQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", "dev": true, "requires": { "escalade": "^3.1.1", @@ -3394,13 +3843,14 @@ } }, "sass": { - "version": "1.75.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.75.0.tgz", - "integrity": "sha512-ShMYi3WkrDWxExyxSZPst4/okE9ts46xZmJDSawJQrnte7M1V9fScVB+uNXOVKRBt0PggHOwoZcn8mYX4trnBw==", + "version": "1.90.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", + "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "dev": true, "requires": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", + "@parcel/watcher": "^2.4.1", + "chokidar": "^4.0.0", + "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" } }, @@ -3416,9 +3866,9 @@ "integrity": "sha512-JKmT4my3Hm1e18OvG4Q6RcFhN4WRqqpTMkHrvZ7fup/dp6aTIWGVCHdRYtASkp/FCzDlJh6iCLQ/VcwwNpAMoQ==" }, "sortablejs": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.2.tgz", - "integrity": "sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.6.tgz", + "integrity": "sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==" }, "source-map": { "version": "0.6.1", @@ -3427,9 +3877,9 @@ "dev": true }, "source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true }, "source-map-support": { @@ -3443,23 +3893,23 @@ } }, "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" } }, "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "requires": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.0.1" } }, "strip-json-comments": { @@ -3469,43 +3919,43 @@ "dev": true }, "style-mod": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", - "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz", + "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==" }, "stylehacks": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", - "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.6.tgz", + "integrity": "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg==", "dev": true, "requires": { - "browserslist": "^4.23.0", - "postcss-selector-parser": "^6.0.16" + "browserslist": "^4.25.1", + "postcss-selector-parser": "^7.1.0" } }, "svgo": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", - "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", "dev": true, "requires": { - "commander": "^7.2.0", + "commander": "^11.1.0", "css-select": "^5.1.0", - "css-tree": "^2.3.1", + "css-tree": "^3.0.1", "css-what": "^6.1.0", "csso": "^5.0.5", - "picocolors": "^1.0.0", + "picocolors": "^1.1.1", "sax": "^1.5.0" } }, "terser": { - "version": "5.30.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.4.tgz", - "integrity": "sha512-xRdd0v64a8mFK9bnsKVdoNP9GQIKUAaJPTaqEQDL4w/J8WaW4sWXXoMZ+6SimPkfT5bElreXf8m9HnmPc3E1BQ==", + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.14.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -3529,18 +3979,19 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "optional": true, "requires": { "is-number": "^7.0.0" } }, "update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" } }, "util-deprecate": { @@ -3555,14 +4006,14 @@ "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==" }, "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" } }, "y18n": { @@ -3572,24 +4023,23 @@ "dev": true }, "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, "requires": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" } }, "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true } } diff --git a/htdocs/package.json b/htdocs/package.json index f31c5dc54c..671d84b613 100644 --- a/htdocs/package.json +++ b/htdocs/package.json @@ -13,29 +13,29 @@ "url": "https://github.com/openwebwork/webwork2" }, "dependencies": { - "@fortawesome/fontawesome-free": "^6.5.2", - "@openwebwork/pg-codemirror-editor": "^0.0.5", - "bootstrap": "~5.3.3", + "@fortawesome/fontawesome-free": "^7.0.0", + "@openwebwork/pg-codemirror-editor": "^0.0.9", + "bootstrap": "~5.3.7", "flatpickr": "^4.6.13", - "iframe-resizer": "^4.3.11", + "iframe-resizer": "^4.4.2", "jquery": "^3.7.1", - "jquery-ui-dist": "^1.13.2", - "luxon": "^3.4.4", - "mathjax": "^3.2.2", + "jquery-ui-dist": "^1.13.3", + "luxon": "^3.7.1", + "mathjax": "^4.1.1", "minisearch": "^7.1.2", "shortcut-buttons-flatpickr": "^0.4.0", - "sortablejs": "^1.15.2" + "sortablejs": "^1.15.6" }, "devDependencies": { - "autoprefixer": "^10.4.19", - "chokidar": "^3.6.0", - "cssnano": "^6.1.2", - "postcss": "^8.4.38", - "prettier": "^3.2.5", - "rtlcss": "^4.1.1", - "sass": "^1.75.0", - "terser": "^5.30.4", - "yargs": "^17.7.2" + "autoprefixer": "^10.4.21", + "chokidar": "^4.0.3", + "cssnano": "^7.1.0", + "postcss": "^8.5.6", + "prettier": "^3.6.2", + "rtlcss": "^4.3.0", + "sass": "^1.90.0", + "terser": "^5.43.1", + "yargs": "^18.0.0" }, "browserslist": [ "last 10 Chrome versions", diff --git a/htdocs/show-source.cgi b/htdocs/show-source.cgi index 8cf298e894..af3181a2ad 100755 --- a/htdocs/show-source.cgi +++ b/htdocs/show-source.cgi @@ -14,10 +14,12 @@ my $filedir = $file =~ s!/[^/]+$!!r; $file =~ s!.*/!!; my @PGdirs = ( - "../templates$filedir", '../templates/macros', "$root/pg/macros", "$root/pg/macros/answers", - "$root/pg/macros/capa", "$root/pg/macros/contexts", "$root/pg/macros/core", "$root/pg/macros/deprecated", - "$root/pg/macros/graph", "$root/pg/macros/math", "$root/pg/macros/misc", "$root/pg/macros/parsers", - "$root/pg/macros/ui", + "../templates$filedir", '../templates/macros', + "$root/pg/macros", "$root/pg/macros/answers", + "$root/pg/macros/contexts", "$root/pg/macros/core", + "$root/pg/macros/deprecated", "$root/pg/macros/graph", + "$root/pg/macros/math", "$root/pg/macros/misc", + "$root/pg/macros/parsers", "$root/pg/macros/ui", ); for my $dir (@PGdirs) { ShowSource("$dir/$file") if (-e "$dir/$file") } diff --git a/htdocs/themes/README.md b/htdocs/themes/README.md new file mode 100644 index 0000000000..048ca09644 --- /dev/null +++ b/htdocs/themes/README.md @@ -0,0 +1,78 @@ +# Theming WeBWorK 2 + +This folder contains the themes for webwork2. If you would like to create a custom theme, then copy one of the existing +theme directories, and modify it as desired. It is recommended that you use either the `math4-green`, `math4-red`, or +`math4-yellow` theme as the basis for a new custom theme, but for more advanced theming you can copy the `math4` +directory itself. Generally only the `_theme-colors.scss` and `_theme-overrides.scss` files need to be modified. The +important things to change are the colors in the `_theme-colors.scss` file. Overrides for special cases can be done in +the `_theme-overrides.scss` file. The `math4-yellow` theme uses a light primary color, and so it is a good example to +follow if you also need a light primary color. It also shows how the `_theme-overrides.scss` file can be used to handle +certain special cases. + +The `math4-overrides.css` and `math4-overrides.js` files can also be created in the theme directory and customizations +can also be added to those files. However, usage of these files is deprecated and support for them will eventually be +dropped. There are `.dist` files in the `math4` directory you can copy, but the `.dist` files do not have anything of +value in them. + +Note that any changes made to the files in the `math4`, `math4-green`, `math4-red`, and `math4-yellow` files will cause +problems when you upgrade webwork2, (other than copies of the `math4-overrides.css.dist` and `math4-overrides.css.js` +files). + +To make the custom theme available for webwork2 to use, run `npm ci` from the `htdocs` directory. Then either set the +theme as the `$defaultTheme` in `conf/localOverrides.conf` or choose the theme in the `Course Configuration` of a course +to use it. Note that for any changes in the theme files to take effect, you must run `npm ci` again. You can also +execute `./generate-assets.js` from the `htdocs` directory to update the theme (this is actually part of what `npm ci` +does). See more details on theme creation on [the WeBWork Wiki](https://wiki.openwebwork.org/wiki/Customizing_WeBWorK). + +The theming system uses Sass which is an extension of CSS, and is compiled into CSS (by the `generate-assets.js` +script). Sass variables can be set in the `_theme-colors.scss` file that control many display aspects of the user +interface. Bootstrap has many Sass variables that can be customized. In addition there are CSS variables that can be +set. Many of these are set initially from the Sass variables, but they can also be changed in the +`_theme-overrides.scss` file. See the [Bootstrap documentation](https://getbootstrap.com/docs/5.3) for available Sass +and CSS variables. There are also Sass and CSS variables specifically for webwork2 that can be used. These are +documented below. In addition Bootstrap functions can be used to manipulate colors in the `_theme-colors.scss` file. +See the [Boottrap Sass function documentation](https://getbootstrap.com/docs/5.3/customize/sass/#functions). + +## WeBWorK 2 Sass Variables + +These must be set in the `_theme-colors.scss` file. + +- `$ww-logo-background-color`: WeBWorK logo background color in the banner. +- `$ww-achievement-level-color`: Color of the level progress bar on the achievements page. + +## WeBWorK 2 CSS Variables + +All of these are set to a default value in the `bootstrap.scss` file, but can be overridden in the +`_theme-overrides.scss` file. Note that values can even be set for a specific CSS selector to only apply to the elements +that match the selector and descendants of those elements. + +- `--ww-primary-foreground-color`: The color of text that is displayed before a primary colored background in the page + header, site navigation menu, and the course list on the webwork2 home page. This defaults to the result of + `#{color-contrast($primary)}` and rarely needs to be changed. +- `--ww-layout-divider-color`: This is the color of the border that separates the page header, site navigation menu, and + main content area. It is also used for the color of the border separates the primary part of the site navigation menu + from page specific sub menus (such as the list of problems when viewing a problem in a homework set). This defaults to + `#aaa` in light mode and `#666` in dark mode. +- `--ww-layout-border-color`: This is the border color for other regions such as the breadcrumb navigation at the top of + every page and the info box shown (the course information or set header box). This defaults to `#e6e6e6` in light mode + and `#495057` in dark mode. +- `--ww-toggle-sidebar-icon-color-rgb`: The color of the site navigation menu toggle button in RGB color components. + This defaults to `255, 255, 255`. +- `--ww-toggle-sidebar-icon-hover-color`: The color of the site navigation menu toggle button when it is hovered over + with the mouse cursor or has keyboard focus. This defaults to `#fff`. +- `--ww-site-nav-link-active-background-color`: The background color of the links in the site navigation menu when they + have keyboard focus. This defaults to `#{$primary}`. +- `--ww-site-nav-link-hover-background-color`: The background color of the links in the site navigation menu when the + mouse cursor hovers over them. This defaults to `#e1e1e1` in light mode and `#{shade-color($primary, 40%)}` in dark + mode. +- `--ww-course-config-tab-link-focus-outline-color`: The outline color of the tab selection buttons on the course + configuration page when they have keyboard focus. This defaults to `#{rgba($primary, $focus-ring-opacity)}` in light + mode and `#{rgba(color-contrast($body-bg-dark), $focus-ring-opacity)}` in dark mode. +- `--ww-logo-background-color`: The background color for the top left region of the page header that contains the + WeBWorK logo. This is set to the value of the `#{$ww-logo-background-color}` Sass variable, and there is no need to + ever modify this. Just set the Sass variable directly to what this should be. This is really only needed to get the + theme color to the other CSS files used by webwork2. +- `--ww-achievement-level-color`: The color of the level progress bar on the achievements page. This defaults to the + value of the `#{$ww-achievement-level-color}` Sass variable, and there is no need to ever modify this. Just set the + Sass variable directly to what this should be. This is really only needed to get the theme color to the other CSS + files used by webwork2. diff --git a/htdocs/themes/math4-green/README b/htdocs/themes/math4-green/README deleted file mode 100644 index e607958755..0000000000 --- a/htdocs/themes/math4-green/README +++ /dev/null @@ -1,8 +0,0 @@ -This is an "alternative" colorization to math4. If you want to provide -multiple themes to your users you should follow this as an example. - -Everything except for the math4-overrides.js, math4-overrides.css, -_theme-colors.scss, and _theme-overrides.scss files should be links pointing -back to the corresponding files in math4. This will make it so that all your -themes will automatically get updates. All of your changes should be in the -listed override files. diff --git a/htdocs/themes/math4-green/_theme-colors.scss b/htdocs/themes/math4-green/_theme-colors.scss index 89fa61322f..4a0d5d4e6e 100644 --- a/htdocs/themes/math4-green/_theme-colors.scss +++ b/htdocs/themes/math4-green/_theme-colors.scss @@ -7,7 +7,6 @@ $info: #618265; // Link colors $link-color: #283f2b; -$link-hover-color: #618265; // Webwork logo background color in the banner $ww-logo-background-color: darken($info, 8%); diff --git a/htdocs/themes/math4-red/README b/htdocs/themes/math4-red/README deleted file mode 100644 index e607958755..0000000000 --- a/htdocs/themes/math4-red/README +++ /dev/null @@ -1,8 +0,0 @@ -This is an "alternative" colorization to math4. If you want to provide -multiple themes to your users you should follow this as an example. - -Everything except for the math4-overrides.js, math4-overrides.css, -_theme-colors.scss, and _theme-overrides.scss files should be links pointing -back to the corresponding files in math4. This will make it so that all your -themes will automatically get updates. All of your changes should be in the -listed override files. diff --git a/htdocs/themes/math4-red/_theme-colors.scss b/htdocs/themes/math4-red/_theme-colors.scss index b34e6f2682..26de64dda7 100644 --- a/htdocs/themes/math4-red/_theme-colors.scss +++ b/htdocs/themes/math4-red/_theme-colors.scss @@ -8,6 +8,7 @@ $info: #c30; // Link colors $link-color: $primary; $link-hover-color: #c00; +$link-color-dark: tint-color($primary, 50%); // Webwork logo background color in the banner $ww-logo-background-color: darken($info, 8%); diff --git a/htdocs/themes/math4-red/_theme-overrides.scss b/htdocs/themes/math4-red/_theme-overrides.scss index 20b5856367..e69de29bb2 100644 --- a/htdocs/themes/math4-red/_theme-overrides.scss +++ b/htdocs/themes/math4-red/_theme-overrides.scss @@ -1,3 +0,0 @@ -a:not(.btn):focus { - outline-color: #{lighten($link-hover-color, 26%)}; -} diff --git a/htdocs/themes/math4-yellow/README b/htdocs/themes/math4-yellow/README deleted file mode 100644 index e607958755..0000000000 --- a/htdocs/themes/math4-yellow/README +++ /dev/null @@ -1,8 +0,0 @@ -This is an "alternative" colorization to math4. If you want to provide -multiple themes to your users you should follow this as an example. - -Everything except for the math4-overrides.js, math4-overrides.css, -_theme-colors.scss, and _theme-overrides.scss files should be links pointing -back to the corresponding files in math4. This will make it so that all your -themes will automatically get updates. All of your changes should be in the -listed override files. diff --git a/htdocs/themes/math4-yellow/_theme-colors.scss b/htdocs/themes/math4-yellow/_theme-colors.scss index cbc8f078bb..527681abff 100644 --- a/htdocs/themes/math4-yellow/_theme-colors.scss +++ b/htdocs/themes/math4-yellow/_theme-colors.scss @@ -5,13 +5,15 @@ $primary: #ffc700; $info: black; +$primary-bg-subtle-dark: shade-color($primary, 90%); +$info-text-emphasis-dark: tint-color($info, 50%); + // Override the default white for the foreground color of active components. // White has poor color contrast with the yellow primary color. $component-active-color: black; // Link colors -$link-color: darken(#bf5454, 30%); -$link-hover-color: lighten($link-color, 30%); +$link-color: shade-color($primary, 60%); // Webwork logo background color in the banner $ww-logo-background-color: $info; @@ -19,9 +21,6 @@ $ww-logo-background-color: $info; // Achievment level bar $ww-achievement-level-color: darken($primary, 15%); -// Make accordion buttons darker. -$accordion-button-active-color: shade-color($primary, 50%); - // Make the navbar colors dark. $navbar-dark-color: rgba(#000, 0.55); $navbar-dark-hover-color: rgba(#000, 0.75); diff --git a/htdocs/themes/math4-yellow/_theme-overrides.scss b/htdocs/themes/math4-yellow/_theme-overrides.scss index 0cf795757f..1046436e60 100644 --- a/htdocs/themes/math4-yellow/_theme-overrides.scss +++ b/htdocs/themes/math4-yellow/_theme-overrides.scss @@ -38,10 +38,30 @@ color: $link-color !important; } -a:not(.btn):focus { - outline-color: #{darken($link-hover-color, 1%)}; -} - :root { --ww-site-nav-link-active-background-color: #{$primary}; + --ww-color-chooser-hover-color: #555; + --ww-color-chooser-focus-outline-color-rgb: 0, 0, 0; + --ww-course-config-tab-link-focus-outline-color: #{rgba(shade-color($primary, 40%), $focus-ring-opacity)}; +} + +@include color-mode(dark) { + --ww-site-nav-link-hover-background-color: #{shade-color($primary, 60%)}; + --ww-course-config-tab-link-focus-outline-color: #{rgba(color-contrast($body-bg-dark), $focus-ring-opacity)}; + + .btn-outline-primary { + --#{$prefix}btn-color: #{tint_color($primary, 40%)}; + } +} + +.masthead { + .institution-logo { + a:not(.btn):focus { + outline-color: #{shade-color($link-hover-color-dark, 70%)}; + } + } + + .login-status .btn.btn-light { + --bs-btn-focus-shadow-rgb: 100, 100, 100; + } } diff --git a/htdocs/themes/math4/README b/htdocs/themes/math4/README deleted file mode 100644 index 0b92a6b6d6..0000000000 --- a/htdocs/themes/math4/README +++ /dev/null @@ -1,18 +0,0 @@ -This folder contains the files necessary for the math4 theme. These files are -tracked by git and any changes made to them will be overwritten when you -upgrade. The two exceptions are math4-overrides.css and math4-overrides.js. - -These files do not need to be present, but if they are they will be included in -system.conf and can be used for general overrides. They can created by copying -math4-overrides.css.dist and math4-overrides.js.dist. This is similar to how -localOverrides.conf interacts with defaults.conf and localOverrides.conf.dist. -In particular if you upgrade your server math4-overrides.js and -math4-overrides.css will not change, but their .dist versions and the other -math4 theme files may change. This might cause problems until you merge the -changes. - -If you want to customize math4 you should only change math4-overrides.css and -math4-overrides.js. Note: Because you can include arbitrary JavaScript in -math4-overrides.js you can actually change pretty much anything, including -adding new html or changing existing html. - diff --git a/htdocs/themes/math4/_theme-colors.scss b/htdocs/themes/math4/_theme-colors.scss index bd57046fb7..b40d760909 100644 --- a/htdocs/themes/math4/_theme-colors.scss +++ b/htdocs/themes/math4/_theme-colors.scss @@ -7,7 +7,7 @@ $info: #1a67ea; // Link colors $link-color: $primary; -$link-hover-color: $info; +$link-color-dark: tint-color($primary, 50%); // Webwork logo background color in the banner $ww-logo-background-color: darken($info, 14%); diff --git a/htdocs/themes/math4/bootstrap.scss b/htdocs/themes/math4/bootstrap.scss index 72cbc9cbd0..3114fe8445 100644 --- a/htdocs/themes/math4/bootstrap.scss +++ b/htdocs/themes/math4/bootstrap.scss @@ -17,10 +17,6 @@ $headings-font-weight: 600; $link-decoration: none; $link-hover-decoration: underline; -// Make breadcrumb dividers and active items a bit darker. -$breadcrumb-divider-color: #495057; -$breadcrumb-active-color: #495057; - @import './theme-colors'; // Include the remainder of bootstrap's scss configuration @@ -75,14 +71,55 @@ $breadcrumb-active-color: #495057; --ww-primary-foreground-color: #{color-contrast($primary)}; --ww-achievement-level-color: #{$ww-achievement-level-color}; --ww-site-nav-link-active-background-color: #{$primary}; + --ww-site-nav-link-hover-background-color: #e1e1e1; + --ww-layout-divider-color: #aaa; + --ww-layout-border-color: #e6e6e6; + --ww-course-config-tab-link-focus-outline-color: #{rgba($primary, $focus-ring-opacity)}; } // Overrides + a:not(.btn):focus { - color: $link-hover-color; outline-style: solid; - outline-color: #{lighten($link-hover-color, 8%)}; outline-width: 1px; + outline-color: #{$link_hover_color}; + box-shadow: none; +} + +@include color-mode(dark) { + --ww-site-nav-link-hover-background-color: #{shade-color($primary, 40%)}; + --ww-layout-divider-color: #666; + --ww-layout-border-color: #495057; + --ww-course-config-tab-link-focus-outline-color: #{rgba(color-contrast($body-bg-dark), $focus-ring-opacity)}; + + .bg-light { + color: var(--bs-body-color) !important; + background-color: var(--bs-primary-bg-subtle) !important; + } + + .btn-outline-primary { + --#{$prefix}btn-color: #{tint_color($primary, 60%)}; + --#{$prefix}btn-border-color: #{tint_color($primary, 20%)}; + } + + .text-danger { + color: var(--bs-danger-text-emphasis) !important; + } + + .text-success { + color: var(--bs-success-text-emphasis) !important; + } + + a:not(.btn):focus { + outline-color: #{$link_hover_color-dark}; + } +} + +.masthead { + a:not(.btn):focus { + outline-color: #{$link_hover_color_dark}; + outline-width: 2px; + } } @import 'theme-overrides'; diff --git a/lib/FormatRenderedProblem.pm b/lib/FormatRenderedProblem.pm index 1c7f0194f3..029de024af 100644 --- a/lib/FormatRenderedProblem.pm +++ b/lib/FormatRenderedProblem.pm @@ -63,7 +63,7 @@ sub formatRenderedProblem { # Add CSS files requested by problems via ADD_CSS_FILE() in the PG file # or via a setting of $ce->{pg}{specialPGEnvironmentVars}{extra_css_files} - # which can be set in course.conf (the value should be an anonomous array). + # which can be set in course.conf (the value should be an anonymous array). my @cssFiles; if (ref($ce->{pg}{specialPGEnvironmentVars}{extra_css_files}) eq 'ARRAY') { push(@cssFiles, { file => $_, external => 0 }) for @{ $ce->{pg}{specialPGEnvironmentVars}{extra_css_files} }; @@ -90,12 +90,12 @@ sub formatRenderedProblem { [ 'node_modules/jquery/dist/jquery.min.js', 0, {} ], [ 'node_modules/jquery-ui-dist/jquery-ui.min.js', 0, {} ], [ 'node_modules/iframe-resizer/js/iframeResizer.contentWindow.min.js', 0, {} ], - [ 'js/MathJaxConfig/mathjax-config.js', 0, { defer => undef } ], - [ 'node_modules/mathjax/es5/tex-svg.js', 0, { defer => undef, id => 'MathJax-script' } ], - [ 'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js', 0, { defer => undef } ], - [ 'js/Problem/problem.js', 0, { defer => undef } ], - [ 'js/System/system.js', 0, { defer => undef } ], - [ 'math4-overrides.js', 1, { defer => undef } ] + [ 'js/MathJaxConfig/mathjax-config.js', 0, { defer => undef } ], + [ 'node_modules/mathjax/tex-svg.js', 0, { defer => undef } ], + [ 'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js', 0, { defer => undef } ], + [ 'js/Problem/problem.js', 0, { defer => undef } ], + [ 'js/System/system.js', 0, { defer => undef } ], + [ 'math4-overrides.js', 1, { defer => undef } ] ); # Get the requested format. @@ -196,11 +196,12 @@ sub formatRenderedProblem { $output->{input} = $ws->{input}; # The following could be constructed from the above, but this is a convenience - $output->{resultSummary} = $resultSummary->to_string if $resultSummary; - $output->{lang} = $PROBLEM_LANG_AND_DIR{lang}; - $output->{dir} = $PROBLEM_LANG_AND_DIR{dir}; - $output->{extra_css_files} = \@extra_css_files; - $output->{extra_js_files} = \@extra_js_files; + $output->{resultSummary} = $resultSummary->to_string if $resultSummary; + $output->{lang} = $PROBLEM_LANG_AND_DIR{lang}; + $output->{dir} = $PROBLEM_LANG_AND_DIR{dir}; + $output->{extra_css_files} = \@extra_css_files; + $output->{extra_js_files} = \@extra_js_files; + $output->{webwork_js_config} = $ws->c->webwork_js_config($ws->{inputs_ref}{showMathJaxErrors} // 0); # Include third party css and javascript files. Only jquery, jquery-ui, mathjax, and bootstrap are needed for # PG. See the comments before the subroutine definitions for load_css and load_js in pg/macros/PG.pl. @@ -267,6 +268,7 @@ sub formatRenderedProblem { showCorrectAnswersOnlyButton => $ws->{inputs_ref}{showCorrectAnswersOnlyButton} // 0, showFooter => $ws->{inputs_ref}{showFooter} // '', problem_data => encode_json($rh_result->{PERSISTENCE_HASH}), + showMathJaxErrors => $ws->{inputs_ref}{showMathJaxErrors} // 0, pretty_print => \&pretty_print ); @@ -368,7 +370,7 @@ EOS $LTIGradeMessage = $ws->c->tag('p', "Unable to update LMS grade. Error: $message")->to_string; push(@{ $rh_result->{debug_messages} }, xml_escape($response->content)); } else { - $LTIGradeMessage = $ws->c->tag('p', 'Grade sucessfully saved.')->to_string; + $LTIGradeMessage = $ws->c->tag('p', 'Grade successfully saved.')->to_string; } } else { $LTIGradeMessage = $ws->c->tag('p', 'Unable to update LMS grade. Error: ' . $response->message)->to_string; diff --git a/lib/HardcopyRenderedProblem.pm b/lib/HardcopyRenderedProblem.pm index 8786cd033d..4f1fcb654b 100644 --- a/lib/HardcopyRenderedProblem.pm +++ b/lib/HardcopyRenderedProblem.pm @@ -2,7 +2,7 @@ =head1 NAME HardcopyRenderedProblem.pm -- Generate a pdf file or zip file containing a tex -file and the neccessary files to generate the pdf file from the result of the +file and the necessary files to generate the pdf file from the result of the renderProblem method. =cut @@ -120,7 +120,7 @@ sub generate_hardcopy_tex { if $@; } my $pgAssetsTex_dir = path($ce->{pg}{directories}{assetsTex}); - for (qw{pg.sty PGML.tex CAPA.tex}) { + for (qw{pg.sty PGML.tex}) { eval { $pgAssetsTex_dir->child($_)->copy_to($working_dir) }; push(@$errors, qq{Failed to copy "$ce->{pg}{directories}{assetsTex}/$_" into directory "$working_dir": $@}) if $@; diff --git a/lib/Mojolicious/WeBWorK.pm b/lib/Mojolicious/WeBWorK.pm index c9315547c4..428d411144 100644 --- a/lib/Mojolicious/WeBWorK.pm +++ b/lib/Mojolicious/WeBWorK.pm @@ -100,13 +100,24 @@ sub startup ($app) { ); # Add a hook to add extra headers if set in the config file. - if (ref $config->{extra_headers} eq 'HASH') { + if (ref $config->{extra_headers} eq 'HASH' || ref $config->{extra_ssl_headers} eq 'HASH') { + my $extraHeaders = ref $config->{extra_headers} eq 'HASH' ? $config->{extra_headers} : {}; + my $extraSSLHeaders = ref $config->{extra_ssl_headers} eq 'HASH' ? $config->{extra_ssl_headers} : {}; $app->hook( before_dispatch => sub ($c) { - for my $path (keys %{ $config->{extra_headers} }) { + for my $path (keys %$extraHeaders) { if ($c->req->url->path =~ /^$path/) { - for (keys %{ $config->{extra_headers}{$path} }) { - $c->res->headers->header($_ => $config->{extra_headers}{$path}{$_}); + for (keys %{ $extraHeaders->{$path} }) { + $c->res->headers->header($_ => $extraHeaders->{$path}{$_}); + } + } + } + if ($c->req->is_secure) { + for my $path (keys %$extraSSLHeaders) { + if ($c->req->url->path =~ /^$path/) { + for (keys %{ $extraSSLHeaders->{$path} }) { + $c->res->headers->header($_ => $extraSSLHeaders->{$path}{$_}); + } } } } diff --git a/lib/WeBWorK/AchievementEvaluator.pm b/lib/WeBWorK/AchievementEvaluator.pm index 249d34ea22..a37b53e5c0 100644 --- a/lib/WeBWorK/AchievementEvaluator.pm +++ b/lib/WeBWorK/AchievementEvaluator.pm @@ -16,7 +16,7 @@ use WeBWorK::WWSafe; our @EXPORT_OK = qw(checkForAchievements); -sub checkForAchievements ($problem_in, $pg, $c, %options) { +sub checkForAchievements ($problem_in, $c, %options) { my $db = $c->db; my $ce = $c->ce; diff --git a/lib/WeBWorK/AchievementItems.pm b/lib/WeBWorK/AchievementItems.pm index f54d407e67..a9ad736516 100644 --- a/lib/WeBWorK/AchievementItems.pm +++ b/lib/WeBWorK/AchievementItems.pm @@ -59,9 +59,6 @@ sub UserItems ($c, $userName, $set, $records) { # Return unless achievement items are enabled. return unless $ce->{achievementsEnabled} && $ce->{achievementItemsEnabled}; - # When acting as another user, achievement items can be listed but not used. - return if $set && $userName ne $c->param('user'); - # Return unless the user has global achievement data. my $globalUserAchievement = $c->{globalData} // $db->getGlobalUserAchievement($userName); return unless $globalUserAchievement && $globalUserAchievement->frozen_hash; @@ -70,6 +67,9 @@ sub UserItems ($c, $userName, $set, $records) { my $use_item_id = $c->param('use_achievement_item_id') // ''; my @items; + # When acting as another user, achievement items can be listed but not used. + $use_item_id = '' if $userName ne $c->param('user'); + for my $item (@{ +ITEMS }) { next unless $globalData->{$item}; my $achievementItem = "WeBWorK::AchievementItems::$item"->new; @@ -90,7 +90,7 @@ sub UserItems ($c, $userName, $set, $records) { $achievementItem->{count}--; $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); $db->putGlobalUserAchievement($globalUserAchievement); - $c->addgoodmessage($c->maketext('[_1] successfuly used. [_2]', $achievementItem->name, $message)); + $c->addgoodmessage($c->maketext('[_1] successfully used. [_2]', $achievementItem->name, $message)); } } diff --git a/lib/WeBWorK/AchievementItems/ExtendDueDate.pm b/lib/WeBWorK/AchievementItems/ExtendDueDate.pm index 2391ab916d..ed355a6e21 100644 --- a/lib/WeBWorK/AchievementItems/ExtendDueDate.pm +++ b/lib/WeBWorK/AchievementItems/ExtendDueDate.pm @@ -4,7 +4,7 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 24 hours. use WeBWorK::Utils qw(x); -use WeBWorK::Utils::DateTime qw(after between); +use WeBWorK::Utils::DateTime qw(before after between); use constant ONE_DAY => 86400; @@ -25,14 +25,64 @@ sub can_use ($self, $set, $records) { sub print_form ($self, $set, $records, $c) { my $randomization_statement = after($set->due_date) ? $c->maketext('All problems will be rerandomized.') : ''; - return $c->tag( - 'p', - $c->maketext( - 'Extend the close date of this assignment to [_1] (an additional 24 hours). [_2]', - $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}), - $randomization_statement - ) - ); + if ($set->enable_reduced_scoring) { + if (before($set->reduced_scoring_date + ONE_DAY)) { + return $c->c( + $c->tag('p', $c->maketext('Extend the deadline by 24 hours. [_1]', $randomization_statement)), + $c->tag( + 'ul', + $c->c( + $c->tag( + 'li', + $c->maketext( + 'You will be able to receive full credit until [_1].', + $c->formatDateTime( + $set->reduced_scoring_date + ONE_DAY, + $c->ce->{studentDateDisplayFormat} + ) + ) + ), + $c->tag( + 'li', + $c->maketext( + 'You will be able to receive reduced credit until [_1].', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}) + ) + ) + )->join('') + ), + )->join(''); + } else { + return $c->c( + $c->tag( + 'p', + $c->maketext( + 'Extend the reduced credit deadline of this assignment to [_1] (an additional 24 hours). [_2]', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}), + $randomization_statement + ) + ), + $c->tag( + 'p', + $c->maketext( + 'Because the deadline has already passed you will only ' + . 'receive reduced credit during this extension.' + ) + ) + )->join(''); + } + + } else { + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this assignment to [_1] (an additional 24 hours). [_2]', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}), + $randomization_statement + ) + ); + } + } sub use_item ($self, $set, $records, $c) { diff --git a/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm b/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm index 6900d1f828..c2310c47b1 100644 --- a/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm +++ b/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm @@ -4,7 +4,7 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend the close date on a test use WeBWorK::Utils qw(x); -use WeBWorK::Utils::DateTime qw(between); +use WeBWorK::Utils::DateTime qw(before between); use constant ONE_DAY => 86400; @@ -12,8 +12,7 @@ sub new ($class) { return bless { id => 'ExtendDueDateGW', name => x('Amulet of Extension'), - description => - x('Extends the close date of a test by 24 hours. Note: The test must still be open for this to work.') + description => x('Extends the close date of a test by 24 hours.') }, $class; } @@ -25,13 +24,61 @@ sub can_use ($self, $set, $records) { } sub print_form ($self, $set, $records, $c) { - return $c->tag( - 'p', - $c->maketext( - 'Extend the close date of this test to [_1] (an additional 24 hours).', - $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}) - ) - ); + if ($set->enable_reduced_scoring) { + if (before($set->reduced_scoring_date + ONE_DAY)) { + return $c->c( + $c->tag('p', $c->maketext('Extend the deadline by 24 hours.')), + $c->tag( + 'ul', + $c->c( + $c->tag( + 'li', + $c->maketext( + 'You will be able to receive full credit until [_1].', + $c->formatDateTime( + $set->reduced_scoring_date + ONE_DAY, + $c->ce->{studentDateDisplayFormat} + ) + ) + ), + $c->tag( + 'li', + $c->maketext( + 'You will be able to receive reduced credit until [_1].', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}) + ) + ) + )->join('') + ), + )->join(''); + } else { + return $c->c( + $c->tag( + 'p', + $c->maketext( + 'Extend the reduced credit deadline of this assignment to [_1] (an additional 24 hours).', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}) + ) + ), + $c->tag( + 'p', + $c->maketext( + 'Because the deadline has already passed you will only ' + . 'receive reduced credit during this extension.' + ) + ) + )->join(''); + } + + } else { + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this assignment to [_1] (an additional 24 hours).', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}) + ) + ); + } } sub use_item ($self, $set, $records, $c) { diff --git a/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm b/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm index f6e24bb3b3..7c24c0d4b8 100644 --- a/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm +++ b/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm @@ -37,7 +37,7 @@ sub print_form ($self, $set, $records, $c) { 'p', $c->maketext( q{This item won't work unless your instructor enables the reduced scoring feature. } - . 'Let your instructor know that you recieved this message.' + . 'Let your instructor know that you received this message.' ) ) unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; diff --git a/lib/WeBWorK/AchievementItems/HalfCreditProb.pm b/lib/WeBWorK/AchievementItems/HalfCreditProb.pm index 307e3d32af..073c09ea83 100644 --- a/lib/WeBWorK/AchievementItems/HalfCreditProb.pm +++ b/lib/WeBWorK/AchievementItems/HalfCreditProb.pm @@ -14,7 +14,7 @@ sub new ($class) { }, $class; } -sub can_use($self, $set, $records) { +sub can_use ($self, $set, $records) { return 0 unless $set->assignment_type eq 'default' && after($set->open_date); diff --git a/lib/WeBWorK/AchievementItems/HalfCreditSet.pm b/lib/WeBWorK/AchievementItems/HalfCreditSet.pm index 37496e9bdd..3f49e53a61 100644 --- a/lib/WeBWorK/AchievementItems/HalfCreditSet.pm +++ b/lib/WeBWorK/AchievementItems/HalfCreditSet.pm @@ -14,7 +14,7 @@ sub new ($class) { }, $class; } -sub can_use($self, $set, $records) { +sub can_use ($self, $set, $records) { return 0 unless $set->assignment_type eq 'default' && after($set->open_date); diff --git a/lib/WeBWorK/AchievementItems/NoReducedCred.pm b/lib/WeBWorK/AchievementItems/NoReducedCred.pm index 8863196463..d0e034eab2 100644 --- a/lib/WeBWorK/AchievementItems/NoReducedCred.pm +++ b/lib/WeBWorK/AchievementItems/NoReducedCred.pm @@ -12,7 +12,7 @@ sub new ($class) { id => 'NoReducedCred', name => x('Potion of Power'), description => x( - 'Remove reduced scoring penalties from an open assignemnt. You will have to resubmit ' + 'Remove reduced scoring penalties from an open assignment. You will have to resubmit ' . 'any problems that have already been penalized to earn full credit on them.' ) }, $class; @@ -32,7 +32,7 @@ sub print_form ($self, $set, $records, $c) { 'p', $c->maketext( q{This item won't work unless your instructor enables the reduced scoring feature. } - . 'Let your instructor know that you recieved this message.' + . 'Let your instructor know that you received this message.' ) ) unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; diff --git a/lib/WeBWorK/AchievementItems/ResurrectGW.pm b/lib/WeBWorK/AchievementItems/ResurrectGW.pm index 00b99ca4ce..2a48181005 100644 --- a/lib/WeBWorK/AchievementItems/ResurrectGW.pm +++ b/lib/WeBWorK/AchievementItems/ResurrectGW.pm @@ -19,7 +19,7 @@ sub new ($class) { }, $class; } -sub can_use($self, $set, $records) { +sub can_use ($self, $set, $records) { return $set->assignment_type =~ /gateway/ && (after($set->due_date) || ($set->reduced_scoring_date && after($set->reduced_scoring_date))); # TODO: Check if a new version can be created, and only allow using this reward in that case. diff --git a/lib/WeBWorK/AchievementItems/ResurrectHW.pm b/lib/WeBWorK/AchievementItems/ResurrectHW.pm index da8364822f..c237b737f4 100644 --- a/lib/WeBWorK/AchievementItems/ResurrectHW.pm +++ b/lib/WeBWorK/AchievementItems/ResurrectHW.pm @@ -16,7 +16,7 @@ sub new ($class) { }, $class; } -sub can_use($self, $set, $records) { +sub can_use ($self, $set, $records) { return $set->assignment_type eq 'default' && (after($set->due_date) || ($set->reduced_scoring_date && after($set->reduced_scoring_date))); } diff --git a/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm b/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm index 7932e6de20..58d1760f22 100644 --- a/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm +++ b/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm @@ -4,7 +4,7 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 48 hours. use WeBWorK::Utils qw(x); -use WeBWorK::Utils::DateTime qw(after between); +use WeBWorK::Utils::DateTime qw(before after between); use constant TWO_DAYS => 172800; @@ -25,14 +25,63 @@ sub can_use ($self, $set, $records) { sub print_form ($self, $set, $records, $c) { my $randomization_statement = after($set->due_date) ? $c->maketext('All problems will be rerandomized.') : ''; - return $c->tag( - 'p', - $c->maketext( - 'Extend the close date of this assignment to [_1] (an additional 48 hours). [_2]', - $c->formatDateTime($set->due_date + TWO_DAYS, $c->ce->{studentDateDisplayFormat}), - $randomization_statement - ) - ); + if ($set->enable_reduced_scoring) { + if (before($set->reduced_scoring_date + TWO_DAYS)) { + return $c->c( + $c->tag('p', $c->maketext('Extend the deadline by 48hours. [_1]', $randomization_statement)), + $c->tag( + 'ul', + $c->c( + $c->tag( + 'li', + $c->maketext( + 'You will be able to receive full credit until [_1].', + $c->formatDateTime( + $set->reduced_scoring_date + TWO_DAYS, + $c->ce->{studentDateDisplayFormat} + ) + ) + ), + $c->tag( + 'li', + $c->maketext( + 'You will be able to receive reduced credit until [_1].', + $c->formatDateTime($set->due_date + TWO_DAYS, $c->ce->{studentDateDisplayFormat}) + ) + ) + )->join('') + ), + )->join(''); + } else { + return $c->c( + $c->tag( + 'p', + $c->maketext( + 'Extend the reduced credit deadline of this assignment to [_1] (an additional 48 hours). [_2]', + $c->formatDateTime($set->due_date + TWO_DAYS, $c->ce->{studentDateDisplayFormat}), + $randomization_statement + ) + ), + $c->tag( + 'p', + $c->maketext( + 'Because the deadline has already passed you will only ' + . 'receive reduced credit during this extension.' + ) + ) + )->join(''); + } + + } else { + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this assignment to [_1] (an additional 48 hours). [_2]', + $c->formatDateTime($set->due_date + TWO_DAYS, $c->ce->{studentDateDisplayFormat}), + $randomization_statement + ) + ); + } } sub use_item ($self, $set, $records, $c) { diff --git a/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm b/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm index 3f2361b835..8e5fa42c79 100644 --- a/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm +++ b/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm @@ -37,7 +37,7 @@ sub print_form ($self, $set, $records, $c) { 'p', $c->maketext( q{This item won't work unless your instructor enables the reduced scoring feature. } - . 'Let your instructor know that you recieved this message.' + . 'Let your instructor know that you received this message.' ) ) unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; diff --git a/lib/WeBWorK/Authen.pm b/lib/WeBWorK/Authen.pm index db565f21f0..ccc02f2cad 100644 --- a/lib/WeBWorK/Authen.pm +++ b/lib/WeBWorK/Authen.pm @@ -327,7 +327,7 @@ sub get_credentials { $self->{login_type} = "normal"; $self->{credential_source} = "params_and_cookie"; debug( - 'credential soure: "cookie (password from params)", user: "', + 'credential source: "cookie (password from params)", user: "', $self->{user_id}, '", key: "', $self->{session_key}, '", timestamp = "', $self->{cookie_timestamp}, '"' @@ -377,9 +377,9 @@ sub check_user { return 0; } - my $User = $db->getUser($user_id); + $self->{user} = $db->getUser($user_id); - unless ($User) { + unless ($self->{user}) { $self->{log_error} = "user unknown"; $self->{error} = $c->maketext(GENERIC_ERROR_MESSAGE); return 0; @@ -388,6 +388,29 @@ sub check_user { return 1; } +sub validate_user { + my $self = shift; + my $c = $self->{c}; + + # Deny access for certain roles (dropped students, proctor roles). + unless ($self->{login_type} =~ /^proctor/ + || $c->ce->status_abbrev_has_behavior($self->{user}->status, 'allow_course_access')) + { + $self->{log_error} = 'user not allowed course access'; + $self->{error} = $c->maketext('This user is not allowed to log in to this course'); + return 0; + } + + # Deny access for permission levels below 'login' permission level. + unless ($c->authz->hasPermissions($self->{user_id}, 'login')) { + $self->{log_error} = 'user not permitted to login'; + $self->{error} = $c->maketext('This user is not allowed to log in to this course'); + return 0; + } + + return 1; +} + sub verify_practice_user { my $self = shift; my $c = $self->{c}; @@ -485,6 +508,7 @@ sub verify_normal_user { $c->stash(authen_error => $c->maketext('The security code is required.')); } } + return 0 unless $self->validate_user; return 1; } else { my $auth_result = $self->authenticate; @@ -494,20 +518,7 @@ sub verify_normal_user { delete $self->session->{two_factor_verification_needed}; if ($auth_result > 0) { - # Deny certain roles (dropped students, proctor roles). - unless ($self->{login_type} =~ /^proctor/ - || $c->ce->status_abbrev_has_behavior($c->db->getUser($user_id)->status, "allow_course_access")) - { - $self->{log_error} = "user not allowed course access"; - $self->{error} = $c->maketext('This user is not allowed to log in to this course'); - return 0; - } - # Deny permission levels below "login" permission level. - unless ($c->authz->hasPermissions($user_id, "login")) { - $self->{log_error} = "user not permitted to login"; - $self->{error} = $c->maketext('This user is not allowed to log in to this course'); - return 0; - } + return 0 unless $self->validate_user; $self->{session_key} = $self->create_session($user_id); $self->{initial_login} = 1; return 1; @@ -844,7 +855,7 @@ sub store_session { } } - # The session parameters need to be set again, because another request may have occured during this + # The session parameters need to be set again, because another request may have occurred during this # request in which case the session parameters for the app will now be set for that request. $self->{c}->setSessionParams; diff --git a/lib/WeBWorK/Authen/Cosign.pm b/lib/WeBWorK/Authen/Cosign.pm deleted file mode 100644 index 3bdae8976c..0000000000 --- a/lib/WeBWorK/Authen/Cosign.pm +++ /dev/null @@ -1,90 +0,0 @@ -package WeBWorK::Authen::Cosign; -use base qw/WeBWorK::Authen/; - -=head1 NAME - -WeBWorK::Authen::Cosign - Authentication plug in for cosign - -to use: include in localOverrides.conf or course.conf - $authen{user_module} = "WeBWorK::Authen::Cosign"; -and add /webwork2 or /webwork2/courseName as a CosignProtected -Location - -if $c->ce->{cosignoff} is set for a course, authentication reverts -to standard WeBWorK authentication. - -=cut - -use strict; -use warnings; -use WeBWorK::Debug; - -# this is similar to the method in the base class, except that cosign -# ensures that we don't get to the address without a login. this means -# that we can't allow guest logins, but don't have to do any password -# checking or cookie management. - -sub get_credentials { - my ($self) = @_; - my $c = $self->{c}; - my $ce = $c->ce; - my $db = $c->db; - - if ($ce->{cosignoff}) { - return $self->SUPER::get_credentials(); - } else { - $c->stash(disable_cookies => 1); - - if (defined($ENV{'REMOTE_USER'})) { - $self->{'user_id'} = $ENV{'REMOTE_USER'}; - $self->{c}->param("user", $ENV{'REMOTE_USER'}); - } else { - return 0; - } - # set external auth parameter so that Login.pm knows - # not to rely on internal logins if there's a check_user - # failure. - $self->{external_auth} = 1; - - # the session key isn't used (cosign is managing this - # for us), and we want to force checking against the - # site_checkPassword - $self->{'session_key'} = undef; - $self->{'password'} = 1; - $self->{'credential_source'} = "params"; - $self->{login_type} = "cosign"; - - return 1; - } -} - -sub site_checkPassword { - my ($self, $userID, $clearTextPassword) = @_; - - if ($self->{c}->ce->{cosignoff}) { - return 0; - } else { - # this is easy; if we're here at all, we've authenticated - # through cosign - return 1; - } -} - -# this is a bit of a cheat, because it does the redirect away from the -# logout script or what have you, but I don't see a way around that. -sub forget_verification { - my ($self, @args) = @_; - my $c = $self->{c}; - - if ($c->ce->{cosignoff}) { - return $self->SUPER::forget_verification(@args); - } else { - $self->{was_verified} = 0; - # $c->headers_out->{"Location"} = $c->ce->{cosign_logout_script}; - # $c->send_http_header; - # return; - $self->{redirect} = $c->ce->{cosign_logout_script}; - } -} - -1; diff --git a/lib/WeBWorK/Authen/LTIAdvanced.pm b/lib/WeBWorK/Authen/LTIAdvanced.pm index 0bd4706b3a..0df122c8f7 100644 --- a/lib/WeBWorK/Authen/LTIAdvanced.pm +++ b/lib/WeBWorK/Authen/LTIAdvanced.pm @@ -71,7 +71,7 @@ sub request_has_data_for_this_verification_module { || !(defined $c->param("oauth_nonce")) || !(defined $c->param("oauth_timestamp"))) { - debug("LTIAdvanced returning that it has insufficent data"); + debug("LTIAdvanced returning that it has insufficient data"); return (0); } else { debug("LTIAdvanced returning that it has sufficient data"); @@ -117,10 +117,9 @@ sub get_credentials { # Determine the WW user_id to use, if possible if (!$ce->{LTI}{v1p1}{preferred_source_of_username}) { - warn - "LTI is not properly configured (no preferred_source_of_username). Please contact your instructor or system administrator."; - $self->{error} = $c->maketext( - "There was an error during the login process. Please speak to your instructor or system administrator."); + $self->{error} = $c->maketext("There was an error during the login process. " + . "Please speak to your instructor or system administrator."); + warn "LTI is not properly configured (no preferred_source_of_username).\n" if $ce->{debug_lti_parameters}; debug("No preferred_source_of_username in " . $c->ce->{'courseName'} . " so LTIAdvanced::get_credentials is returning a 0\n"); @@ -228,8 +227,8 @@ sub get_credentials { warn "================================\n"; } if (!defined($self->{user_id})) { - croak - "LTIAdvanced was unable to create a username from the data provided with the current settings. Set \$debug_lti_parameters=1 in authen_LTI.conf to debug"; + croak "LTIAdvanced was unable to create a username from the data provided with the current settings. " + . "Set \$debug_lti_parameters=1 in authen_LTI.conf to debug"; } $self->{login_type} = "normal"; @@ -237,8 +236,9 @@ sub get_credentials { debug("LTIAdvanced::get_credentials is returning a 1\n"); return 1; } - warn - "LTI is not properly configured (failed to set user_id from preferred_source_of_username or fallback_source_of_username). Please contact your instructor or system administrator."; + warn "LTI is not properly configured (failed to set user_id from preferred_source_of_username or " + . "fallback_source_of_username).\n" + if $ce->{debug_lti_parameters}; $self->{error} = $c->maketext( "There was an error during the login process. Please speak to your instructor or system administrator."); debug("LTIAdvanced::get_credentials is returning a 0\n"); @@ -262,9 +262,9 @@ sub check_user { return 0; } - my $User = $db->getUser($user_id); + $self->{user} = $db->getUser($user_id); - if (!$User) { + if (!$self->{user}) { my %options; $options{ $ce->{LTI}{v1p1}{preferred_source_of_username} } = 1 if ($ce->{LTI}{v1p1}{preferred_source_of_username}); @@ -285,9 +285,8 @@ sub check_user { foreach my $key (keys(%options), ($use_lis_person_sourcedid_options ? @lis_person_sourcedid_options : ())) { if (defined($c->param($key))) { - debug( - "User |$user_id| is unknown but may be an new user from an LSM via LTI. Saw a value for $key About to return a 1" - ); + debug("User |$user_id| is unknown but may be a new user from an LMS via LTI. " + . "Saw a value for $key About to return a 1"); return 1; #This may be a new user coming in from a LMS via LTI. } } @@ -298,14 +297,14 @@ sub check_user { return 0; } - unless ($ce->status_abbrev_has_behavior($User->status, "allow_course_access")) { - $self->{log_error} .= "LOGIN FAILED $user_id - course access denied"; + unless ($ce->status_abbrev_has_behavior($self->{user}->status, "allow_course_access")) { + $self->{log_error} .= "$user_id - course access denied"; $self->{error} = $c->maketext("Authentication failed. Please speak to your instructor."); return 0; } unless ($authz->hasPermissions($user_id, "login")) { - $self->{log_error} .= "LOGIN FAILED $user_id - no permission to login"; + $self->{log_error} .= "$user_id - no permission to login"; $self->{error} = $c->maketext("Authentication failed. Please speak to your instructor."); return 0; } @@ -353,19 +352,15 @@ sub authenticate { debug("LTIAdvanced::authenticate called for user |$user|"); debug "ref(c) = |" . ref($c) . "|"; - my $ce = $c->ce; - my $db = $c->db; - my $courseName = $c->ce->{'courseName'}; + my $ce = $c->ce; # Check nonce to see whether request is legitimate debug("Nonce = |" . $self->{oauth_nonce} . "|"); my $nonce = WeBWorK::Authen::LTIAdvanced::Nonce->new($c, $self->{oauth_nonce}, $self->{oauth_timestamp}); - if (!($nonce->ok)) { - $self->{error} .= $c->maketext( - "There was an error during the login process. Please speak to your instructor or system administrator if this recurs." - ); + if (!$nonce->ok) { debug("Failed to verify nonce"); - return 0; + return $c->maketext("There was an error during the login process. " + . "Please speak to your instructor or system administrator if this recurs."); } debug("c->param(oauth_signature) = |" . $c->param("oauth_signature") . "|"); @@ -418,24 +413,21 @@ sub authenticate { debug("construction of Net::OAuth object failed: $@"); debug("eval failed: ", $@, "

"); - $self->{error} .= $c->maketext( - "There was an error during the login process. Please speak to your instructor or system administrator."); $self->{log_error} .= "Construction of OAuth request record failed"; - return 0; + return $c->maketext( + "There was an error during the login process. Please speak to your instructor or system administrator."); } if (!$request->verify && !$altrequest->verify) { - debug("LTIAdvanced::authenticate request-> verify failed"); - debug("OAuth verification Failed "); + debug("LTIAdvanced::authenticate request->verify failed"); + debug("OAuth verification Failed"); - $self->{error} .= $c->maketext( - "There was an error during the login process. Please speak to your instructor or system administrator."); - $self->{log_error} .= - "OAuth verification failed. Check the Consumer Secret and that the URL in the LMS exactly matches the WeBWorK URL."; + $self->{log_error} .= "OAuth verification failed. " + . "Check the Consumer Secret and that the URL in the LMS exactly matches the WeBWorK URL."; if ($ce->{debug_lti_parameters}) { - warn( - "OAuth verification failed. Check the Consumer Secret and that the URL in the LMS exactly matches the WeBWorK URL as defined in site.conf. E.G. Check that if you have https in the LMS url then you have https in \$server_root_url in site.conf" - ); + warn("OAuth verification failed. Check the Consumer Secret and that the URL in the LMS exactly " + . "matches the WeBWorK URL as defined in site.conf. E.G. Check that if you have https in the " + . "LMS url then you have https in \$server_root_url in site.conf"); } return 0; } else { @@ -443,44 +435,34 @@ sub authenticate { my $userID = $self->{user_id}; - # Indentation of the internal blocks below was modified to follow - # the WW coding standard; however, the leading indentation of the - # if/elsif/closing '}' was kept as in the original code for now. - # Thus the apparenly overlarge indentation below. - if (!$db->existsUser($userID)) { # New User. Create User record + if (!$self->{user}) { # New User. Create User record if ($ce->{block_lti_create_user}) { -# We don't yet have the next string in the PO/POT files - so the next line is disabled. -# $c->maketext("Account creation is currently disabled in this course. Please speak to your instructor or system administrator."); $self->{log_error} .= "Account creation blocked by block_lti_create_user setting. Did not create user $userID."; - if ($ce->{debug_lti_parameters}) { - warn( - "Account creation is currently disabled in this course. Please speak to your instructor or system administrator." - ); - } - return 0; + warn "Account creation is currently disabled in this course. " + . "Please speak to your instructor or system administrator." + if $ce->{debug_lti_parameters}; + return $c->maketext("Account creation is currently disabled in this course. " + . "Please speak to your instructor or system administrator."); } else { # Attempt to create the user, and warn if that fails. - unless ($self->create_user()) { - $c->maketext( - "There was an error during the login process. Please speak to your instructor or system administrator." - ); + unless ($self->create_user) { $self->{log_error} .= "Failed to create user $userID."; - if ($ce->{debug_lti_parameters}) { - warn("Failed to create user $userID."); - } + warn "Failed to create user $userID.\n" if $ce->{debug_lti_parameters}; + return $c->maketext('Unable to create a WeBWorK user. ' + . 'Please speak to your instructor or system administrator.'); } } } elsif ($ce->{LMSManageUserData}) { - $self->{initial_login} = 1 - ; # Set here so login gets logged, even for accounts which maybe_update_user() would not modify or when it fails to update - # Existing user. Possibly modify demographic information and permission level. + # Set here so login gets logged, even for accounts which maybe_update_user() + # would not modify or when it fails to update. + $self->{initial_login} = 1; + + # Existing user. Possibly modify demographic information and permission level. unless ($self->maybe_update_user()) { - # Do not fail the login if data update failed - # FIXME - In the future we would like the message below (and other warn messages in this file) to be sent via maketext. - warn( - "The system failed to update some of your account information. Please speak to your instructor or system administrator." - ); + # Do not fail the login if data update failed + warn("The system failed to update some of your account information. " + . "Please speak to your instructor or system administrator."); } } else { # Set here so login gets logged when $ce->{LMSManageUserData} is false @@ -501,9 +483,8 @@ sub authenticate { } debug("LTIAdvanced is returning a failed authentication"); - $self->{error} = $c->maketext( + return $c->maketext( "There was an error during the login process. Please speak to your instructor or system administrator."); - return (0); } # create a new user trying to log in @@ -515,32 +496,35 @@ sub create_user { my $db = $c->db; my $courseName = $c->ce->{'courseName'}; - ############################################################ # Determine the roles defined for this user by the LTI request # and assign a permission level on that basis. - ############################################################ + my $LTIrolesString = $c->param("roles"); my @LTIroles = split /,/, $LTIrolesString; - #remove the urn string if its present + # Remove the urn string if its present. s/^urn:lti:.*:ims\/lis\/// for @LTIroles; if ($ce->{debug_lti_parameters}) { warn "The adjusted LTI roles defined for this user are: \n--", - join("\n--", @LTIroles), "\n", + join("\n-- ", @LTIroles), "\n", "Any initial ^urn:lti:.*:ims/lis/ segments have been stripped off.\n", "The user will be assigned the highest role defined for them\n", "========================\n"; } - my $nr = scalar(@LTIroles); - if (!defined($ce->{userRoles}->{ $ce->{LTI}{v1p1}{LMSrolesToWeBWorKroles}->{ $LTIroles[0] } })) { - croak("Cannot find a WeBWorK role that corresponds to the LMS role of " . $LTIroles[0] . "."); + if (!defined $ce->{LTI}{v1p1}{LMSrolesToWeBWorKroles}{ $LTIroles[0] } + || !defined $ce->{userRoles}{ $ce->{LTI}{v1p1}{LMSrolesToWeBWorKroles}{ $LTIroles[0] } }) + { + $self->{log_error} = "Cannot find a WeBWorK role that corresponds to the LMS role of $LTIroles[0]."; + warn "Cannot find a WeBWorK role that corresponds to the LMS role of $LTIroles[0].\n" + if $ce->{debug_lti_parameters}; + return 0; } - my $LTI_webwork_permissionLevel = $ce->{userRoles}->{ $ce->{LTI}{v1p1}{LMSrolesToWeBWorKroles}->{ $LTIroles[0] } }; - if ($nr > 1) { - for (my $j = 1; $j < $nr; $j++) { + my $LTI_webwork_permissionLevel = $ce->{userRoles}{ $ce->{LTI}{v1p1}{LMSrolesToWeBWorKroles}{ $LTIroles[0] } }; + if (@LTIroles > 1) { + for (my $j = 1; $j < @LTIroles; $j++) { my $wwRole = $ce->{LTI}{v1p1}{LMSrolesToWeBWorKroles}->{ $LTIroles[$j] }; next unless defined $wwRole; if ($LTI_webwork_permissionLevel < $ce->{userRoles}->{$wwRole}) { @@ -549,20 +533,26 @@ sub create_user { } } - ####### End defining roles and $LTI_webwork_permissionLevel####### + # End defining roles and $LTI_webwork_permissionLevel warn "New user: $userID -- requested permission level is $LTI_webwork_permissionLevel." - if ($ce->{debug_lti_parameters}); + if $ce->{debug_lti_parameters}; + + # Don't create a user that does not have permission to login. + if ($LTI_webwork_permissionLevel < $ce->{userRoles}{ $ce->{permissionLevels}{login} }) { + $self->{log_error} .= "$userID - no permission to login"; + return 0; + } - # We dont create users with too high of a permission level - # for security reasons. + # We dont create users with too high of a permission level for security reasons. if ($LTI_webwork_permissionLevel > $ce->{userRoles}->{ $ce->{LTIAccountCreationCutoff} }) { $self->{log_error} .= - "userID: $userID -- Unknown instructor attempting to log in via LTI. Instructor accounts must be created manually"; - croak $c->maketext( - "The instructor account with user id [_1] does not exist. Please create the account manually via WeBWorK.", - $userID - ); + "The instructor account with user id $userID does not exist. " + . 'Instructor accounts must be created manually.'; + warn "The instructor account with user id $userID does not exist. " + . "Instructor accounts must be created manually.\n" + if $ce->{debug_lti_parameters}; + return 0; } my $newUser = $db->newUser(); @@ -584,6 +574,7 @@ sub create_user { } $db->addUser($newUser); + $self->{user} = $newUser; $self->write_log_entry("New user $userID added via LTIAdvanced login"); # Assign permssion level @@ -649,7 +640,6 @@ sub maybe_update_user { my $db = $c->db; my $courseName = $c->ce->{'courseName'}; - my $user = $db->getUser($userID); my $permissionLevel = $db->getPermissionLevel($userID); # We don't alter records of users with too high a permission if (defined($permissionLevel->permission) @@ -684,10 +674,10 @@ sub maybe_update_user { my $change_made = 0; for my $element (@elements) { - if ($user->$element ne $tempUser->$element) { + if ($self->{user}->$element ne $tempUser->$element) { $change_made = 1; warn "WeBWorK User has $element: " - . $user->$element + . $self->{user}->$element . " but LMS user has $element " . $tempUser->$element . "\n" if ($ce->{debug_lti_parameters}); diff --git a/lib/WeBWorK/Authen/LTIAdvanced/SubmitGrade.pm b/lib/WeBWorK/Authen/LTIAdvanced/SubmitGrade.pm index 26aa71071d..5b175d0c74 100644 --- a/lib/WeBWorK/Authen/LTIAdvanced/SubmitGrade.pm +++ b/lib/WeBWorK/Authen/LTIAdvanced/SubmitGrade.pm @@ -298,7 +298,7 @@ EOS } # Blackboard seems to return this when there is no prior grade. - # See: https://webwork.maa.org/moodle/mod/forum/discuss.php?d=5002 + # See: https://forums.openwebwork.org/mod/forum/discuss.php?d=5002 $priorScore = '' if $priorScore eq 'success'; # Do not update the score if there is no significant change. Note that the cases where the webwork score diff --git a/lib/WeBWorK/Authen/LTIAdvantage.pm b/lib/WeBWorK/Authen/LTIAdvantage.pm index c2a7351481..8be03a7c7a 100644 --- a/lib/WeBWorK/Authen/LTIAdvantage.pm +++ b/lib/WeBWorK/Authen/LTIAdvantage.pm @@ -34,7 +34,7 @@ sub request_has_data_for_this_verification_module ($self) { return 1; } - debug('LTIAdvantage returning that it has insufficent data'); + debug('LTIAdvantage returning that it has insufficient data'); return 0; } @@ -141,7 +141,8 @@ sub get_credentials ($self) { } # Fallback if necessary - if (!defined $self->{user_id} + if ($ce->{LTI}{v1p3}{fallback_source_of_username} + && !defined $self->{user_id} && (my $user_id = $extract_claim->($ce->{LTI}{v1p3}{fallback_source_of_username}))) { $user_id_source = $ce->{LTI}{v1p3}{fallback_source_of_username}; @@ -235,21 +236,21 @@ sub check_user ($self) { return 0; } - my $User = $db->getUser($user_id); + $self->{user} = $db->getUser($user_id); - if (!$User) { - debug("User |$user_id| is unknown but may be an new user from an LMS via LTI."); + if (!$self->{user}) { + debug("User |$user_id| is unknown but may be a new user from an LMS via LTI."); return 1; } - unless ($ce->status_abbrev_has_behavior($User->status, 'allow_course_access')) { - $self->{log_error} .= "LOGIN FAILED $user_id - course access denied"; + unless ($ce->status_abbrev_has_behavior($self->{user}->status, 'allow_course_access')) { + $self->{log_error} .= "$user_id - course access denied"; $self->{error} = $c->maketext('Authentication failed. Please speak to your instructor.'); return 0; } unless ($authz->hasPermissions($user_id, 'login')) { - $self->{log_error} .= "LOGIN FAILED $user_id - no permission to login"; + $self->{log_error} .= "$user_id - no permission to login"; $self->{error} = $c->maketext('Authentication failed. Please speak to your instructor.'); return 0; } @@ -290,11 +291,9 @@ sub authenticate ($self) { # The actual authentication for this module has already been done. This just creates and updates users if needed. - my $ce = $c->ce; - my $db = $c->db; - my $courseName = $c->ce->{courseName}; + my $ce = $c->ce; - if (!$db->existsUser($self->{user_id})) { + if (!$self->{user}) { # New User. Create User record. if ($ce->{block_lti_create_user}) { $self->{log_error} .= @@ -303,12 +302,15 @@ sub authenticate ($self) { warn $c->maketext('Account creation is currently disabled in this course. ' . 'Please speak to your instructor or system administrator.') . "\n"; } - return 0; + return $c->maketext("Account creation is currently disabled in this course. " + . "Please speak to your instructor or system administrator."); } else { # Attempt to create the user, and warn if that fails. unless ($self->create_user) { $self->{log_error} .= "Failed to create user $self->{user_id}."; - warn "Failed to create user $self->{user_id}.\n" if ($ce->{debug_lti_parameters}); + warn "Failed to create user $self->{user_id}.\n" if $ce->{debug_lti_parameters}; + return $c->maketext('Unable to create a WeBWorK user. ' + . 'Please speak to your instructor or system administrator.'); } } } elsif ($ce->{LMSManageUserData}) { @@ -360,7 +362,10 @@ sub create_user ($self) { } if (!defined($ce->{userRoles}{ $ce->{LTI}{v1p3}{LMSrolesToWeBWorKroles}{ $LTIroles[0] } })) { - die "Cannot find a WeBWorK role that corresponds to the LMS role of $LTIroles[0].\n"; + $self->{log_error} = "Cannot find a WeBWorK role that corresponds to the LMS role of $LTIroles[0].\n"; + warn "Cannot find a WeBWorK role that corresponds to the LMS role of $LTIroles[0].\n" + if $ce->{debug_lti_parameters}; + return 0; } my $LTI_webwork_permissionLevel = $ce->{userRoles}{ $ce->{LTI}{v1p3}{LMSrolesToWeBWorKroles}{ $LTIroles[0] } }; @@ -378,11 +383,19 @@ sub create_user ($self) { # We dont create users with too high of a permission level for security reasons. if ($LTI_webwork_permissionLevel > $ce->{userRoles}{ $ce->{LTIAccountCreationCutoff} }) { - die $c->maketext( - 'The instructor account with user id [_1] does not exist. ' - . 'Instructor accounts must be created manually.', - $userID - ) . "\n"; + $self->{log_error} = + "The instructor account with user id $userID does not exist. " + . 'Instructor accounts must be created manually.'; + warn "The instructor account with user id $userID does not exist. " + . "Instructor accounts must be created manually.\n" + if $ce->{debug_lti_parameters}; + return 0; + } + + # Don't create a user that does not have permission to login. + if ($LTI_webwork_permissionLevel < $ce->{userRoles}{ $ce->{permissionLevels}{login} }) { + $self->{log_error} .= "$userID - no permission to login"; + return 0; } my $newUser = $db->newUser; @@ -401,6 +414,7 @@ sub create_user ($self) { $ce->{LTI}{v1p3}{modify_user}($self, $newUser) if ref($ce->{LTI}{v1p3}{modify_user}) eq 'CODE'; $db->addUser($newUser); + $self->{user} = $newUser; $self->write_log_entry("New user $userID added via LTIAdvantange login"); # Set permission level. @@ -466,7 +480,6 @@ sub maybe_update_user ($self) { my $userID = $self->{user_id}; my $courseName = $ce->{courseName}; - my $user = $db->getUser($userID); my $permissionLevel = $db->getPermissionLevel($userID); # We don't alter records of users with too high a permission. @@ -492,10 +505,10 @@ sub maybe_update_user ($self) { my $change_made = 0; for my $element (qw(last_name first_name email_address status section recitation student_id)) { - if ($user->$element ne $tempUser->$element) { + if ($self->{user}->$element ne $tempUser->$element) { $change_made = 1; warn "WeBWorK User has $element: " - . $user->$element + . $self->{user}->$element . " but LMS user has $element " . $tempUser->$element . "\n" if ($ce->{debug_lti_parameters}); diff --git a/lib/WeBWorK/Authen/Moodle.pm b/lib/WeBWorK/Authen/Moodle.pm deleted file mode 100644 index 58eccc42cd..0000000000 --- a/lib/WeBWorK/Authen/Moodle.pm +++ /dev/null @@ -1,253 +0,0 @@ -package WeBWorK::Authen::Moodle; -use base qw/WeBWorK::Authen/; - -=head1 NAME - -WeBWorK::Authen::Moodle - Allow moodle cookies to be used for WeBWorK authentication. - -=cut - -=for comment - -TODO - -* Modules that modify data that's being taken from moodle should check for "alternative URLs" in the -CE that can point back to the moodle installation. operations include: change password, change user -data, change permission level, add user, delete user. Run this for a rough estimate: - pcregrep -r '\$db->(add|put)(User|Password|PermissionLevel)\b' lib - -=cut - -use strict; -use warnings; -use Digest::MD5 qw/md5_hex/; -use WeBWorK::Debug; -use Date::Parse; # for moodle 1.7 date parsing - -sub new { - my $self = shift->SUPER::new(@_); - - $self->init_mdl_session; - - return $self; -} - -# call superclass get_credentials. if no credentials were found, look for a moodle cooke. -# if a moodle cookie is found, a new webwork session is created and the session key is used. -# (this is similar to what happens when a guest user is selected.) -sub get_credentials { - my $self = shift; - my $c = $self->{c}; - - my $super_result = $self->SUPER::get_credentials; - if ($super_result) { - debug("Superclass's get_credentials found credentials. Using them.\n"); - return $super_result; - } - - my ($moodle_user_id, $moodle_expiration_time) = $self->fetch_moodle_session; -#debug("fetch_moodle_session returned: moodle_user_id='$moodle_user_id' moodle_expiration_time='$moodle_expiration_time'.\n"); # causes errors when undefined - - if (defined $moodle_user_id and defined $moodle_expiration_time and time <= $moodle_expiration_time) { - my $newKey = $self->create_session($moodle_user_id); - debug("Unexpired moodle session found. Created new WeBWorK session with newKey='$newKey'.\n"); - - $self->{user_id} = $moodle_user_id; - $self->{session_key} = $newKey; - $self->{login_type} = "normal"; - $self->{credential_source} = "moodle"; - return 1; - } else { - debug("No moodle session found or moodle session expired. No credentials to be had.\n"); - warn( - "No moodle session found or moodle sessioin expired. If this happens repeatedly and you are constantly being asked - to log back in ask your moodle admin to check that the Moodle item: - Server -> Session Handling -> dbsessions (Use database for session information) has been checked." - ); - } - - return 0; -} - -# extend the moodle session if authentication succeeded -sub site_fixup { - my $self = shift; - - if ($self->was_verified) { - debug("User was verified, updating moodle session.\n"); - $self->update_moodle_session; - } -} - -# we assume that the database is set up to use the moodle password table, which uses MD5 passwords. -# this is overridden to accommodate this. -sub checkPassword { - my ($self, $userID, $possibleClearPassword) = @_; - my $db = $self->{c}->db; - - debug("Moodle module is doing the password checking.\n"); - - my $Password = $db->getPassword($userID); # checked - if (defined $Password) { - # check against Moodle password database - my $possibleMD5Password = md5_hex($possibleClearPassword); - debug("Hashed password from supplied cleartext: '$possibleMD5Password'.\n"); - debug("Hashed password from Password record: '", $Password->password, "'.\n"); - if ($possibleMD5Password eq $Password->password) { - $self->write_log_entry("AUTH MDL: password accepted"); - return 1; - } else { - if ($self->can("site_checkPassword")) { - $self->write_log_entry("AUTH MDL: password rejected, deferring to site_checkPassword"); - return $self->site_checkPassword($userID, $possibleClearPassword); - } else { - $self->write_log_entry("AUTH MDL: password rejected"); - return 0; - } - } - - } -} - -sub check_session { - my ($self, $user_id, $session_key, $update_timestamp) = @_; - - my ($sessionExists, $keyMatches, $timestampValid) = - $self->SUPER::check_session($user_id, $session_key, $update_timestamp); - debug( - "SUPER::check_session returned: sessionExists='", - $sessionExists, "' keyMatches='", - $keyMatches, "' timestampValid='", - $timestampValid, "'" - ); - - if ($update_timestamp and $sessionExists and $keyMatches and not $timestampValid) { - debug("special case: webwork key matches an expired session (check for a unexpired moodle session)"); - my ($moodle_user_id, $moodle_expiration_time) = $self->fetch_moodle_session; - debug( - "fetch_moodle_session returned: moodle_user_id='$moodle_user_id' moodle_expiration_time='$moodle_expiration_time'.\n" - ); - if (defined $moodle_user_id - and $moodle_user_id eq $user_id - and defined $moodle_expiration_time - and time <= $moodle_expiration_time) - { - $self->{session_key} = $self->create_session($moodle_user_id); - $timestampValid = 1; - } - } - - return $sessionExists, $keyMatches, $timestampValid; -} - -################################################################################ - -use DBI; -use PHP::Serialization qw/unserialize/; - -use constant DEFAULT_EXPIRY => 7200; - -sub init_mdl_session { - my $self = shift; - - # version-specific stuff - $self->{moodle17} = $self->{c}->ce->{authen}{moodle_options}{moodle17}; - $self->{sql_session_table} = $self->{moodle17} ? "sessions2" : "sessions"; - $self->{sql_data_field} = $self->{moodle17} ? "sessdata" : "data"; - - $self->{mdl_dbh} = DBI->connect_cached( - $self->{c}->ce->{authen}{moodle_options}{dsn}, - $self->{c}->ce->{authen}{moodle_options}{username}, - $self->{c}->ce->{authen}{moodle_options}{password}, - { - PrintError => 0, - RaiseError => 1, - }, - ); - die $DBI::errstr unless defined $self->{mdl_dbh}; -} - -sub fetch_moodle_session { - # fetches the basic information from the moodle session. - # returns the user name and expiration time of the moodle session - # Note that we don't worry about the user being in this course at this point. - # That is taken care of in Schema::Moodle::User. - my ($self) = @_; - my $c = $self->{c}; - my $db = $c->db; - - my $cookie = $c->req->cookie('MoodleSession'); - return unless $cookie; - - my $session_table = $self->prefix_table($self->{sql_session_table}); - my $data_field = $self->{sql_data_field}; - my $stmt = "SELECT `expiry`,`$data_field` FROM `$session_table` WHERE `sesskey`=?"; - my @bind_vals = $cookie->value; - - my $sth = $self->{mdl_dbh}->prepare_cached($stmt, undef, 3); # 3: see DBI docs - $sth->execute(@bind_vals); - my $row = $sth->fetchrow_arrayref; - $sth->finish; - return unless defined $row; - - my ($expires, $data_string) = @$row; - - # Moodle 1.7 stores expiry as a DATETIME, but WeBWorK wants a UNIX timestamp. - $expires = str2time($expires) if $self->{moodle17}; - - my $data = unserialize_session($data_string); - my $username = $data->{"USER"}{"username"}; - - return $username, $expires; -} - -sub update_moodle_session { - # extend the timeout of the current moodle session, if one exists. - my ($self) = @_; - my $c = $self->{c}; - my $db = $c->db; - - my $cookie = $c->req->cookie('MoodleSession'); - return unless $cookie; - - my $config_table = $self->prefix_table("config"); - my $value = "IFNULL((SELECT `value` FROM `$config_table` WHERE `name`=?),?)+?"; - - # Moodle 1.7 stores expiry as a DATETIME, but WeBWorK supplies a UNIX timestamp. - $value = "FROM_UNIXTIME($value)" if $self->{moodle17}; - - my $session_table = $self->prefix_table($self->{sql_session_table}); - my $stmt = "UPDATE `$session_table` SET `expiry`=$value WHERE `sesskey`=?"; - my @bind_vals = ("sessiontimeout", DEFAULT_EXPIRY, time, $cookie->value); - - my $sth = $self->{mdl_dbh}->prepare_cached($stmt, undef, 3); # 3: see DBI docs - my $result = $sth->execute(@bind_vals); - $sth->finish; - - return defined $result; -} - -sub prefix_table { - my ($self, $base) = @_; - if (defined $self->{c}->ce->{authen}{moodle_options}{table_prefix}) { - return $self->{c}->ce->{authen}{moodle_options}{table_prefix} . $base; - } else { - return $base; - } -} - -sub unserialize_session { - my $serialData = shift; - # first, url decode: - $serialData =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg; - # then, split it up by |, it's some ADODB sillyness - my @serialArray = split(/(\w+)\|/, $serialData); - my %variables; - # finally, actually deserialize it: - for (my $i = 1; $i < $#serialArray; $i += 2) { - $variables{ $serialArray[$i] } = unserialize($serialArray[ $i + 1 ]); - } - return \%variables; -} - -1; diff --git a/lib/WeBWorK/Authen/Shibboleth.pm b/lib/WeBWorK/Authen/Shibboleth.pm index 498220f598..61e6d7f027 100644 --- a/lib/WeBWorK/Authen/Shibboleth.pm +++ b/lib/WeBWorK/Authen/Shibboleth.pm @@ -11,7 +11,7 @@ To use this module copy C to C, and uncomment the line in C that reads C. -Refer to the L +Refer to the L documentation on the WeBWorK wiki and the instructions in the comments of the C file. diff --git a/lib/WeBWorK/Authz.pm b/lib/WeBWorK/Authz.pm index a238f3fb67..784d97c8fb 100644 --- a/lib/WeBWorK/Authz.pm +++ b/lib/WeBWorK/Authz.pm @@ -46,7 +46,7 @@ use warnings; use Carp qw/croak/; use WeBWorK::Utils::DateTime qw(before); -use WeBWorK::Utils::Sets qw(is_restricted); +use WeBWorK::Utils::Sets qw(restricted_set_message); use WeBWorK::Authen::Proctor; use Net::IP; use Scalar::Util qw(weaken); @@ -414,34 +414,35 @@ sub checkSet { # Cache the set for future use as needed. This should probably be more sophisticated than this. $self->{merged_set} = $set; + # Save restricted set messages to show to instructors if they exist. + my $canViewUnopened = $self->hasPermissions($userName, "view_unopened_sets"); + my @restrictedSetMessages; + # Now we know that the set is assigned to the appropriate user. - # Check to see if the user is trying to access a set that is not open. - if ( - before($set->open_date) - && !$self->hasPermissions($userName, "view_unopened_sets") - && !( - defined $set->assignment_type - && $set->assignment_type =~ /gateway/ - && $node_name eq 'problem_list' - && $db->countSetVersions($effectiveUserName, $set->set_id) - ) - ) - { - return $c->maketext("Requested set '[_1]' is not yet open.", $setName); - } + # $c->{viewSetCheck} is used to configure what is shown on ProblemSet page. # Check to make sure that the set is visible, and that the user is allowed to view hidden sets. my $visible = $set && $set->visible ne '0' && $set->visible ne '1' ? 1 : $set->visible; if (!$visible && !$self->hasPermissions($userName, "view_hidden_sets")) { + $c->{viewSetCheck} = 'hidden'; + return $c->maketext("Requested set '[_1]' is not available.", $setName); + } + + # Check to see if the user is trying to access a set that is not open. + if (before($set->open_date) && !$canViewUnopened) { + $c->{viewSetCheck} = 'not-open'; return $c->maketext("Requested set '[_1]' is not available yet.", $setName); } # Check to see if conditional release conditions have been met. - if ($ce->{options}{enableConditionalRelease} - && is_restricted($db, $set, $effectiveUserName) - && !$self->hasPermissions($userName, "view_unopened_sets")) - { - return $c->maketext("The prerequisite conditions have not been met for set '[_1]'.", $setName); + my $conditional_msg = restricted_set_message($c, $set, 'conditional'); + if ($conditional_msg) { + if ($canViewUnopened) { + push(@restrictedSetMessages, $conditional_msg); + } else { + $c->{viewSetCheck} = 'restricted'; + return $conditional_msg; + } } # Check to be sure that gateways are being sent to the correct content generator. @@ -474,25 +475,27 @@ sub checkSet { # Check for ip restrictions. my $badIP = $self->invalidIPAddress($set); - return $badIP if $badIP; - - # If LTI grade passback is enabled and set to 'homework' mode then we need to make sure that there is a sourcedid - # for this set before students access it. - my $LTIGradeMode = $ce->{LTIGradeMode} // ''; - - if ($LTIGradeMode eq 'homework' && !$self->hasPermissions($userName, "view_unopened_sets")) { - my $LMS = - $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} - ? $c->link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) - : $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name}; - return $c->b($c->maketext( - 'You must use your Learning Management System ([_1]) to access this set. ' - . 'Try logging in to the Learning Management System and visiting the set from there.', - $LMS - )) - unless $set->lis_source_did || ($ce->{LTIVersion} eq 'v1p3' && $ce->{LTI}{v1p3}{ignoreMissingSourcedID}); + if ($badIP) { + if ($self->hasPermissions($userName, 'view_ip_restricted_sets')) { + push(@restrictedSetMessages, $badIP); + } else { + $c->{viewSetCheck} = 'restricted'; + return $badIP; + } + } + + # Check for lis_source_did if LTI grade passback is 'homework'. + my $lti_msg = restricted_set_message($c, $set, 'lti'); + if ($lti_msg) { + if ($canViewUnopened) { + push(@restrictedSetMessages, $lti_msg); + } else { + $c->{viewSetCheck} = 'restricted'; + return $lti_msg; + } } + $c->{restrictedSetMessages} = \@restrictedSetMessages if @restrictedSetMessages; return 0; } @@ -514,8 +517,7 @@ sub invalidIPAddress { return 0 if (!defined($set->restrict_ip) || $set->restrict_ip eq '' - || $set->restrict_ip eq 'No' - || $self->hasPermissions($userName, 'view_ip_restricted_sets')); + || $set->restrict_ip eq 'No'); my $clientIP = new Net::IP($c->tx->remote_address); @@ -530,7 +532,9 @@ sub invalidIPAddress { # if there are no addresses in the locations, return an error that # says this return $c->maketext( - "Client ip address [_1] is not allowed to work this assignment, because the assignment has ip address restrictions and there are no allowed locations associated with the restriction. Contact your professor to have this problem resolved.", + 'Client ip address [_1] is not allowed to work this assignment, because the assignment has ip address ' + . 'restrictions and there are no allowed locations associated with the restriction. Contact your ' + . 'professor to have this problem resolved.', $clientIP->ip() ) if (!@restrictAddresses); @@ -552,17 +556,13 @@ sub invalidIPAddress { # this is slightly complicated by having to check relax_restrict_ip my $badIP = ''; if ($restrictType eq 'RestrictTo' && !$inRestrict) { - $badIP = - "Client ip address " - . $clientIP->ip() - . " is not in the list of addresses from " - . "which this assignment may be worked."; + $badIP = $c->maketext( + 'Client ip address [_1] is not in the list of addresses from which this assignment may be worked.', + $clientIP->ip()); } elsif ($restrictType eq 'DenyFrom' && $inRestrict) { - $badIP = - "Client ip address " - . $clientIP->ip() - . " is in the list of addresses from " - . "which this assignment may not be worked."; + $badIP = $c->maketext( + 'Client ip address [_1] is in the list of addresses from which this assignment may not be worked.', + $clientIP->ip()); } else { return 0; } diff --git a/lib/WeBWorK/ConfigValues.pm b/lib/WeBWorK/ConfigValues.pm index 411be4426c..5a61a7e860 100644 --- a/lib/WeBWorK/ConfigValues.pm +++ b/lib/WeBWorK/ConfigValues.pm @@ -213,7 +213,7 @@ sub getConfigValues ($ce) { { var => 'hardcopyThemePGEditor', doc => x('Hardcopy Theme for Problem Editor'), - doc2 => x('Choose a layout/styling theme for PDF hardcopy production from the Prooblem Editor.'), + doc2 => x('Choose a layout/styling theme for PDF hardcopy production from the Problem Editor.'), values => [qw(empty.xml)], type => 'popuplist', hashVar => '{hardcopyThemePGEditor}' @@ -278,8 +278,8 @@ sub getConfigValues ($ce) { "Achievements are a way to gamify WeBWorK. In parallel to a student's regular scores on " . 'assignments, they earn "achievement points" for (a) answering an exercise correctly, and ' . '(b) earning badges. Badges can be for tasks like earning 100% on three assignments, ' - . 'answering five questions correclty on the first attempt, etc. As students earn achivement ' - . 'points, they can "level up" as well. An instructor can manage Achievents using the ' + . 'answering five questions correctly on the first attempt, etc. As students earn achievement ' + . 'points, they can "level up" as well. An instructor can manage Achievements using the ' . 'Achievements Manager tool.' ), type => 'boolean' @@ -545,8 +545,8 @@ sub getConfigValues ($ce) { var => 'permissionLevels{report_bugs}', doc => x('Can report bugs'), doc2 => x( - 'Users with at least this permission level get a link in the left panel for reporting bugs to the ' - . 'bug tracking system at bugs.webwork.maa.org.' + 'Users with at least this permission level get a link in the left panel for reporting issues at ' + . 'github.com/openwebwork/webwork2.' ), type => 'permission' }, @@ -776,12 +776,12 @@ sub getConfigValues ($ce) { }, { var => 'problemGraderScore', - doc => x('Method to enter problem scores in the single problem manual grader'), + doc => x('Method to enter problem scores in the manual problem graders'), doc2 => x( - 'This configures if the single problem manual grader has inputs to enter problem scores as ' - . 'a percent, a point value, or both. Note, the problem score is always saved as a ' - . 'percent, so when using a point value, the problem score will be rounded to the ' - . 'nearest whole percent.' + 'This configures if the manual problem grader or single problem grader has inputs to enter ' + . 'problem scores as a percent, a point value, or both. Note, the problem score is always ' + . 'saved as a percent, so when using a point value, the problem score will be rounded to ' + . 'the nearest whole percent.' ), values => [qw(Percent Point Both)], type => 'popuplist' @@ -796,7 +796,7 @@ sub getConfigValues ($ce) { . 'the "Check Answers" button. Or if that button is also not present, it will activate ' . 'the "Preview My Answers" button. A third option is "conservative". In this case, the ' . 'enter key behaves like "preview" when the "Submit" button is available and there are ' - . 'only finitely many attempts allowed. Otherise the enter key behaves like "submit". ' + . 'only finitely many attempts allowed. Otherwise the enter key behaves like "submit". ' . 'Note that this is only affects homework problem pages, not test/quiz pages, and not ' . 'instructor pages like the PG Editor and the Library Browser.' ), @@ -820,7 +820,8 @@ sub getConfigValues ($ce) { doc2 => x( 'A "Reveal" button must be clicked to make a correct answer visible any time that correct ' . 'answers for a problem are shown. Note that this is always the case for instructors ' - . 'before answers are available to students, and in "Show Me Another" problems.' + . 'before answers are available to students (except when the problem grader is open), and ' + . 'in "Show Me Another" problems.' ), type => 'boolean' } @@ -829,13 +830,15 @@ sub getConfigValues ($ce) { x('E-Mail'), { var => 'mail{feedbackSubjectFormat}', - doc => x('Format for the subject line in feedback emails'), + doc => x('Format for the subject of feedback emails'), doc2 => x( - 'When students click the Email Instructor button to send feedback, WeBWorK fills in the ' - . 'subject line. Here you can set the subject line. In it, you can have various bits of ' - . 'information filled in with the following escape sequences.

  • %c = course ID
  • ' + '

    When students click the Email Instructor button to send feedback, WeBWorK fills in ' + . 'the subject line. Here you can set the subject line. In it, you can have various bits of ' + . 'information filled in with the following escape sequences.

    • %c = course ID
    • ' . '
    • %u = user ID
    • %s = set ID
    • %p = problem ID
    • %x = section
    • ' - . '
    • %r = recitation
    • %% = literal percent sign
    ' + . '
  • %r = recitation
  • %% = literal percent sign

If content is between ' + . "a brace pair, like '{ rec:%r}', then it will only be included in the subject line if all " + . 'substitutions within the double brace pair are defined and nonempty.' ), width => 45, type => 'text' @@ -1152,13 +1155,15 @@ sub getConfigValues ($ce) { }; # Get the list of theme folders in the theme directory. - my $themes = eval { path($ce->{webworkDirs}{themes})->list({ dir => 1 })->map('basename')->sort; }; + my $themes = eval { + path($ce->{webworkDirs}{themes})->list({ dir => 1 })->grep(sub {-d})->map('basename')->sort; + }; die "can't opendir $ce->{webworkDirs}{themes}: $@" if $@; # Get the list of all site hardcopy theme files. my $hardcopyThemesSite = eval { path($ce->{webworkDirs}{hardcopyThemes})->list->grep(qr/\.xml$/)->map('basename')->sort }; - die "Unabled to list files in $ce->{webworkDirs}{hardcopyThemes}: $@" if $@; + die "Unable to list files in $ce->{webworkDirs}{hardcopyThemes}: $@" if $@; my $hardcopyThemesCourse = eval { path($ce->{courseDirs}{hardcopyThemes})->list->grep(sub { diff --git a/lib/WeBWorK/ContentGenerator.pm b/lib/WeBWorK/ContentGenerator.pm index 3e069f2a03..2bd7756686 100644 --- a/lib/WeBWorK/ContentGenerator.pm +++ b/lib/WeBWorK/ContentGenerator.pm @@ -32,6 +32,7 @@ use MIME::Base64; use Scalar::Util qw(weaken); use HTML::Entities; use Encode; +use Mojo::JSON qw(encode_json true); use WeBWorK::File::Scoring qw(parse_scoring_file); use WeBWorK::Localize; @@ -94,7 +95,7 @@ The method content() is called to send the page content to client. async sub go ($c) { my $ce = $c->ce; - # If grades are being passed back to the lti, then peroidically update all of the + # If grades are being passed back to the lti, then periodically update all of the # grades because things can get out of sync if instructors add or modify sets. massUpdate($c) if $c->stash('courseID') && ref($c->db) && $ce->{LTIGradeMode}; @@ -109,8 +110,6 @@ async sub go ($c) { my $tx = $c->render_later->tx; - $c->stash->{footerWidthClass} = $c->can('info') ? 'col-md-8' : 'col-12'; - if ($c->can('pre_header_initialize')) { my $pre_header_initialize = $c->pre_header_initialize; await $pre_header_initialize @@ -132,6 +131,8 @@ async sub go ($c) { await $initialize if ref $initialize eq 'Future' || ref $initialize eq 'Mojo::Promise'; } + $c->stash->{footerWidthClass} //= $c->can('info') ? 'col-md-8' : 'col-12'; + $c->content; # All content generator modules must have rendered at this point unless there was an error in which case an error @@ -646,7 +647,7 @@ sub timestamp ($c) { Defined in this package. Print any messages (error or non-error) resulting from the last form submission. -This could be used to give Sucess and Failure messages after an action is performed by a module. +This could be used to give Success and Failure messages after an action is performed by a module. The implementation in this package outputs the value of the field $c->{status_message}, if it is present. @@ -682,20 +683,19 @@ sub page_title ($c) { return route_title($c, $c->current_route, 1); } -=item webwork_url - -Defined in this package. - -Outputs the $webwork_url defined in site.conf, unless $webwork_url is equal to -"/", in which case this outputs the empty string. +=item webwork_js_config -This is used to set a value in a global webworkConfig javascript variable, -that can be accessed in javascript files. +Outputs the webwork2 JavaScript configuration. This configuration can be +accessed by JavaScript files to obtain various webwork2 settings. =cut -sub webwork_url ($c) { - return $c->location; +sub webwork_js_config ($c, $showMathJaxErrors = 0) { + return encode_json({ + webwork_url => $c->location, + mathJaxBSColorSchemeUrl => getAssetURL($c->ce, 'js/MathJaxConfig/bs-color-scheme.js'), + $showMathJaxErrors ? (showMathJaxErrors => true) : () + }); } =item warnings() @@ -813,7 +813,7 @@ there are pg errors. =cut sub have_warnings ($c) { - return $c->stash('warnings') || $c->{pgerrors}; + return $c->stash('warnings'); } =item exists_theme_file @@ -1122,7 +1122,7 @@ object from which the base path will be taken. %options can consist of: Can be either a reference to an array or a reference to a hash. -If it is a reference to a hash, it maps parmaeter names to values. These +If it is a reference to a hash, it maps parameter names to values. These parameters will be included in the generated link. If a value is an arrayref, the values of the array referenced will be used. If a value is undefined, the value from the current request will be used. @@ -1220,8 +1220,8 @@ Used to display a generic warning message at the top of the page =cut sub warningMessage ($c) { - return $c->maketext('Warning: There may be something wrong with this question. ' - . 'Please inform your instructor including the warning messages below.'); + return $c->maketext('Warning: WeBWorK has encountered warnings while processing your request. ' + . 'See the warning messages below for details.'); } =item $string = formatDateTime($date_time, $format_string, $timezone, $locale) @@ -1238,7 +1238,7 @@ If C<$locale> is provided, the string returned will be in the format of that locale. If C<$locale> is not provided, Perl defaults to using C. Note that the defaults for C<$timezone> and C<$locale> should almost never be -overriden when this method is used. +overridden when this method is used. =cut diff --git a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm index 02f1467544..12225ae105 100644 --- a/lib/WeBWorK/ContentGenerator/CourseAdmin.pm +++ b/lib/WeBWorK/ContentGenerator/CourseAdmin.pm @@ -707,9 +707,10 @@ sub do_rename_course ($c) { eval { renameCourse( - courseID => $rename_oldCourseID, - ce => WeBWorK::CourseEnvironment->new({ courseName => $rename_oldCourseID }), - newCourseID => $rename_newCourseID, + courseID => $rename_oldCourseID, + ce => WeBWorK::CourseEnvironment->new({ courseName => $rename_oldCourseID }), + newCourseID => $rename_newCourseID, + updateLTICourseMap => 1, %optional_arguments ); }; diff --git a/lib/WeBWorK/ContentGenerator/Feedback.pm b/lib/WeBWorK/ContentGenerator/Feedback.pm index 336e5fc127..335caff765 100644 --- a/lib/WeBWorK/ContentGenerator/Feedback.pm +++ b/lib/WeBWorK/ContentGenerator/Feedback.pm @@ -12,7 +12,7 @@ use Email::Stuffer; use Try::Tiny; use WeBWorK::Upload; -use WeBWorK::Utils qw(createEmailSenderTransportSMTP fetchEmailRecipients); +use WeBWorK::Utils qw(createEmailSenderTransportSMTP fetchEmailRecipients formatEmailSubject); # request paramaters used # @@ -108,18 +108,15 @@ sub initialize ($c) { } } - my %subject_map = ( - 'c' => $courseID, - 'u' => $user ? $user->user_id : undef, - 's' => $set ? $set->set_id : undef, - 'p' => $problem ? $problem->problem_id : undef, - 'x' => $user ? $user->section : undef, - 'r' => $user ? $user->recitation : undef, - '%' => '%', + my $subject = formatEmailSubject( + $ce->{mail}{feedbackSubjectFormat}, + $courseID, + $user ? $user->user_id : '', + $set ? $set->set_id : '', + $problem ? $problem->problem_id : '', + $user ? $user->section : '', + $user ? $user->recitation : '' ); - my $chars = join('', keys %subject_map); - my $subject = $ce->{mail}{feedbackSubjectFormat} || 'WeBWorK question from %c: %u set %s/prob %p'; - $subject =~ s/%([$chars])/defined $subject_map{$1} ? $subject_map{$1} : ''/eg; my %data = ( user => $user, diff --git a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm index f97712269f..246ab07820 100644 --- a/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm +++ b/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm @@ -274,14 +274,15 @@ sub get_instructor_comment ($c, $problem) { async sub pre_header_initialize ($c) { # Make sure these are defined for the templates. - $c->stash->{problems} = []; - $c->stash->{pg_results} = []; - $c->stash->{startProb} = 0; - $c->stash->{endProb} = 0; - $c->stash->{numPages} = 0; - $c->stash->{pageNumber} = 0; - $c->stash->{problem_numbers} = []; - $c->stash->{probOrder} = []; + $c->stash->{problems} = []; + $c->stash->{pg_results} = []; + $c->stash->{startProb} = 0; + $c->stash->{endProb} = 0; + $c->stash->{numPages} = 0; + $c->stash->{pageNumber} = 0; + $c->stash->{problem_numbers} = []; + $c->stash->{probOrder} = []; + $c->stash->{haveProblemWarnings} = 0; # If authz->checkSet has failed, then this set is invalid. No need to proceeded. return if $c->{invalidSet}; @@ -502,7 +503,6 @@ async sub pre_header_initialize ($c) { my $maxAttemptsPerVersion = $tmplSet->attempts_per_version || 0; my $timeInterval = $tmplSet->time_interval || 0; my $versionsPerInterval = $tmplSet->versions_per_interval || 0; - my $timeLimit = $tmplSet->version_time_limit || 0; # What happens if someone didn't set one of these? Perhaps this can happen if we're handed a malformed set, where # the values in the database are null. @@ -588,7 +588,8 @@ async sub pre_header_initialize ($c) { $set = $db->getMergedSetVersion($effectiveUserID, $setID, $setVersionNumber); $set->visible(1); - # If there is a cap on problems per page, make sure that is respected in case something higher snuck in. + # If there is a cap on problems per page, make sure that is respected + # in case something higher snuck in. if ( $ce->{test}{maxProblemsPerPage} && ($tmplSet->problems_per_page == 0 @@ -603,6 +604,8 @@ async sub pre_header_initialize ($c) { # Convert the floating point value from Time::HiRes to an integer for use below. Truncate toward 0. my $timeNowInt = int($c->submitTime); + my $timeLimit = ($tmplSet->version_time_limit || 0) * $effectiveUser->accommodation_time_factor; + # Set up creation time, and open and due dates. my $ansOffset = $set->answer_date - $set->due_date; $set->version_creation_time($timeNowInt); @@ -625,7 +628,7 @@ async sub pre_header_initialize ($c) { $cleanSet->due_date($set->due_date); $cleanSet->answer_date($set->answer_date); $cleanSet->version_last_attempt_time($set->version_last_attempt_time); - $cleanSet->version_time_limit($set->version_time_limit); + $cleanSet->version_time_limit($set->version_time_limit * $effectiveUser->accommodation_time_factor); $cleanSet->attempts_per_version($set->attempts_per_version); $cleanSet->assignment_type($set->assignment_type); $db->putSetVersion($cleanSet); @@ -780,14 +783,11 @@ async sub pre_header_initialize ($c) { return; } - # Unset the showProblemGrader parameter if the "Hide Problem Grader" button was clicked. - $c->param(showProblemGrader => undef) if $c->param('hideProblemGrader'); - # What does the user want to do? my %want = ( showOldAnswers => $user->showOldAnswers ne '' ? $user->showOldAnswers : $ce->{pg}{options}{showOldAnswers}, showCorrectAnswers => 1, - showProblemGrader => $c->param('showProblemGrader') || 0, + showProblemGrader => $userID ne $effectiveUserID, showHints => 0, # Hints are not yet implemented in gateway quzzes. showSolutions => 1, recordAnswers => $c->{submitAnswers} && !$authz->hasPermissions($userID, 'avoid_recording_answers'), @@ -887,9 +887,6 @@ async sub pre_header_initialize ($c) { my @problems; my @pg_results; - # pg errors are stored here. - $c->{errors} = []; - # Process the problems as needed. my @mergedProblems; if ($setID eq 'Undefined_Set') { @@ -1313,7 +1310,8 @@ async sub pre_header_initialize ($c) { } elsif ($endTime > $set->due_date) { $c->{exceededAllowedTime} = 1; } - $c->{elapsedTime} = int(($endTime - $set->open_date) / 0.6 + 0.5) / 100; + $c->{elapsedTime} = int(($endTime - $set->open_date) / 0.6 + 0.5) / 100; + $c->{completedTime} = $c->formatDateTime($endTime, $ce->{studentDateDisplayFormat}); # Get the number of attempts and number of remaining attempts. $c->{attemptNumber} = @@ -1346,7 +1344,7 @@ sub path ($c, $args) { $courseName => $navigation_allowed ? $c->url_for('set_list') : '', $setID eq 'Undefined_Set' || $c->{invalidSet} || $c->{actingCreationError} || $c->stash->{actingConfirmation} - ? ($setID => '') + ? ($setID =~ /^(.+),(v\d+)$/ ? ($1 => $c->url_for('problem_list', setID => $1), $2 => '') : ($setID => '')) : ( $c->{set}->set_id => $c->url_for('problem_list', setID => $c->{set}->set_id), 'v' . $c->{set}->version_id => '' @@ -1362,7 +1360,7 @@ sub nav ($c, $args) { return '' if $c->{invalidSet} || $c->{actingCreationError} || $c->stash->{actingConfirmation}; # Set up and display a student navigation for those that have permission to act as a student. - if ($c->authz->hasPermissions($userID, 'become_student') && $effectiveUserID ne $userID) { + if ($c->authz->hasPermissions($userID, 'become_student')) { my $setID = $c->{set}->set_id; return '' if $setID eq 'Undefined_Set'; @@ -1371,81 +1369,83 @@ sub nav ($c, $args) { # Find all versions of this set that have been taken (excluding those taken by the current user). my @users = - $db->listSetVersionsWhere({ user_id => { not_like => $userID }, set_id => { like => "$setID,v\%" } }); + $db->listSetVersionsWhere({ user_id => { '!=' => $userID }, set_id => { like => "$setID,v\%" } }); my @allUserRecords = $db->getUsers(map { $_->[0] } @users); - my $filter = $c->param('studentNavFilter'); - - # Format the student names for display, and associate the users with the test versions. - my %filters; - my @userRecords; - for (0 .. $#allUserRecords) { - # Add to the sections and recitations if defined. Also store the first user found in that section or - # recitation. This user will be switched to when the filter is selected. - my $section = $allUserRecords[$_]->section; - $filters{"section:$section"} = - [ $c->maketext('Filter by section [_1]', $section), $allUserRecords[$_]->user_id, $users[$_][2] ] - if $section && !$filters{"section:$section"}; - my $recitation = $allUserRecords[$_]->recitation; - $filters{"recitation:$recitation"} = - [ $c->maketext('Filter by recitation [_1]', $recitation), $allUserRecords[$_]->user_id, $users[$_][2] ] - if $recitation && !$filters{"recitation:$recitation"}; - - # Only keep this user if it satisfies the selected filter if a filter was selected. - next - unless !$filter - || ($filter =~ /^section:(.*)$/ && $allUserRecords[$_]->section eq $1) - || ($filter =~ /^recitation:(.*)$/ && $allUserRecords[$_]->recitation eq $1); - - my $addRecord = $allUserRecords[$_]; - push @userRecords, $addRecord; - - $addRecord->{displayName} = - ($addRecord->last_name || $addRecord->first_name - ? $addRecord->last_name . ', ' . $addRecord->first_name - : $addRecord->user_id); - $addRecord->{setVersion} = $users[$_][2]; - } + if (@allUserRecords) { + my $filter = $c->param('studentNavFilter'); + + # Format the student names for display, and associate the users with the test versions. + my %filters; + my @userRecords; + for (0 .. $#allUserRecords) { + # Add to the sections and recitations if defined. Also store the first user found in that section or + # recitation. This user will be switched to when the filter is selected. + my $section = $allUserRecords[$_]->section; + $filters{"section:$section"} = + [ $c->maketext('Filter by section [_1]', $section), $allUserRecords[$_]->user_id, $users[$_][2] ] + if $section && !$filters{"section:$section"}; + my $recitation = $allUserRecords[$_]->recitation; + $filters{"recitation:$recitation"} = [ + $c->maketext('Filter by recitation [_1]', $recitation), $allUserRecords[$_]->user_id, + $users[$_][2] + ] + if $recitation && !$filters{"recitation:$recitation"}; + + # Only keep this user if it satisfies the selected filter if a filter was selected. + next + unless !$filter + || ($filter =~ /^section:(.*)$/ && $allUserRecords[$_]->section eq $1) + || ($filter =~ /^recitation:(.*)$/ && $allUserRecords[$_]->recitation eq $1); + + my $addRecord = $allUserRecords[$_]; + push @userRecords, $addRecord; + + $addRecord->{displayName} = + ($addRecord->last_name || $addRecord->first_name + ? $addRecord->last_name . ', ' . $addRecord->first_name + : $addRecord->user_id); + $addRecord->{setVersion} = $users[$_][2]; + } - # Sort by last name, then first name, then user_id, then set version. - @userRecords = sort { - lc($a->last_name) cmp lc($b->last_name) - || lc($a->first_name) cmp lc($b->first_name) - || lc($a->user_id) cmp lc($b->user_id) - || lc($a->{setVersion}) <=> lc($b->{setVersion}) - } @userRecords; - - # Find the previous, current, and next test. - my $currentTestIndex = 0; - for (0 .. $#userRecords) { - if ($userRecords[$_]->user_id eq $effectiveUserID && $userRecords[$_]->{setVersion} == $setVersion) { - $currentTestIndex = $_; - last; + # Sort by last name, then first name, then user_id, then set version. + @userRecords = sort { + lc($a->last_name) cmp lc($b->last_name) + || lc($a->first_name) cmp lc($b->first_name) + || lc($a->user_id) cmp lc($b->user_id) + || lc($a->{setVersion}) <=> lc($b->{setVersion}) + } @userRecords; + + # Find the previous, current, and next test. + my $currentTestIndex = 0; + for (0 .. $#userRecords) { + if ($userRecords[$_]->user_id eq $effectiveUserID && $userRecords[$_]->{setVersion} == $setVersion) { + $currentTestIndex = $_; + last; + } } + my $prevTest = $currentTestIndex > 0 ? $userRecords[ $currentTestIndex - 1 ] : 0; + my $nextTest = $currentTestIndex < $#userRecords ? $userRecords[ $currentTestIndex + 1 ] : 0; + + # Mark the current test. + $userRecords[$currentTestIndex]{currentTest} = 1; + + # Show the student nav. + return $c->include( + 'ContentGenerator/GatewayQuiz/nav', + userID => $userID, + eUserID => $effectiveUserID, + userRecords => \@userRecords, + setVersion => $setVersion, + prevTest => $prevTest, + nextTest => $nextTest, + currentTestIndex => $currentTestIndex, + filters => \%filters, + filter => $filter + ); } - my $prevTest = $currentTestIndex > 0 ? $userRecords[ $currentTestIndex - 1 ] : 0; - my $nextTest = $currentTestIndex < $#userRecords ? $userRecords[ $currentTestIndex + 1 ] : 0; - - # Mark the current test. - $userRecords[$currentTestIndex]{currentTest} = 1; - - # Show the student nav. - return $c->include( - 'ContentGenerator/GatewayQuiz/nav', - userRecords => \@userRecords, - setVersion => $setVersion, - prevTest => $prevTest, - nextTest => $nextTest, - currentTestIndex => $currentTestIndex, - filters => \%filters, - filter => $filter - ); } -} - -sub warningMessage ($c) { - return $c->maketext('Warning: There may be something wrong with a question in this test. ' - . 'Please inform your instructor including the warning messages below.'); + return ''; } # Evaluation utility @@ -1494,10 +1494,9 @@ async sub getProblemHTML ($c, $effectiveUser, $set, $formFields, $mergedProblem) && $c->can_showCorrectAnswersForAll($set, $c->{problem}, $c->{tmplSet})), showMessages => !$showOnlyCorrectAnswers, showCorrectAnswers => ( - $c->{will}{showProblemGrader} ? 2 - : !$c->{previewAnswers} && $c->can_showCorrectAnswersForAll($set, $c->{problem}, $c->{tmplSet}) + !$c->{previewAnswers} && $c->can_showCorrectAnswersForAll($set, $c->{problem}, $c->{tmplSet}) ? ($c->ce->{pg}{options}{correctRevealBtnAlways} ? 1 : 2) - : !$c->{previewAnswers} && $c->{will}{showCorrectAnswers} ? 1 + : $c->{will}{showProblemGrader} || (!$c->{previewAnswers} && $c->{will}{showCorrectAnswers}) ? 1 : 0 ), debuggingOptions => getTranslatorDebuggingOptions($c->authz, $c->{userID}), @@ -1507,27 +1506,14 @@ async sub getProblemHTML ($c, $effectiveUser, $set, $formFields, $mergedProblem) }, ); - # Warnings in the renderPG subprocess will not be caught by the global warning handler of this process. - # So rewarn them and let the global warning handler take care of it. - warn $pg->{warnings} if $pg->{warnings}; - - if ($pg->{flags}{error_flag}) { - push @{ $c->{errors} }, - { - set => $set->set_id . ',v' . $set->version_id, - problem => $mergedProblem->problem_id, - message => $pg->{errors}, - context => $pg->{body_text}, - }; - $pg->{body_text} = undef; - } - # If the user can check answers and either this is not an answer submission or the problem_data form # parameter was previously set, then set or update the problem_data form parameter. $c->param('problem_data_' . $mergedProblem->problem_id => encode_json($pg->{PERSISTENCE_HASH} || '{}')) if $c->{can}{checkAnswers} && (!$c->{submitAnswers} || defined $c->param('problem_data_' . $mergedProblem->problem_id)); + $c->stash->{haveProblemWarnings} = 1 if $pg->{warnings} || @{ $pg->{pgwarning} // [] }; + return $pg; } diff --git a/lib/WeBWorK/ContentGenerator/Hardcopy.pm b/lib/WeBWorK/ContentGenerator/Hardcopy.pm index fdd35ed8ca..7e7809f389 100644 --- a/lib/WeBWorK/ContentGenerator/Hardcopy.pm +++ b/lib/WeBWorK/ContentGenerator/Hardcopy.pm @@ -10,6 +10,7 @@ problem sets. use File::Temp qw/tempdir/; use Mojo::File; +use Mojo::Util qw(xml_escape); use String::ShellQuote; use Archive::Zip qw(:ERROR_CODES); use XML::LibXML; @@ -130,14 +131,16 @@ async sub pre_header_initialize ($c) { # Make sure the format is valid. unless (grep { $_ eq $hardcopy_format } keys %HC_FORMATS) { - $c->addbadmessage(qq{"$hardcopy_format" is not a valid hardcopy format.}); + $c->addbadmessage($c->maketext('"[_1]" is not a valid hardcopy format.', xml_escape($hardcopy_format))); $validation_failed = 1; } # Make sure we are allowed to generate hardcopy in this format. unless ($authz->hasPermissions($userID, "download_hardcopy_format_$hardcopy_format")) { - $c->addbadmessage( - $c->maketext('You do not have permission to generate hardcopy in [_1] format.', $hardcopy_format)); + $c->addbadmessage($c->maketext( + 'You do not have permission to generate hardcopy in [_1] format.', + xml_escape($hardcopy_format) + )); $validation_failed = 1; } @@ -284,13 +287,14 @@ async sub pre_header_initialize ($c) { my $fullFilePath = "$ce->{webworkDirs}{tmp}/$courseID/hardcopy/$userID/$tempFile"; unless (-e $fullFilePath) { - $c->addbadmessage($c->maketext('The requested file "[_1]" does not exist on the server.', $tempFile)); + $c->addbadmessage( + $c->maketext('The requested file "[_1]" does not exist on the server.', xml_escape($tempFile))); return; } unless ($baseName =~ /\.$userID\./ || $authz->hasPermissions($userID, 'download_hardcopy_multiuser')) { $c->addbadmessage($c->maketext('You do not have permission to access the requested file "[_1]".'), - $tempFile); + xml_escape($tempFile)); return; } @@ -670,7 +674,7 @@ sub generate_hardcopy_tex ($c, $temp_dir_path, $final_file_basename) { ); } } - for (qw{pg.sty PGML.tex CAPA.tex}) { + for (qw{pg.sty PGML.tex}) { eval { Mojo::File->new("$ce->{pg}{directories}{assetsTex}/$_")->copy_to($bundle_path) }; if ($@) { $c->add_error( diff --git a/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm b/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm index 906845efa4..353e3f06ea 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm @@ -212,7 +212,7 @@ sub save_as_handler ($c) { )); } else { $c->addbadmessage($c->maketext( - 'Unable to change the achievement notification template for achivement [_1]. Unknown error.', + 'Unable to change the achievement notification template for achievement [_1]. Unknown error.', $achievementName )); } diff --git a/lib/WeBWorK/ContentGenerator/Instructor/Index.pm b/lib/WeBWorK/ContentGenerator/Instructor/Index.pm index 2ac5e5e94e..ac0f00f2be 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/Index.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/Index.pm @@ -80,13 +80,6 @@ sub pre_header_initialize ($c) { } else { push @error, E_ONE_SET; } - } elsif (defined $c->param('user_stats')) { - if ($nusers == 1) { - $route = 'instructor_user_statistics'; - $args{userID} = $firstUserID; - } else { - push @error, E_ONE_USER; - } } elsif (defined $c->param('set_stats')) { if ($nsets == 1) { $route = 'instructor_set_statistics'; diff --git a/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm b/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm index c7736812de..6e208d6cd9 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm @@ -90,7 +90,7 @@ the submit button pressed (the action). Requested actions and aliases View/Reload action = view Generate Hardcopy: action = hardcopy - Format Code: action = format_code + Code Maintenance: action = code_maintenance Save: action = save Save as: action = save_as Append: action = add_problem @@ -108,25 +108,25 @@ not exist. The path to the actual file being edited is stored in inputFilePath. use Mojo::File; use XML::LibXML; -use WeBWorK::Utils qw(not_blank x max); -use WeBWorK::Utils::Files qw(surePathToFile readFile path_is_subdir); -use WeBWorK::Utils::Instructor qw(assignProblemToAllSetUsers addProblemToSet); -use WeBWorK::Utils::JITAR qw(seq_to_jitar_id jitar_id_to_seq); -use WeBWorK::Utils::Sets qw(format_set_name_display); -use SampleProblemParser qw(getSampleProblemCode generateMetadata); +use WeBWorK::Utils qw(not_blank x max); +use WeBWorK::Utils::Files qw(surePathToFile readFile path_is_subdir); +use WeBWorK::Utils::Instructor qw(assignProblemToAllSetUsers addProblemToSet); +use WeBWorK::Utils::JITAR qw(seq_to_jitar_id jitar_id_to_seq); +use WeBWorK::Utils::Sets qw(format_set_name_display); +use WeBWorK::PG::SampleProblemParser qw(getSampleProblemCode generateMetadata); use constant DEFAULT_SEED => 123456; # Editor tabs -use constant ACTION_FORMS => [qw(view hardcopy format_code save save_as add_problem revert)]; +use constant ACTION_FORMS => [qw(view hardcopy code_maintenance save save_as add_problem revert)]; use constant ACTION_FORM_TITLES => { - view => x('View/Reload'), - hardcopy => x('Generate Hardcopy'), - format_code => x('Format Code'), - save => x('Save'), - save_as => x('Save As'), - add_problem => x('Append'), - revert => x('Revert'), + view => x('View/Reload'), + hardcopy => x('Generate Hardcopy'), + code_maintenance => x('Code Maintenance'), + save => x('Save'), + save_as => x('Save As'), + add_problem => x('Append'), + revert => x('Revert'), }; my $BLANKPROBLEM = 'newProblem.pg'; @@ -847,9 +847,9 @@ sub view_handler ($c) { return; } -# The format_code action is handled by javascript. This is provided just in case +# The code_maintenance action is handled by javascript. This is provided just in case # something goes wrong and the handler is called. -sub format_code_handler { } +sub code_maintenance_handler { } sub hardcopy_handler ($c) { # Redirect to problem editor page. @@ -1278,7 +1278,7 @@ sub save_as_handler ($c) { $new_file_type = $file_type; } else { $c->addbadmessage($c->maketext( - 'Please use radio buttons to choose the method for saving this file. Uknown saveMode: [_1].', $saveMode + 'Please use radio buttons to choose the method for saving this file. Unknown saveMode: [_1].', $saveMode )); return; } diff --git a/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm b/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm index 7bf2c9ed78..dae595e356 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm @@ -13,6 +13,7 @@ use HTML::Entities; use WeBWorK::Utils::JITAR qw(jitar_id_to_seq); use WeBWorK::Utils::Rendering qw(renderPG); use WeBWorK::Utils::Sets qw(get_test_problem_position format_set_name_display); +use WeBWorK::Utils::DateTime qw(before); async sub initialize ($c) { my $authz = $c->authz; @@ -96,6 +97,17 @@ async sub initialize ($c) { if ($c->param('assignGrades')) { $c->addgoodmessage($c->maketext('Grades have been saved for all current users.')); + # Get all of the merged user sets for this set. These are needed to determine if the problem sub_status also + # needs to be set. The sub_status must be set if reduced scoring is not enabled for the course or set or if it + # is before the reduced scoring date. + my %mergedSets; + if ($c->stash->{set}->assignment_type =~ /gateway/) { + $mergedSets{ $_->user_id }{ $_->version_id } = $_ + for $db->getMergedSetVersionsWhere({ set_id => { like => "$setID,v\%" } }); + } else { + %mergedSets = map { $_->user_id => { 0 => $_ } } $db->getMergedSetsWhere({ set_id => $setID }); + } + for my $user (@{ $c->stash->{users} }) { my $userID = $user->user_id; for (@{ $user->{data} }) { @@ -115,9 +127,16 @@ async sub initialize ($c) { $_->{problem}{flags} =~ s/:needs_grading$//; if ($c->param("$userID.$versionID.mark_correct")) { $_->{problem}->status(1); + $_->{problem}->sub_status(1); } elsif (defined $c->param("$userID.$versionID.score")) { my $newscore = $c->param("$userID.$versionID.score") / 100; - if ($newscore != $_->{problem}->status) { $_->{problem}->status($newscore); } + if ($newscore != $_->{problem}->status) { + $_->{problem}->status($newscore); + $_->{problem}->sub_status($newscore) + if !$ce->{pg}{ansEvalDefaults}{enableReducedScoring} + || !$mergedSets{$userID}{$versionID}->enable_reduced_scoring + || before($mergedSets{$userID}{$versionID}->reduced_scoring_date); + } } if ($versionID) { $db->putProblemVersion($_->{problem}); } diff --git a/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm b/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm index eba2d2aa82..19c2c557aa 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm @@ -29,20 +29,15 @@ use constant SET_FIELDS => [ ]; use constant PROBLEM_FIELDS => [qw(source_file value max_attempts showMeAnother showHintsAfter prPeriod att_to_open_children counts_parent_grade)]; -use constant USER_PROBLEM_FIELDS => [qw(problem_seed status num_correct num_incorrect)]; +use constant USER_PROBLEM_FIELDS => [qw(problem_seed status)]; # These constants determine what order those fields should be displayed in. -use constant HEADER_ORDER => [qw(set_header hardcopy_header)]; -use constant PROBLEM_FIELD_ORDER => [ - qw(problem_seed status value max_attempts showMeAnother showHintsAfter prPeriod attempted last_answer num_correct - num_incorrect) -]; -# For gateway sets, don't allow changing max_attempts on a per problem basis. -use constant GATEWAY_PROBLEM_FIELD_ORDER => - [qw(problem_seed status value attempted last_answer num_correct num_incorrect)]; +use constant HEADER_ORDER => [qw(set_header hardcopy_header)]; +use constant PROBLEM_FIELD_ORDER => [qw(problem_seed status value max_attempts showMeAnother showHintsAfter prPeriod)]; +use constant GATEWAY_PROBLEM_FIELD_ORDER => [qw(problem_seed status value)]; use constant JITAR_PROBLEM_FIELD_ORDER => [ qw(problem_seed status value max_attempts showMeAnother showHintsAfter prPeriod att_to_open_children - counts_parent_grade attempted last_answer num_correct num_incorrect) + counts_parent_grade) ]; # Exclude the gateway set fields from the set field order, because they are only displayed for sets that are gateways. @@ -70,14 +65,28 @@ use constant JITAR_SET_FIELD_ORDER => [qw(restrict_prob_progression email_instru # [min, max, step] will introduce validation, so should not be used on just any # input where we expect numbers # size => "50", # size of the edit box (if any) -# override => "none", # none, one, any, all - defines for whom this data can/must be overidden +# override => "all", # none, one, any, all - defines for whom this data can be overidden # module => "problem_list", # WeBWorK module # default => 0 # if a field cannot default to undefined/empty what should it default to -# labels => { # special values can be hashed to display labels -# 1 => x('Yes'), -# 0 => x('No'), +# labels => { # Display labels for type "choose" or type "[min, max, step]". +# 1 => x('Yes'), # This is required for type "choose", is optional for type "[min, max, step]", +# 0 => x('No'), # and should never be used for any other type. # }, +# choices => [ qw(0 1) ] # Order of the labels above. This must be given if labels is. # convertby => 60, # divide incoming database field values by this, and multiply when saving +# +# Note that if "type" is "[min, max, step]" and "labels" is defined, then a select will be shown before the numeric +# input with the labels as options. The label values must not overlap with the numeric values (i.e., min must be +# greater than all defined label values), and must be numeric. The labels must also include a "numeric" label. This +# label will be shown when the number input value is used. It is impomrtant that the choices should not include the +# special "numeric" value, and that all other choices have numeric values. + +# FIXME: The override "none" case needs to be revisited if it is ever used again. It is definitely not implemented +# correctly, or it is pointless. If override "none" is to mean it can't be changed at all, then why have it? But then +# again, with the current implementation fields set to override "none" are not shown when editing for more than one +# user, but are shown when editing for one user (although they still can't be edited). That doesn't make sense. The +# previous fields that used it were also of type "hidden", and it turns out that type "hidden" and override "none" +# really means don't use at all, and so listing them was pointless. use constant BLANKPROBLEM => 'newProblem.pg'; @@ -281,7 +290,9 @@ use constant FIELD_PROPERTIES => { 'This sets a number of minutes for each version of a test, once it is started. Use "0" to indicate no ' . 'time limit. If there is a time limit, then there will be an indication that this is a timed ' . 'test on the main "Assignments" page. Additionally the student will be sent to a confirmation ' - . 'page beefore they can begin.' + . 'page before they can begin. Note that the actual time a student will have to complete a timed test ' + . 'is the product of this time limit and the accommodation time factor set for the student in the ' + . 'accounts manager.' ) }, time_limit_cap => { @@ -479,65 +490,57 @@ use constant FIELD_PROPERTIES => { ) }, max_attempts => { - name => x('Max Attempts'), - type => 'edit', - size => 6, - override => 'any', - default => '-1', - labels => { - '-1' => x('Unlimited'), - }, + name => x('Max Attempts'), + type => [ 0, undef, 1 ], + size => 6, + override => 'any', + default => '-1', + choices => [qw(-1)], + labels => { '-1' => x('Unlimited'), numeric => x('Limit to') }, help_text => x( - 'You may cap the number of attempts a student can use for the problem. Use -1 to indicate unlimited attempts.' + 'You may cap the number of attempts a student can use for the problem. ' + . 'Select "Unlimited" to allow an unlimited number of attempts.' ) }, showMeAnother => { - name => x('Show Me Another'), - type => 'edit', - size => '6', - override => 'any', - default => '-2', - labels => { - '-1' => x('Never'), - '-2' => x('Course Default'), - }, + name => x('Show Me Another'), + type => [ 0, undef, 1 ], + size => '6', + override => 'any', + default => '-2', + choices => [qw(-2 -1)], + labels => { '-2' => x('Course Default'), '-1' => x('Never'), numeric => x('After number of attempts is') }, help_text => x( 'When a student has more attempts than is specified here they will be able to view another ' - . 'version of this problem. If set to -1 the feature is disabled and if set to -2 ' - . 'the course default is used.' + . 'version of this problem. The "Show Me Another" feature is is disabled if "Never" is selected.' ) }, showHintsAfter => { - name => x('Show Hints After'), - type => 'edit', - size => '6', - override => 'any', - default => '-2', - labels => { - '-2' => x('Course Default'), - '-1' => x('Never'), - }, + name => x('Show Hints'), + type => [ 0, undef, 1 ], + size => '6', + override => 'any', + default => '-2', + choices => [qw(-2 -1)], + labels => { '-2' => x('Course Default'), '-1' => x('Never'), numeric => x('After number of attempts is') }, help_text => x( 'This specifies the number of attempts before hints are shown to students. ' - . 'The value of -2 uses the default from course configuration. ' - . 'The value of -1 disables hints. ' + . 'If "Never" is selected, then hints are disabled. ' . 'Note that this will only have an effect if the problem has a hint.' ), }, prPeriod => { - name => x('Rerandomize After'), - type => 'edit', - size => '6', - override => 'any', - default => '-1', - labels => { - '-1' => x('Course Default'), - '0' => x('Never'), - }, + name => x('Rerandomize'), + type => [ 1, undef, 1 ], + size => '6', + override => 'any', + default => '-1', + choices => [qw(-1 0)], + labels => { '-1' => x('Course Default'), '0' => x('Never'), numeric => x('After number of attempts is') }, help_text => x( 'This specifies the rerandomization period: the number of attempts before a new version of ' - . 'the problem is generated by changing the Seed value. The value of -1 uses the ' - . 'default from course configuration. The value of 0 disables rerandomization.' + . 'the problem is generated by changing the Seed value. ' + . 'Randomization is disabled if "Never" is selected.' ), }, problem_seed => { @@ -561,34 +564,6 @@ use constant FIELD_PROPERTIES => { . 'to 1 to manually award full credit on this problem.' ) }, - attempted => { - name => x('Attempted'), - type => 'hidden', - override => 'none', - choices => [qw(0 1)], - labels => { - 1 => x('Yes'), - 0 => x('No'), - }, - default => '0', - }, - last_answer => { - name => x('Last Answer'), - type => 'hidden', - override => 'none', - }, - num_correct => { - name => x('Correct'), - type => 'hidden', - override => 'none', - default => '0', - }, - num_incorrect => { - name => x('Incorrect'), - type => 'hidden', - override => 'none', - default => '0', - }, hide_hint => { name => x('Hide Hints from Students'), type => 'choose', @@ -605,19 +580,18 @@ use constant FIELD_PROPERTIES => { ) }, att_to_open_children => { - name => x('Attempt Threshold for Children'), - type => 'edit', - size => 6, - override => 'any', - default => '0', - labels => { - '-1' => x('max'), - }, + name => x('Attempt Threshold for Children'), + type => [ 0, undef, 1 ], + size => 6, + override => 'any', + default => '0', + choices => [qw(-1)], + labels => { '-1' => x('No Attempts Remaining'), numeric => x('Number incorrect is') }, help_text => x( 'The child problems for this problem will become visible to the student when they either have more ' . 'incorrect attempts than is specified here, or when they run out of attempts, whichever comes ' - . 'first. Use -1 to indicate that child problems should only be available after a student ' - . 'runs out of attempts.' + . 'first. Select "No Attempts Remaining" to indicate that child problems should only be available ' + . 'after a student runs out of attempts.' ), }, counts_parent_grade => { @@ -638,13 +612,6 @@ use constant FIELD_PROPERTIES => { }, }; -use constant FIELD_PROPERTIES_GWQUIZ => { - max_attempts => { - type => 'hidden', - override => 'any', - } -}; - # Create a table of fields for the given parameters, one row for each db field. # If only the setID is included, it creates a table of set information. # If the problemID is included, it creates a table of problem information. @@ -724,13 +691,7 @@ sub fieldTable ($c, $userID, $setID, $problemID, $globalRecord, $userRecord = un } for my $field (@fieldOrder) { - my %properties; - - if ($isGWset && defined(FIELD_PROPERTIES_GWQUIZ->{$field})) { - %properties = %{ FIELD_PROPERTIES_GWQUIZ->{$field} }; - } else { - %properties = %{ FIELD_PROPERTIES()->{$field} }; - } + my %properties = %{ FIELD_PROPERTIES()->{$field} }; # Don't show fields if that option isn't enabled. if (!$ce->{options}{enableConditionalRelease} @@ -822,9 +783,8 @@ sub fieldHTML ($c, $userID, $setID, $problemID, $globalRecord, $userRecord, $fie my %properties = %{ FIELD_PROPERTIES()->{$field} }; if ($field eq 'problems_per_page') { - if ($c->ce->{test}{maxProblemsPerPage} == 1) { - $properties{override} = 'none'; - } elsif ($c->ce->{test}{maxProblemsPerPage} > 1) { + return '' if $c->ce->{test}{maxProblemsPerPage} == 1; + if ($c->ce->{test}{maxProblemsPerPage} > 1) { my $max = $c->ce->{test}{maxProblemsPerPage}; $properties{type} = [ 1, $max, 1 ]; $properties{help_text} = @@ -841,10 +801,6 @@ sub fieldHTML ($c, $userID, $setID, $problemID, $globalRecord, $userRecord, $fie return '' if $properties{override} eq 'none' && !$forOneUser; return '' if $properties{override} eq 'all' && $forUsers; - my $edit = $properties{type} eq 'edit' && $properties{override} ne 'none'; - my $number = ref($properties{type}) eq 'ARRAY' && $properties{override} ne 'none'; - my $choose = $properties{type} eq 'choose' && $properties{override} ne 'none'; - my ($globalValue, $userValue, $blankField) = (undef, undef, ''); if ($field =~ /:/) { # This allows one "select" to set multiple database fields. @@ -882,106 +838,141 @@ sub fieldHTML ($c, $userID, $setID, $problemID, $globalRecord, $userRecord, $fie # Determine if this is a set record or problem record. my ($recordType, $recordID) = defined $problemID ? ('problem', $problemID) : ('set', $setID); - my %labels = (map { $_ => $c->maketext($properties{labels}{$_}) } keys %{ $properties{labels} }); + my %labels = map { $_ => $c->maketext($properties{labels}{$_}) } keys %{ $properties{labels} // {} }; # This contains either a text input or a select for changing a given database field. my $input = ''; - if ($edit || $number) { - if ($field =~ /_date/) { - $input = $c->tag( - 'div', - class => 'input-group input-group-sm flatpickr', - $c->c( - $c->text_field( - "$recordType.$recordID.$field", - $forUsers ? $userValue : $globalValue, - id => "$recordType.$recordID.${field}_id", - class => 'form-control form-control-sm' - . ($field eq 'open_date' ? ' datepicker-group' : ''), - placeholder => ( - $forUsers && $canOverride ? $c->maketext('Set Default') : $c->maketext('None Specified') - ), - data => { - input => undef, - done_text => $c->maketext('Done'), - today_text => $c->maketext('Today'), - now_text => $c->maketext('Now'), - locale => $c->ce->{language}, - timezone => $c->ce->{siteDefaults}{timezone} - } - ), - $c->tag( - 'a', - class => 'btn btn-secondary btn-sm', - data => { toggle => undef }, - role => 'button', - tabindex => 0, - 'aria-label' => $c->maketext('Pick date and time'), - $c->tag('i', class => 'fas fa-calendar-alt', 'aria-hidden' => 'true', '') - ) - )->join('') - ); - } else { - my $value = $forUsers ? ($labels{$userValue} || $userValue) : ($labels{$globalValue} || $globalValue); - $value = $c->ce->{test}{maxProblemsPerPage} - if ($field eq 'problems_per_page' - && $c->ce->{test}{maxProblemsPerPage} - && ($value == 0 || $value > $c->ce->{test}{maxProblemsPerPage})); - $value = format_set_name_display($value =~ s/\s*,\s*/,/gr) if $field eq 'restricted_release'; - - my @field_args = ( - "$recordType.$recordID.$field", $value, - id => "$recordType.$recordID.${field}_id", - class => 'form-control form-control-sm', - $field eq 'restricted_release' || $field eq 'source_file' ? (dir => 'ltr') : () - ); - if ($field eq 'problem_seed') { - # Insert a randomization button + if ($properties{override} ne 'none') { + if ($properties{type} eq 'edit' || ref($properties{type}) eq 'ARRAY') { + if ($field =~ /_date/) { $input = $c->tag( 'div', - class => 'input-group input-group-sm', - style => 'min-width: 7rem', + class => 'input-group input-group-sm flatpickr', $c->c( - $c->number_field(@field_args, min => 0), + $c->text_field( + "$recordType.$recordID.$field", + $forUsers ? $userValue : $globalValue, + id => "$recordType.$recordID.${field}_id", + class => 'form-control form-control-sm' + . ($field eq 'open_date' ? ' datepicker-group' : ''), + placeholder => ( + $forUsers + && $canOverride ? $c->maketext('Set Default') : $c->maketext('None Specified') + ), + data => { + input => undef, + done_text => $c->maketext('Done'), + today_text => $c->maketext('Today'), + now_text => $c->maketext('Now'), + locale => $c->ce->{language}, + timezone => $c->ce->{siteDefaults}{timezone} + } + ), $c->tag( - 'button', - type => 'button', - class => 'randomize-seed-btn btn btn-sm btn-secondary', - title => 'randomize', - data => { - seed_input => "$recordType.$recordID.problem_seed_id", - status_input => "$recordType.$recordID.status_id" - }, - $c->tag('i', class => 'fa-solid fa-shuffle') + 'a', + class => 'btn btn-secondary btn-sm', + data => { toggle => undef }, + role => 'button', + tabindex => 0, + 'aria-label' => $c->maketext('Pick date and time'), + $c->tag('i', class => 'fas fa-calendar-alt', 'aria-hidden' => 'true', '') ) )->join('') ); - } elsif ($number) { - $input = $c->number_field( - @field_args, - min => ($properties{type}[0] || 0), - max => ($properties{type}[1] || undef), - step => ($properties{type}[2] || 1), - $forUsers && $canOverride ? (placeholder => $c->maketext('Set Default')) : () - ); } else { - $input = $c->text_field(@field_args, - $forUsers && $canOverride ? (placeholder => $c->maketext('Set Default')) : ()); + my $value = $forUsers ? $userValue : $globalValue; + $value = $c->ce->{test}{maxProblemsPerPage} + if ($field eq 'problems_per_page' + && $c->ce->{test}{maxProblemsPerPage} + && ($value == 0 || $value > $c->ce->{test}{maxProblemsPerPage})); + $value = format_set_name_display($value =~ s/\s*,\s*/,/gr) if $field eq 'restricted_release'; + + my @field_args = ( + id => "$recordType.$recordID.${field}_id", + class => 'form-control form-control-sm', + $field eq 'restricted_release' || $field eq 'source_file' ? (dir => 'ltr') : () + ); + if ($field eq 'problem_seed') { + # Insert a randomization button + $input = $c->tag( + 'div', + class => 'input-group input-group-sm', + style => 'min-width: 7rem', + $c->c( + $c->number_field("$recordType.$recordID.$field", $value, @field_args, min => 0), + $c->tag( + 'button', + type => 'button', + class => 'randomize-seed-btn btn btn-sm btn-secondary', + title => 'randomize', + data => { + seed_input => "$recordType.$recordID.problem_seed_id", + status_input => "$recordType.$recordID.status_id" + }, + $c->tag('i', class => 'fa-solid fa-shuffle') + ) + )->join('') + ); + } elsif (ref($properties{type}) eq 'ARRAY') { + if (ref $properties{labels} eq 'HASH') { + $input = $c->tag( + 'div', + class => 'input-group input-group-sm mixed-numeric-select', + style => 'min-width: 7rem', + $c->c( + $c->select_field( + "$recordType.$recordID.$field", + [ + $forUsers && $canOverride ? [ $c->maketext('Set Default') => '' ] : (), + [ + $labels{numeric} => 'numeric', + $value ne '' && !defined $labels{$value} ? (selected => undef) : () + ], + map { [ $labels{$_} => $_, $_ eq $value ? (selected => undef) : () ] } + @{ $properties{choices} } + ], + class => 'form-select form-select-sm' + ), + $c->number_field( + "$recordType.$recordID.$field", defined $labels{$value} ? '' : $value, + @field_args, + min => $properties{type}[0], + $properties{type}[1] ? (max => $properties{type}[1]) : (), + step => $properties{type}[2] || 1, + style => 'max-width: 4rem' + ) + )->join('') + ); + } else { + $input = $c->number_field( + "$recordType.$recordID.$field", $value, + @field_args, + min => $properties{type}[0], + $properties{type}[1] ? (max => $properties{type}[1]) : (), + step => $properties{type}[2] || 1, + $forUsers && $canOverride ? (placeholder => $c->maketext('Set Default')) : (), + ); + } + } else { + $input = $c->text_field("$recordType.$recordID.$field", + $value, @field_args, + $forUsers && $canOverride ? (placeholder => $c->maketext('Set Default')) : ()); + } } + } elsif ($properties{type} eq 'choose') { + my $value = $forUsers ? $userValue : $globalValue; + + $input = $c->select_field( + "$recordType.$recordID.$field", + [ + $forUsers && $userRecord ? [ $c->maketext('Set Default') => '' ] : (), + map { [ $labels{$_} => $_, $_ eq $value ? (selected => undef) : () ] } @{ $properties{choices} } + ], + id => "$recordType.$recordID.${field}_id", + class => 'form-select form-select-sm' + ); } - } elsif ($choose) { - my $value = $forUsers ? $userValue : $globalValue; - - $input = $c->select_field( - "$recordType.$recordID.$field", - [ - $forUsers && $userRecord ? [ $c->maketext('Set Default') => '' ] : (), - map { [ $labels{$_} => $_, $_ eq $value ? (selected => undef) : () ] } @{ $properties{choices} } - ], - id => "$recordType.$recordID.${field}_id", - class => 'form-select form-select-sm' - ); } my $globalDisplayValue = @@ -1342,18 +1333,11 @@ sub initialize ($c) { my $forOneUser = $forUsers == 1; $c->stash->{forOneUser} = $forOneUser; - # If editing a versioned set, it only makes sense edit it for one user. + # If editing a versioned set, it only makes sense to edit it for one user. return if ($editingSetVersion && !$forOneUser); my %properties = %{ FIELD_PROPERTIES() }; - # Invert the labels hashes. - my %undoLabels; - for my $key (keys %properties) { - %{ $undoLabels{$key} } = - map { $c->maketext($properties{$key}{labels}{$_}) => $_ } keys %{ $properties{$key}{labels} }; - } - my $error = 0; if ($c->param('submit_changes')) { my @names = ('open_date', 'due_date', 'answer_date', 'reduced_scoring_date'); @@ -1405,7 +1389,6 @@ sub initialize ($c) { $c->addbadmessage($c->maketext('No changes were saved!')) if $error; if ($c->param('submit_changes') && !$error) { - my $oldAssignmentType = $setRecord->assignment_type(); # Save general set information (including headers) @@ -1428,9 +1411,9 @@ sub initialize ($c) { for my $field (@{ SET_FIELDS() }) { next unless canChange($forUsers, $field); - my $param = $c->param("set.$setID.$field"); + my @paramValues = $c->param("set.$setID.$field"); + my $param = @paramValues > 1 && $paramValues[0] eq 'numeric' ? $paramValues[1] : $paramValues[0]; if ($param && $param ne '') { - $param = $undoLabels{$field}{$param} if defined $undoLabels{$field}{$param}; $param = $param * $properties{$field}->{convertby} if $properties{$field}{convertby}; # Special case: Does field fill in multiple values? @@ -1502,11 +1485,10 @@ sub initialize ($c) { foreach my $field (@{ SET_FIELDS() }) { next unless canChange($forUsers, $field); - my $param = $c->param("set.$setID.$field"); - $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" - unless defined $param && $param ne ""; - my $unlabel = $undoLabels{$field}->{$param}; - $param = $unlabel if defined $unlabel; + my @paramValues = $c->param("set.$setID.$field"); + my $param = @paramValues > 1 && $paramValues[0] eq 'numeric' ? $paramValues[1] : $paramValues[0]; + $param = defined $properties{$field}{default} ? $properties{$field}{default} : '' + unless defined $param && $param ne ''; if ($field =~ /restricted_release/ && $param) { $param = format_set_name_internal($param =~ s/\s*,\s*/,/gr); $c->check_sets($db, $param); @@ -1655,10 +1637,10 @@ sub initialize ($c) { for my $field (@{ PROBLEM_FIELDS() }) { next unless canChange($forUsers, $field); - my $param = $c->param("problem.$problemID.$field"); + my @paramValues = $c->param("problem.$problemID.$field"); + my $param = + @paramValues > 1 && $paramValues[0] eq 'numeric' ? $paramValues[1] : $paramValues[0]; if (defined $param && $param ne '') { - $param = $undoLabels{$field}{$param} if defined $undoLabels{$field}{$param}; - # Protect exploits with source_file if ($field eq 'source_file') { if ($param =~ /\.\./ || $param =~ /^\//) { @@ -1682,11 +1664,12 @@ sub initialize ($c) { for my $field (@{ USER_PROBLEM_FIELDS() }) { next unless canChange($forUsers, $field); - my $param = $c->param("problem.$problemID.$field"); - $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" - unless defined $param && $param ne ""; - my $unlabel = $undoLabels{$field}->{$param}; - $param = $unlabel if defined $unlabel; + my @paramValues = $c->param("problem.$problemID.$field"); + my $param = + @paramValues > 1 && $paramValues[0] eq 'numeric' ? $paramValues[1] : $paramValues[0]; + $param = defined $properties{$field}{default} ? $properties{$field}{default} : '' + unless defined $param && $param ne ''; + # Protect exploits with source_file if ($field eq 'source_file') { if ($param =~ /\.\./ || $param =~ /^\//) { @@ -1719,11 +1702,10 @@ sub initialize ($c) { foreach my $field (@{ PROBLEM_FIELDS() }) { next unless canChange($forUsers, $field); - my $param = $c->param("problem.$problemID.$field"); - $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" - unless defined $param && $param ne ""; - my $unlabel = $undoLabels{$field}->{$param}; - $param = $unlabel if defined $unlabel; + my @paramValues = $c->param("problem.$problemID.$field"); + my $param = @paramValues > 1 && $paramValues[0] eq 'numeric' ? $paramValues[1] : $paramValues[0]; + $param = defined $properties{$field}{default} ? $properties{$field}{default} : '' + unless defined $param && $param ne ''; # Protect exploits with source_file if ($field eq 'source_file') { @@ -1759,11 +1741,11 @@ sub initialize ($c) { foreach my $field (keys %useful) { next unless canChange($forUsers, $field); - my $param = $c->param("problem.$problemID.$field"); - $param = defined $properties{$field}->{default} ? $properties{$field}->{default} : "" - unless defined $param && $param ne ""; - my $unlabel = $undoLabels{$field}->{$param}; - $param = $unlabel if defined $unlabel; + my @paramValues = $c->param("problem.$problemID.$field"); + my $param = + @paramValues > 1 && $paramValues[0] eq 'numeric' ? $paramValues[1] : $paramValues[0]; + $param = defined $properties{$field}{default} ? $properties{$field}{default} : '' + unless defined $param && $param ne ''; $changed ||= changed($record->$field, $param); $record->$field($param); } @@ -2048,13 +2030,11 @@ sub initialize ($c) { } # Helper method for checking if two values are different. -# The return values will usually be thrown away, but they could be useful for debugging. sub changed ($first, $second) { - return "def/undef" if defined $first && !defined $second; - return "undef/def" if !defined $first && defined $second; - return "" if !defined $first && !defined $second; - return "ne" if $first ne $second; - return ""; + return 0 if !defined $first && !defined $second; + return 1 if !defined $first || !defined $second; + return 1 if $first ne $second; + return 0; } # Helper method that determines for how many users at a time a field can be changed. @@ -2071,7 +2051,7 @@ sub canChange ($forUsers, $field) { return 1 if $howManyCan eq "any"; return 1 if $howManyCan eq "one" && $forOneUser; return 1 if $howManyCan eq "all" && !$forUsers; - return 0; # FIXME: maybe it should default to 1? + return 0; } # Helper method that determines if a file is valid and returns a pretty error message. diff --git a/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm b/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm index 6a65b99ce0..5e33ee8369 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm @@ -643,17 +643,6 @@ sub save_edit_handler ($c) { } } - # make sure the dates are not more than 10 years in the future - my $curr_time = time; - my $seconds_per_year = 31_556_926; - my $cutoff = $curr_time + $seconds_per_year * 10; - return (0, $c->maketext('Error: Open date cannot be more than 10 years from now in set [_1].', $setID)) - if $Set->open_date > $cutoff; - return (0, $c->maketext('Error: Close date cannot be more than 10 years from now in set [_1].', $setID)) - if $Set->due_date > $cutoff; - return (0, $c->maketext('Error: Answer date cannot be more than 10 years from now in set [_1].', $setID)) - if $Set->answer_date > $cutoff; - # Check that the open, due and answer dates are in increasing order. # Bail if this is not correct. if ($Set->open_date > $Set->due_date) { diff --git a/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm b/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm index 63ef67a7bb..33b86fb40b 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm @@ -22,30 +22,7 @@ sub initialize ($c) { # Check permissions return unless $c->authz->hasPermissions($user, 'access_instructor_tools'); - # Cache a list of all users except set level proctors and practice users, and restrict to the sections or - # recitations that are allowed for the user if such restrictions are defined. This list is sorted by last_name, - # then first_name, then user_id. This is used in multiple places in this module, and is guaranteed to be used at - # least once. So it is done here to prevent extra database access. - $c->{student_records} = [ - $db->getUsersWhere( - { - user_id => [ -and => { not_like => 'set_id:%' }, { not_like => "$ce->{practiceUserPrefix}\%" } ], - $ce->{viewable_sections}{$user} || $ce->{viewable_recitations}{$user} - ? ( - -or => [ - $ce->{viewable_sections}{$user} ? (section => $ce->{viewable_sections}{$user}) : (), - $ce->{viewable_recitations}{$user} ? (recitation => $ce->{viewable_recitations}{$user}) : () - ] - ) - : () - }, - [qw/last_name first_name user_id/] - ) - ]; - - if ($c->current_route eq 'instructor_user_statistics') { - $c->{studentID} = $c->stash('userID'); - } elsif ($c->current_route =~ /^instructor_(set|problem)_statistics$/) { + if ($c->current_route =~ /^instructor_(set|problem)_statistics$/) { my $setRecord = $db->getGlobalSet($c->stash('setID')); return unless $setRecord; $c->{setRecord} = $setRecord; @@ -57,6 +34,30 @@ sub initialize ($c) { return unless $problemRecord; $c->{problemRecord} = $problemRecord; } + + # Cache a list of all users except set level proctors and practice users, and restrict to the sections + # or recitations that are allowed for the user if such restrictions are defined. This list is sorted by + # last_name, then first_name, then user_id. This is used in multiple places in this module, and is used + # on every page except the main page, so it is done here to prevent extra database access. + $c->{student_records} = [ + $db->getUsersWhere( + { + user_id => + [ -and => { not_like => 'set_id:%' }, { not_like => "$ce->{practiceUserPrefix}\%" } ], + $ce->{viewable_sections}{$user} || $ce->{viewable_recitations}{$user} + ? ( + -or => [ + $ce->{viewable_sections}{$user} ? (section => $ce->{viewable_sections}{$user}) : (), + $ce->{viewable_recitations}{$user} + ? (recitation => $ce->{viewable_recitations}{$user}) + : () + ] + ) + : () + }, + [qw/last_name first_name user_id/] + ) + ]; } return; @@ -67,9 +68,7 @@ sub page_title ($c) { my $setID = $c->stash('setID') || ''; - if ($c->current_route eq 'instructor_user_statistics') { - return $c->maketext('Statistics for student [_1]', $c->{studentID}); - } elsif ($c->current_route eq 'instructor_set_statistics') { + if ($c->current_route eq 'instructor_set_statistics') { return $c->maketext('Statistics for [_1]', $c->tag('span', dir => 'ltr', format_set_name_display($setID))); } elsif ($c->current_route eq 'instructor_problem_statistics') { return $c->maketext( @@ -79,12 +78,11 @@ sub page_title ($c) { ); } - return $c->maketext('Statistics'); + return $c->maketext('Set Statistics'); } sub siblings ($c) { - # Stats and StudentProgress share this template. - return $c->include('ContentGenerator/Instructor/Stats/siblings', header => $c->maketext('Statistics')); + return $c->include('ContentGenerator/Instructor/Stats/siblings'); } # Apply the currently selected filter to the student records, and return a reference to the @@ -567,6 +565,7 @@ sub build_bar_chart ($c, $data, %options) { viewbox => '-2 -2 ' . ($imageWidth + 3) . ' ' . ($imageHeight + 3), 'aria-labelledby' => "bar_graph_title_$id", role => 'img', + class => 'stats-image', -nocredits => 1 ); diff --git a/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm b/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm index 6acc9cc579..0871948c44 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm @@ -68,8 +68,7 @@ sub page_title ($c) { } sub siblings ($c) { - # Stats and StudentProgress share this template. - return $c->include('ContentGenerator/Instructor/Stats/siblings', header => $c->maketext('Student Progress')); + return $c->include('ContentGenerator/Instructor/StudentProgress/siblings'); } # Display student progress table diff --git a/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm b/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm index a3eff9d7b6..ca6db7ed6b 100644 --- a/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm +++ b/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm @@ -93,24 +93,47 @@ use constant SORT_SUBS => { }; use constant FIELDS => [ - 'user_id', 'first_name', 'last_name', 'email_address', 'student_id', 'status', - 'section', 'recitation', 'comment', 'permission', 'password' + 'user_id', 'first_name', 'last_name', 'email_address', + 'student_id', 'status', 'accommodation_time_factor', 'section', + 'recitation', 'comment', 'permission', 'password' ]; -# Note that only the editable fields need a type (i.e. all but user_id), -# and only the text fields need a size. +# Note that only the editable fields need a type (i.e. all but user_id). +# The fields of type text or number may also include optional attributes for the HTML input. +# Any field may also contain a perlValidate method that will be called to validate user input. If provided, it should be +# a subroutine that takes the parameter value as its only argument, and returns a translatable error string if the +# parameter value is not valid for the field, and 0 otherwise. use constant FIELD_PROPERTIES => { - user_id => { name => x('Login Name') }, - first_name => { name => x('First Name'), type => 'text', size => 10 }, - last_name => { name => x('Last Name'), type => 'text', size => 10 }, - email_address => { name => x('Email Address'), type => 'text', size => 20 }, - student_id => { name => x('Student ID'), type => 'text', size => 11 }, - status => { name => x('Enrollment Status'), type => 'status' }, - section => { name => x('Section'), type => 'text', size => 3 }, - recitation => { name => x('Recitation'), type => 'text', size => 3 }, - comment => { name => x('Comment'), type => 'text', size => 20 }, - permission => { name => x('Permission Level'), type => 'permission' }, - password => { name => x('Password'), type => 'password' }, + user_id => { name => x('Login Name') }, + first_name => { name => x('First Name'), type => 'text', attributes => { size => 10 } }, + last_name => { name => x('Last Name'), type => 'text', attributes => { size => 10 } }, + email_address => { name => x('Email Address'), type => 'text', attributes => { size => 20 } }, + student_id => { name => x('Student ID'), type => 'text', attributes => { size => 11 } }, + status => { name => x('Enrollment Status'), type => 'status' }, + accommodation_time_factor => { + name => x('Accommodation Time Factor'), + type => 'number', + attributes => { + size => 5, + min => 1, + step => 'any', + title => 'Enter a decimal number that is greater than or equal to 1.' + }, + perlValidate => sub { + my $value = shift; + return $value !~ /^(\d+(\.\d*)?|\.\d+)$/ || $value <= 0 + ? (x( + 'Accomodation time factor for [_1] unchanged. ' + . 'A value was given that is not a decimal number or is not greater than or equal to 1.' + ))[0] + : 0; + } + }, + section => { name => x('Section'), type => 'text', attributes => { size => 3 } }, + recitation => { name => x('Recitation'), type => 'text', attributes => { size => 3 } }, + comment => { name => x('Comment'), type => 'text', attributes => { size => 20 } }, + permission => { name => x('Permission Level'), type => 'permission' }, + password => { name => x('Password'), type => 'password' }, }; sub pre_header_initialize ($c) { @@ -517,7 +540,14 @@ sub save_edit_handler ($c) { for my $field ($User->NONKEYFIELDS()) { my $newValue = $c->param("user.$userID.$field"); - $User->$field($newValue) if defined $newValue; + next unless defined $newValue; + if (ref(FIELD_PROPERTIES()->{$field}{perlValidate}) eq 'CODE' + && (my $error = FIELD_PROPERTIES()->{$field}{perlValidate}->($newValue))) + { + $c->addbadmessage($c->maketext($error, $userID)); + next; + } + $User->$field($newValue); } $db->putUser($User); diff --git a/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm b/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm index 78139db160..75b58e5d6c 100644 --- a/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm +++ b/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm @@ -1,11 +1,13 @@ package WeBWorK::ContentGenerator::LTIAdvantage; -use Mojo::Base 'WeBWorK::ContentGenerator', -signatures; +use Mojo::Base 'WeBWorK::ContentGenerator', -signatures, -async_await; use Mojo::UserAgent; +use Mojo::URL; use Mojo::JSON qw(decode_json); use Crypt::JWT qw(decode_jwt encode_jwt); use Math::Random::Secure qw(irand); use Digest::SHA qw(sha256_hex); +use Mojo::File qw(tempfile); use WeBWorK::Debug qw(debug); use WeBWorK::Authen::LTIAdvantage::SubmitGrade; @@ -175,9 +177,11 @@ sub launch ($c) { return $c->redirect_to($c->systemLink( $c->url_for($c->stash->{LTILaunchRedirect}), - $c->stash->{isContentSelection} - ? ( - params => { + params => { + %{ Mojo::URL->new($c->stash->{LTILaunchRedirect})->query->to_hash }, + $c->stash->{isContentSelection} + ? ( + courseID => $c->stash->{courseID}, initial_request => 1, accept_multiple => @@ -191,9 +195,9 @@ sub launch ($c) { ? (data => $c->stash->{lti_jwt_claims} {'https://purl.imsglobal.org/spec/lti-dl/claim/deep_linking_settings'}{data}) : () - } - ) - : () + ) + : () + } )); } @@ -425,4 +429,120 @@ sub purge_expired_lti_data ($c, $ce, $db) { return; } +async sub registration ($c) { + return $c->render(json => { error => 'invalid configuration request' }, status => 400) + unless defined $c->req->param('openid_configuration') && defined $c->req->param('registration_token'); + + # If we want to allow options in the configuration such as whether grade passback is enabled or to allow the LMS + # administrator to choose a tool name, then this should render a form that the LMS will be presented in an iframe + # allowing the LMS administrator to select the options. When that form is submitted, then the code below should be + # executed taking those options into consideration. However, at this point this is a simplistic approach that will + # work in most cases. + + $c->render_later; + + my $configurationResult = (await Mojo::UserAgent->new->get_p($c->req->param('openid_configuration')))->result; + return $c->render(json => { error => 'unabled to obtain openid configuration' }, status => 400) + unless $configurationResult->is_success; + my $lmsConfiguration = $configurationResult->json; + + return $c->render(json => { error => 'invalid openid configuration received' }, status => 400) + unless defined $lmsConfiguration->{registration_endpoint} + && defined $lmsConfiguration->{issuer} + && defined $lmsConfiguration->{jwks_uri} + && defined $lmsConfiguration->{token_endpoint} + && defined $lmsConfiguration->{authorization_endpoint} + && defined $lmsConfiguration->{'https://purl.imsglobal.org/spec/lti-platform-configuration'} + {product_family_code}; + + # FIXME: This should also probably check that the token_endpoint_auth_method is private_key_jwt, the + # id_token_signing_alg_values_supported is RS256, and that the scopes_supported is an array and contains all of the + # scopes listed below. There are perhaps some other configuration values that should be checked as well. However, + # most of the time these are all going to be fine. + + my $rootURL = $c->url_for('root')->to_abs; + + my $registrationResult = (await Mojo::UserAgent->new->post_p( + $lmsConfiguration->{registration_endpoint}, + { + Authorization => 'Bearer ' . $c->req->param('registration_token'), + 'Content-Type' => 'application/json' + }, + json => { + application_type => 'web', + response_types => ['id_token'], + grant_types => [ 'implicit', 'client_credentials' ], + client_name => 'WeBWorK at ' . $rootURL->host_port, + client_uri => $rootURL->to_string, + initiate_login_uri => $c->url_for('ltiadvantage_login')->to_abs->to_string, + redirect_uris => [ $c->url_for('ltiadvantage_launch')->to_abs->to_string ], + jwks_uri => $c->url_for('ltiadvantage_keys')->to_abs->to_string, + token_endpoint_auth_method => 'private_key_jwt', + scope => join(' ', + 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem', + 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly', + 'https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly', + 'https://purl.imsglobal.org/spec/lti-ags/scope/score'), + 'https://purl.imsglobal.org/spec/lti-tool-configuration' => { + domain => $rootURL->host_port, + target_link_uri => $rootURL->to_string, + claims => [ 'iss', 'sub', 'name', 'given_name', 'family_name', 'email' ], + messages => [ { + type => 'LtiDeepLinkingRequest', + target_link_uri => $c->url_for('ltiadvantage_content_selection')->to_abs->to_string, + # Placements are specific to the LMS. The following placements are needed for Canvas, and Moodle + # completely ignores this parameter. Does D2L need any? What about Blackboard? + placements => [ 'assignment_selection', 'course_assignments_menu' ] + } ] + } + } + ))->result; + unless ($registrationResult->is_success) { + $c->log->error('Invalid regististration response: ' . $registrationResult->message); + return $c->render(json => { error => 'invalid registration response' }, status => 400); + } + return $c->render(json => { error => 'invalid registration received' }, status => 400) + unless defined $registrationResult->json->{client_id}; + + my $configuration = <<~ "END_CONFIG"; + \$LTI{v1p3}{PlatformID} = '$lmsConfiguration->{issuer}'; + \$LTI{v1p3}{ClientID} = '${\($registrationResult->json->{client_id})}'; + \$LTI{v1p3}{DeploymentID} = '${ + \($registrationResult->json->{'https://purl.imsglobal.org/spec/lti-tool-configuration'}{deployment_id} + // 'obtain from LMS administrator') + }'; + \$LTI{v1p3}{PublicKeysetURL} = '$lmsConfiguration->{jwks_uri}'; + \$LTI{v1p3}{AccessTokenURL} = '$lmsConfiguration->{token_endpoint}'; + \$LTI{v1p3}{AccessTokenAUD} = '${ + \($lmsConfiguration->{authorization_server} + // $lmsConfiguration->{token_endpoint}) + }'; + \$LTI{v1p3}{AuthReqURL} = '$lmsConfiguration->{authorization_endpoint}'; + END_CONFIG + + my $registrationDir = Mojo::File->new($c->ce->{webworkDirs}{DATA})->child('LTIRegistrationRequests'); + if (!-d $registrationDir) { + eval { $registrationDir->make_path }; + if ($@) { + $c->log->error("Failed to create directory for saving LTI registrations: $@"); + return $c->render(json => { error => 'internal server error' }, status => 400); + } + } + + my $registrationFile = tempfile( + TEMPLATE => + $lmsConfiguration->{'https://purl.imsglobal.org/spec/lti-platform-configuration'}{product_family_code} + . '-XXXX', + DIR => $registrationDir, + SUFFIX => '.conf', + UNLINK => 0 + ); + $registrationFile->spew($configuration, 'UTF-8'); + + # This tells the LMS that registration is complete and it can close its dialog. + return $c->render(data => ''); +} + 1; diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index e2ef7bd20a..ac08c1ff0e 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -7,7 +7,6 @@ WeBWorK::ContentGenerator::Problem - Allow a student to interact with a problem. =cut -use WeBWorK::HTML::SingleProblemGrader; use WeBWorK::Debug; use WeBWorK::Utils qw(decodeAnswers wwRound); use WeBWorK::Utils::DateTime qw(before between after); @@ -23,6 +22,8 @@ use WeBWorK::AchievementEvaluator qw(checkForAchievements); use WeBWorK::DB::Utils qw(global2user fake_set fake_problem); use WeBWorK::Localize; use WeBWorK::AchievementEvaluator; +use WeBWorK::HTML::SingleProblemGrader; +use WeBWorK::HTML::StudentNav qw(studentNav); # GET/POST Parameters for this module # @@ -431,20 +432,17 @@ async sub pre_header_initialize ($c) { Count => $problem->{showMeAnotherCount}, }; - # Unset the showProblemGrader parameter if the "Hide Problem Grader" button was clicked. - $c->param(showProblemGrader => undef) if $c->param('hideProblemGrader'); - # Permissions # What does the user want to do? my %want = ( showOldAnswers => $user->showOldAnswers ne '' ? $user->showOldAnswers : $ce->{pg}{options}{showOldAnswers}, showCorrectAnswers => 1, - showProblemGrader => $c->param('showProblemGrader') || 0, - showAnsGroupInfo => $c->param('showAnsGroupInfo') || $ce->{pg}{options}{showAnsGroupInfo}, - showAnsHashInfo => $c->param('showAnsHashInfo') || $ce->{pg}{options}{showAnsHashInfo}, - showPGInfo => $c->param('showPGInfo') || $ce->{pg}{options}{showPGInfo}, - showResourceInfo => $c->param('showResourceInfo') || $ce->{pg}{options}{showResourceInfo}, + showProblemGrader => $userID ne $effectiveUserID, + showAnsGroupInfo => $c->param('showAnsGroupInfo') || $ce->{pg}{options}{showAnsGroupInfo}, + showAnsHashInfo => $c->param('showAnsHashInfo') || $ce->{pg}{options}{showAnsHashInfo}, + showPGInfo => $c->param('showPGInfo') || $ce->{pg}{options}{showPGInfo}, + showResourceInfo => $c->param('showResourceInfo') || $ce->{pg}{options}{showResourceInfo}, showHints => 1, showSolutions => 1, useMathView => $user->useMathView ne '' ? $user->useMathView : $ce->{pg}{options}{useMathView}, @@ -531,18 +529,16 @@ async sub pre_header_initialize ($c) { # requiring another answer submission. my $showReturningFeedback = 0; - # Sticky answers - if (!($c->{submitAnswers} || $previewAnswers || $checkAnswers) && $will{showOldAnswers}) { + # Reinsert sticky answers. Do this only if new answers are NOT being submitted, + # and a new problem version is NOT being opened. + if (!($prEnabled && !$problem->{prCount}) + && !($c->{submitAnswers} || $previewAnswers || $checkAnswers) + && $will{showOldAnswers}) + { my %oldAnswers = decodeAnswers($problem->last_answer); - # Do this only if new answers are NOT being submitted - if ($prEnabled && !$problem->{prCount}) { - # Clear answers if this is a new problem version - delete $formFields->{$_} for keys %oldAnswers; - } else { - $formFields->{$_} = $oldAnswers{$_} for (keys %oldAnswers); - $showReturningFeedback = 1 - if $ce->{pg}{options}{automaticAnswerFeedback} && $problem->num_correct + $problem->num_incorrect > 0; - } + $formFields->{$_} = $oldAnswers{$_} for (keys %oldAnswers); + $showReturningFeedback = 1 + if $ce->{pg}{options}{automaticAnswerFeedback} && $problem->num_correct + $problem->num_incorrect > 0; } my $showOnlyCorrectAnswers = $c->param('showCorrectAnswers') && $will{showCorrectAnswers}; @@ -555,7 +551,9 @@ async sub pre_header_initialize ($c) { $c->{set}, $problem, $c->{set}->psvn, - $formFields, + $prEnabled + && !$problem->{prCount} + && !($c->{submitAnswers} || $previewAnswers || $checkAnswers || $showOnlyCorrectAnswers) ? {} : $formFields, { displayMode => $displayMode, showHints => $will{showHints}, @@ -581,22 +579,21 @@ async sub pre_header_initialize ($c) { && after($c->{set}->answer_date, $c->submitTime)), showMessages => !$showOnlyCorrectAnswers, showCorrectAnswers => ( - $will{showProblemGrader} || ($c->{submitAnswers} && $c->{showCorrectOnRandomize}) ? 2 + $c->{submitAnswers} && $c->{showCorrectOnRandomize} ? 2 : !$c->{previewAnswers} && after($c->{set}->answer_date, $c->submitTime) ? ($ce->{pg}{options}{correctRevealBtnAlways} ? 1 : 2) - : !$c->{previewAnswers} && $will{showCorrectAnswers} ? 1 + : $will{showProblemGrader} || (!$c->{previewAnswers} && $will{showCorrectAnswers}) ? 1 : 0 ), debuggingOptions => getTranslatorDebuggingOptions($authz, $userID), - $can{checkAnswers} - && defined $formFields->{problem_data} ? (problemData => $formFields->{problem_data}) : () + $prEnabled && !$problem->{prCount} + ? (problemData => '{}') + : ($can{checkAnswers} && defined $formFields->{problem_data}) + ? (problemData => $formFields->{problem_data}) + : () } ); - # Warnings in the renderPG subprocess will not be caught by the global warning handler of this process. - # So rewarn them and let the global warning handler take care of it. - warn $pg->{warnings} if $pg->{warnings}; - debug('end pg processing'); $pg->{body_text} .= $c->hidden_field( @@ -608,20 +605,6 @@ async sub pre_header_initialize ($c) { $can{showHints} &&= $pg->{flags}{hintExists}; $can{showSolutions} &&= $pg->{flags}{solutionExists}; - # Record errors - $c->{pgdebug} = $pg->{debug_messages} if ref $pg->{debug_messages} eq 'ARRAY'; - $c->{pgwarning} = $pg->{warning_messages} if ref $pg->{warning_messages} eq 'ARRAY'; - $c->{pginternalerrors} = $pg->{internal_debug_messages} if ref $pg->{internal_debug_messages} eq 'ARRAY'; - # $c->{pgerrors} is defined if any of the above are defined, and is nonzero if any are non-empty. - $c->{pgerrors} = @{ $c->{pgdebug} // [] } || @{ $c->{pgwarning} // [] } || @{ $c->{pginternalerrors} // [] } - if defined $c->{pgdebug} || defined $c->{pgwarning} || defined $c->{pginternalerrors}; - - # If $c->{pgerrors} is not defined, then the PG messages arrays were not defined, - # which means $pg->{pgcore} was not defined and the translator died. - warn 'Processing of this PG problem was not completed. Probably because of a syntax error. ' - . 'The translator died prematurely and no PG warning messages were transmitted.' - unless defined $c->{pgerrors}; - # Store fields $c->{want} = \%want; $c->{can} = \%can; @@ -634,53 +617,6 @@ async sub pre_header_initialize ($c) { return; } -sub warnings ($c) { - my $output = $c->c; - - # Display warning messages - if (!defined $c->{pgerrors}) { - push( - @$output, - $c->tag( - 'div', - $c->c( - $c->tag('h3', style => 'color:red;', $c->maketext('PG question failed to render')), - $c->tag('p', $c->maketext('Unable to obtain error messages from within the PG question.')) - )->join('') - ) - ); - } elsif ($c->{pgerrors} > 0) { - my @pgdebug = @{ $c->{pgdebug} // [] }; - my @pgwarning = @{ $c->{pgwarning} // [] }; - my @pginternalerrors = @{ $c->{pginternalerrors} // [] }; - push( - @$output, - $c->tag( - 'div', - $c->c( - $c->tag('h2', $c->maketext('PG question processing error messages')), - @pgdebug ? $c->c( - $c->tag('h3', $c->maketext('PG debug messages')), - $c->tag('p', $c->c(@pgdebug)->join($c->tag('br'))) - )->join('') : '', - @pgwarning ? $c->c( - $c->tag('h3', $c->maketext('PG warning messages')), - $c->tag('p', $c->c(@pgwarning)->join($c->tag('br'))) - )->join('') : '', - @pginternalerrors ? $c->c( - $c->tag('h3', $c->maketext('PG internal errors')), - $c->tag('p', $c->c(@pginternalerrors)->join($c->tag('br'))) - )->join('') : '' - )->join('') - ) - ); - } - - push(@$output, $c->SUPER::warnings()); - - return $output->join(''); -} - sub head ($c) { return '' if ($c->{invalidSet}); return $c->{pg}{head_text} if $c->{pg}{head_text}; @@ -722,9 +658,6 @@ sub siblings ($c) { my @items; - # Keep the grader open when linking to problems if it is already open. - my %problemGraderLink = $c->{will}{showProblemGrader} ? (params => { showProblemGrader => 1 }) : (); - for my $problemID (@problemIDs) { if ($isJitarSet && !$authz->hasPermissions($eUserID, 'view_unopened_sets') @@ -795,7 +728,7 @@ sub siblings ($c) { @items, $c->tag( 'a', - $active ? () : (href => $c->systemLink($problemPage, %problemGraderLink)), + $active ? () : (href => $c->systemLink($problemPage)), class => $class, $c->b($c->maketext('Problem [_1]', join('.', @seq)) . $status_symbol) ) @@ -806,7 +739,7 @@ sub siblings ($c) { @items, $c->tag( 'a', - $active ? () : (href => $c->systemLink($problemPage, %problemGraderLink)), + $active ? () : (href => $c->systemLink($problemPage)), class => 'nav-link' . ($active ? ' active' : ''), $c->b($c->maketext('Problem [_1]', $problemID) . $status_symbol) ) @@ -842,74 +775,6 @@ sub nav ($c, $args) { my $mergedSet = $db->getMergedSet($eUserID, $setID); return '' if !$mergedSet; - # Set up a student navigation for those that have permission to act as a student. - my $userNav = ''; - if ($authz->hasPermissions($userID, 'become_student') && $eUserID ne $userID) { - # Find all users for this set (except the current user) sorted by last_name, then first_name, then user_id. - my @allUserRecords = $db->getUsersWhere( - { - user_id => [ - map { $_->[0] } $db->listUserSetsWhere({ set_id => $setID, user_id => { not_like => $userID } }) - ] - }, - [qw/last_name first_name user_id/] - ); - - my $filter = $c->param('studentNavFilter'); - - # Find the previous, current, and next users, and format the student names for display. - # Also create a hash of sections and recitations if there are any for the course. - my @userRecords; - my $currentUserIndex = 0; - my %filters; - for (@allUserRecords) { - # Add to the sections and recitations if defined. Also store the first user found in that section or - # recitation. This user will be switched to when the filter is selected. - my $section = $_->section; - $filters{"section:$section"} = [ $c->maketext('Filter by section [_1]', $section), $_->user_id ] - if $section && !$filters{"section:$section"}; - my $recitation = $_->recitation; - $filters{"recitation:$recitation"} = [ $c->maketext('Filter by recitation [_1]', $recitation), $_->user_id ] - if $recitation && !$filters{"recitation:$recitation"}; - - # Only keep this user if it satisfies the selected filter if a filter was selected. - next - unless !$filter - || ($filter =~ /^section:(.*)$/ && $_->section eq $1) - || ($filter =~ /^recitation:(.*)$/ && $_->recitation eq $1); - - my $addRecord = $_; - $currentUserIndex = @userRecords if $addRecord->user_id eq $eUserID; - push @userRecords, $addRecord; - - # Construct a display name. - $addRecord->{displayName} = - ($addRecord->last_name || $addRecord->first_name - ? $addRecord->last_name . ', ' . $addRecord->first_name - : $addRecord->user_id); - } - my $prevUser = $currentUserIndex > 0 ? $userRecords[ $currentUserIndex - 1 ] : 0; - my $nextUser = $currentUserIndex < $#userRecords ? $userRecords[ $currentUserIndex + 1 ] : 0; - - # Mark the current user. - $userRecords[$currentUserIndex]{currentUser} = 1; - - my $problemPage = $c->url_for('problem_detail', setID => $setID, problemID => $problemID); - - # Set up the student nav. - $userNav = $c->include( - 'ContentGenerator/Problem/student_nav', - eUserID => $eUserID, - problemPage => $problemPage, - userRecords => \@userRecords, - currentUserIndex => $currentUserIndex, - prevUser => $prevUser, - nextUser => $nextUser, - filter => $filter, - filters => \%filters - ); - } - my $isJitarSet = $mergedSet->assignment_type eq 'jitar'; my ($prevID, $nextID); @@ -970,10 +835,9 @@ sub nav ($c, $args) { } my %tail; - $tail{displayMode} = $c->{displayMode} if defined $c->{displayMode}; - $tail{showOldAnswers} = 1 if $c->{will}{showOldAnswers}; - $tail{showProblemGrader} = 1 if $c->{will}{showProblemGrader}; - $tail{studentNavFilter} = $c->param('studentNavFilter') if $c->param('studentNavFilter'); + $tail{displayMode} = $c->{displayMode} if defined $c->{displayMode}; + $tail{showOldAnswers} = 1 if $c->{will}{showOldAnswers}; + $tail{studentNavFilter} = $c->param('studentNavFilter') if $c->param('studentNavFilter'); return $c->tag( 'div', @@ -981,7 +845,7 @@ sub nav ($c, $args) { role => 'navigation', 'aria-label' => 'problem navigation', $c->c($c->tag('div', class => 'd-flex submit-buttons-container', $c->navMacro($args, \%tail, @links)), - $userNav)->join('') + studentNav($c, $setID))->join('') ); } @@ -1113,7 +977,7 @@ sub output_problem_body ($c) { } else { # For students render the body text of the problem with a message about error details. return $c->c( - $c->tag('div', id => 'output_problem_body', $c->b($c->{pg}{body_text})), + $c->tag('div', $c->b($c->{pg}{body_text})), $c->include( 'ContentGenerator/Base/error_output', error => $c->{pg}{errors}, @@ -1123,7 +987,14 @@ sub output_problem_body ($c) { } } - return $c->tag('div', id => 'output_problem_body', $c->b($c->{pg}{body_text})); + return $c->tag( + 'div', + id => 'output_problem_body', + class => 'text-dark', + style => 'color-scheme: light', + data => { bs_theme => 'light' }, + $c->b($c->{pg}{body_text}) + ); } # Output messages about the problem @@ -1133,10 +1004,8 @@ sub output_message ($c) { # Output the problem grader if the user has permissions to grade problems sub output_grader ($c) { - if ($c->{will}{showProblemGrader}) { - return WeBWorK::HTML::SingleProblemGrader->new($c, $c->{pg}, $c->{problem})->insertGrader; - } - + return WeBWorK::HTML::SingleProblemGrader->new($c, $c->{pg}, $c->{problem}, $c->{set})->insertGrader + if $c->{will}{showProblemGrader}; return ''; } @@ -1444,7 +1313,7 @@ sub output_summary ($c) { # Attempt summary if ($c->{submitAnswers}) { push(@$output, $c->attemptResults($pg)); - } elsif ($will{checkAnswers} || $c->{will}{showProblemGrader}) { + } elsif ($will{checkAnswers}) { push( @$output, $c->tag( @@ -1480,7 +1349,7 @@ sub output_summary ($c) { 'div', class => 'alert alert-danger d-inline-block mb-2 p-1', $c->maketext( - 'ATTEMPT NOT ACCEPTED -- Please submit answers again (or request new version if neccessary).') + 'ATTEMPT NOT ACCEPTED -- Please submit answers again (or request new version if necessary).') ) ) if $c->{resubmitDetected}; @@ -1549,7 +1418,7 @@ sub output_achievement_message ($c) { && $c->{submitAnswers} && $c->{problem}->set_id ne 'Undefined_Set') { - return checkForAchievements($c->{problem}, $c->{pg}, $c); + return checkForAchievements($c->{problem}, $c); } return ''; @@ -1593,7 +1462,8 @@ sub output_past_answer_button ($c) { $c->hidden_field(selected_sets => $c->{problem}->set_id), $c->hidden_field(selected_users => $c->{problem}->user_id), $c->tag( - 'p', + 'div', + class => 'mb-3', $c->submit_button( $c->maketext('Show Past Answers'), name => 'action', diff --git a/lib/WeBWorK/ContentGenerator/ProblemSet.pm b/lib/WeBWorK/ContentGenerator/ProblemSet.pm index ba77939ec5..d20438d94d 100644 --- a/lib/WeBWorK/ContentGenerator/ProblemSet.pm +++ b/lib/WeBWorK/ContentGenerator/ProblemSet.pm @@ -17,19 +17,25 @@ use WeBWorK::Utils::Sets qw(is_restricted grade_set format_set_name_display use WeBWorK::DB::Utils qw(grok_versionID_from_vsetID_sql); use WeBWorK::Localize; use WeBWorK::AchievementItems; +use WeBWorK::HTML::StudentNav qw(studentNav); + +sub can ($c, $arg) { + if ($arg eq 'info') { + return $c->{pg} ? 1 : 0; + } + return $c->SUPER::can($arg); +} async sub initialize ($c) { my $db = $c->db; my $ce = $c->ce; my $authz = $c->authz; - # $c->{invalidSet} is set in checkSet which is called by ContentGenerator.pm - return - if $c->{invalidSet} - && ($c->{invalidSet} !~ /^Client ip address .* is not in the list of addresses/ - || $authz->{merged_set}->assignment_type !~ /gateway/); + # $c->{invalidSet} is set in checkSet which is called by ContentGenerator.pm. + # If $c->{viewSetCheck} is also set, we want to view some information unless the set is hidden. + return if $c->{invalidSet} && (!$c->{viewSetCheck} || $c->{viewSetCheck} eq 'hidden'); - # This will all be valid if checkSet did not set $c->{invalidSet}. + # This will all be valid if the above check passes. my $userID = $c->param('user'); my $eUserID = $c->param('effectiveUser'); @@ -105,6 +111,7 @@ async sub initialize ($c) { $c->{pg} = await renderPG($c, $effectiveUser, $c->{set}, $problem, $c->{set}->psvn, {}, { displayMode => $displayMode }); + $c->{pg} = '' unless $c->{pg}{body_text} =~ /\S/; return; } @@ -113,17 +120,24 @@ sub nav ($c, $args) { # Don't show the nav if the user does not have unrestricted navigation permissions. return '' unless $c->authz->hasPermissions($c->param('user'), 'navigation_allowed'); - my @links = ( - $c->maketext('Assignments'), - $c->url_for($c->app->routes->lookup($c->current_route)->parent->name), - $c->maketext('Assignments') - ); return $c->tag( 'div', class => 'row sticky-nav', role => 'navigation', - 'aria-label' => 'problem navigation', - $c->tag('div', $c->navMacro($args, {}, @links)) + 'aria-label' => 'set navigation', + $c->c( + $c->tag( + 'div', + class => 'd-flex submit-buttons-container', + $c->navMacro( + $args, {}, + $c->maketext('Assignments'), + $c->url_for($c->app->routes->lookup($c->current_route)->parent->name), + $c->maketext('Assignments') + ) + ), + $c->{set} ? studentNav($c, $c->{set}->set_id) : '' + )->join('') ); } @@ -161,10 +175,8 @@ sub siblings ($c) { return $c->include('ContentGenerator/ProblemSet/siblings', setIDs => \@setIDs); } -sub info { - my ($c) = @_; - return '' unless $c->{pg}; - return $c->include('ContentGenerator/ProblemSet/info'); +sub info ($c) { + return $c->{pg} ? $c->include('ContentGenerator/ProblemSet/info') : ''; } # This is called by the ContentGenerator/ProblemSet/body template for a regular homework set. @@ -180,12 +192,14 @@ sub gateway_body ($c) { my $ce = $c->ce; my $db = $c->db; - my $set = $c->{set}; - my $effectiveUser = $c->param('effectiveUser'); - my $user = $c->param('user'); + my $set = $c->{set}; + my $effectiveUserID = $c->param('effectiveUser'); + my $userID = $c->param('user'); + + my $effectiveUser = $db->getUser($effectiveUserID); my $timeNow = time; - my $timeLimit = $set->version_time_limit || 0; + my $timeLimit = ($set->version_time_limit || 0) * $effectiveUser->accommodation_time_factor; # Compute how many versions have been launched within timeInterval to determine if a new version can be created, # if a version can be continued, and the date a next version can be started. If there is an open version that @@ -206,8 +220,9 @@ sub gateway_body ($c) { } # Get a problem to determine how many submits have been made. - my @ProblemNums = $db->listUserProblems($effectiveUser, $set->set_id); - my $Problem = $db->getMergedProblemVersion($effectiveUser, $set->set_id, $verSet->version_id, $ProblemNums[0]); + my @ProblemNums = $db->listUserProblems($effectiveUserID, $set->set_id); + my $Problem = + $db->getMergedProblemVersion($effectiveUserID, $set->set_id, $verSet->version_id, $ProblemNums[0]); my $verSubmits = defined $Problem ? $Problem->num_correct + $Problem->num_incorrect : 0; my $maxSubmits = $verSet->attempts_per_version || 0; @@ -292,11 +307,11 @@ sub gateway_body ($c) { $data->{score} = ''; # Only show score if user has permission and assignment has at least one submit. - if ($authz->hasPermissions($user, 'view_hidden_work') + if ($authz->hasPermissions($userID, 'view_hidden_work') || ($verSet->hide_score eq 'N' && $verSubmits >= 1) || ($verSet->hide_score eq 'BeforeAnswerDate' && $timeNow > $set->answer_date)) { - my ($total, $possible) = grade_set($db, $verSet, $effectiveUser, 1); + my ($total, $possible) = grade_set($db, $verSet, $effectiveUserID, 1); $total = wwRound(2, $total); $data->{score} = "$total/$possible"; } diff --git a/lib/WeBWorK/ContentGenerator/ProblemSets.pm b/lib/WeBWorK/ContentGenerator/ProblemSets.pm index 3eeb4fb4c3..2c02a51ceb 100644 --- a/lib/WeBWorK/ContentGenerator/ProblemSets.pm +++ b/lib/WeBWorK/ContentGenerator/ProblemSets.pm @@ -11,7 +11,7 @@ use WeBWorK::Debug; use WeBWorK::Utils qw(sortByName); use WeBWorK::Utils::DateTime qw(after); use WeBWorK::Utils::Files qw(readFile path_is_subdir); -use WeBWorK::Utils::Sets qw(is_restricted format_set_name_display); +use WeBWorK::Utils::Sets qw(restricted_set_message); use WeBWorK::Localize; # The "default" data in the course_info.txt file. @@ -114,15 +114,11 @@ sub info ($c) { } sub getSetStatus ($c, $set) { - my $ce = $c->ce; - my $db = $c->db; - my $authz = $c->authz; - my $effectiveUser = $c->param('effectiveUser') || $c->param('user'); - my $canViewUnopened = $authz->hasPermissions($c->param('user'), 'view_unopened_sets'); - - my @restricted = $ce->{options}{enableConditionalRelease} ? is_restricted($db, $set, $effectiveUser) : (); - - my $link_is_active = 1; + my $ce = $c->ce; + my $db = $c->db; + my $authz = $c->authz; + my $effectiveUser = $c->param('effectiveUser') || $c->param('user'); + my $restricted_msg = restricted_set_message($c, $set, 'conditional') || restricted_set_message($c, $set, 'lti'); # Determine set status. my $status_msg; @@ -132,11 +128,7 @@ sub getSetStatus ($c, $set) { $status = 'not-open'; $status_msg = $c->maketext('Will open on [_1].', $c->formatDateTime($set->open_date, $ce->{studentDateDisplayFormat})); - push(@$other_messages, $c->restricted_progression_msg(1, $set->restricted_status * 100, @restricted)) - if @restricted; - $link_is_active = 0 - unless $canViewUnopened - || ($set->assignment_type =~ /gateway/ && $db->countSetVersions($effectiveUser, $set->set_id)); + push(@$other_messages, $restricted_msg) if $restricted_msg; } elsif ($c->submitTime < $set->due_date) { $status = 'open'; @@ -172,31 +164,8 @@ sub getSetStatus ($c, $set) { $c->maketext('Open. Due [_1].', $c->formatDateTime($set->due_date, $ce->{studentDateDisplayFormat})); } - if (@restricted) { - $link_is_active = 0 unless $canViewUnopened; - push(@$other_messages, $c->restricted_progression_msg(0, $set->restricted_status * 100, @restricted)); - } elsif (!$canViewUnopened - && $ce->{LTIVersion} - && ($ce->{LTIVersion} ne 'v1p3' || !$ce->{LTI}{v1p3}{ignoreMissingSourcedID}) - && defined $ce->{LTIGradeMode} - && $ce->{LTIGradeMode} eq 'homework' - && !$set->lis_source_did) - { - # The set shouldn't be shown if LTI grade mode is set to homework and a - # sourced_id is not available to use to send back grades - # (unless we are using LTI 1.3 and $LTI{v1p3}{ignoreMissingSourcedID} is set) - push( - @$other_messages, - $c->maketext( - 'You must log into this set via your Learning Management System ([_1]).', - $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} - ? $c->link_to( - $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} - ) - : $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} - ) - ); - $link_is_active = 0; + if ($restricted_msg) { + push(@$other_messages, $restricted_msg); } } elsif ($c->submitTime < $set->answer_date) { $status_msg = $c->maketext('Answers available for review on [_1].', @@ -209,8 +178,7 @@ sub getSetStatus ($c, $set) { status => $status, status_msg => $status_msg, other_messages => $other_messages, - link_is_active => $link_is_active, - is_restricted => scalar(@restricted) + is_restricted => $restricted_msg ? 1 : 0 ); } @@ -232,20 +200,4 @@ sub byUrgency { return $a->set_id cmp $b->set_id; } -sub restricted_progression_msg ($c, $open, $restriction, @restricted) { - if (@restricted == 1) { - return $c->maketext( - 'To access this set you must score at least [_1]% on set [_2].', - sprintf('%.0f', $restriction), - $c->tag('span', dir => 'ltr', format_set_name_display($restricted[0])) - ); - } else { - return $c->maketext( - 'To access this set you must score at least [_1]% on the following sets: [_2].', - sprintf('%.0f', $restriction), - join(', ', map { $c->tag('span', dir => 'ltr', format_set_name_display($_)) } @restricted) - ); - } -} - 1; diff --git a/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm b/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm index 09e719d91b..f5d95d9e6e 100644 --- a/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm +++ b/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm @@ -21,14 +21,34 @@ use WebworkWebservice; sub initializeRoute ($c, $routeCaptures) { $c->{rpc} = 1; + my $allow_unsecured_rpc = $c->config('allow_unsecured_rpc'); + my $disable_cookies = 0; + + if ($allow_unsecured_rpc) { + if (ref($allow_unsecured_rpc) eq 'HASH') { + my $courseID = $c->param('courseID'); + if ($courseID && $allow_unsecured_rpc->{$courseID}) { + if (ref($allow_unsecured_rpc->{$courseID}) eq 'HASH') { + my $userID = $c->param('user'); + if ($userID && $allow_unsecured_rpc->{$courseID}{$userID}) { + $disable_cookies = 1; + } + } else { + $disable_cookies = 1; + } + } + } else { + $disable_cookies = 1; + } + } $c->stash(disable_cookies => 1) - if $c->current_route eq 'render_rpc' && $c->param('disableCookies') && $c->config('allow_unsecured_rpc'); + if $c->current_route eq 'render_rpc' && $c->param('disableCookies') && $disable_cookies; # This provides compatibility for legacy html2xml parameters. # This should be deleted when the html2xml endpoint is removed. if ($c->current_route eq 'html2xml') { - $c->stash(disable_cookies => 1) if $c->config('allow_unsecured_rpc'); + $c->stash(disable_cookies => 1) if $disable_cookies; for ([ 'userID', 'user' ], [ 'course_password', 'passwd' ], [ 'session_key', 'key' ]) { $c->param($_->[1], $c->param($_->[0])) if defined $c->param($_->[0]) && !defined $c->param($_->[1]); } diff --git a/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm b/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm index 3ee248c2b0..d4d4ef44a0 100644 --- a/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm +++ b/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm @@ -2,14 +2,10 @@ package WeBWorK::ContentGenerator::SampleProblemViewer; use Mojo::Base 'WeBWorK::ContentGenerator', -signatures; use File::Basename qw(basename); -use Mojo::File; -use Mojo::JSON qw(decode_json encode_json); -use File::Find; use Pod::Simple::Search; -use Pod::Simple::SimpleTree; -use WeBWorK::Utils::Files qw(path_is_subdir); -use SampleProblemParser qw(parseSampleProblem generateMetadata getSampleProblemCode); +use WeBWorK::Utils::Files qw(path_is_subdir); +use WeBWorK::PG::SampleProblemParser qw(parseSampleProblem generateMetadata getSampleProblemCode getSearchData); =head1 NAME @@ -92,10 +88,10 @@ sub renderSampleProblem ($c) { %{ parseSampleProblem( $problemFile, - metadata => $metadata, - pod_root => $c->url_for('pod_viewer', filePath => 'macros'), - pg_doc_home => $c->url_for('sample_problem_index'), - macro_locations => \%macro_locations, + metadata => $metadata, + pod_base_url => $c->url_for('pod_viewer', filePath => 'macros'), + sample_problem_base_url => $c->url_for('sample_problem_index'), + macro_locations => \%macro_locations, ) }, metadata => $metadata, @@ -106,195 +102,7 @@ sub renderSampleProblem ($c) { } sub searchData ($c) { - my $sampleProblemDir = $c->ce->{pg_dir} . '/tutorial/sample-problems'; - - my $searchDataFile = Mojo::File->new($c->ce->{webworkDirs}{DATA})->child('sample-problem-search-data.json'); - my %files = map { $_->{filename} => $_ } @{ (eval { decode_json($searchDataFile->slurp('UTF-8')) } // []) }; - my @updatedFiles; - - # Process the sample problems in the sample problem directory. - find( - { - wanted => sub { - return unless $_ =~ /\.pg$/; - - my $file = Mojo::File->new($File::Find::name); - my $lastModified = $file->stat->mtime; - - if ($files{$_}) { - push(@updatedFiles, $files{$_}); - return if $files{$_}{lastModified} >= $lastModified; - } - - my @fileContents = eval { split("\n", $file->slurp('UTF-8')) }; - return if $@; - - if (!$files{$_}) { - $files{$_} = { - type => 'sample problem', - filename => $_, - dir => $file->dirname->basename - }; - push(@updatedFiles, $files{$_}); - } - $files{$_}{lastModified} = $lastModified; - - my (%words, @kw, @macros, @subjects, $description); - - while (@fileContents) { - my $line = shift @fileContents; - if ($line =~ /^#:%\s*(\w+)\s*=\s*(.*)\s*$/) { - # Store the name and subjects. - $files{$_}{name} = $2 if $1 eq 'name'; - if ($1 eq 'subject') { - @subjects = split(',\s*', $2 =~ s/\[(.*)\]/$1/r); - } - } elsif ($line =~ /^#:\s*(.*)?/) { - my @newWords = $c->processLine($1); - @words{@newWords} = (1) x @newWords if @newWords; - } elsif ($line =~ /loadMacros\(/) { - my $macros = $line; - while ($line && $line !~ /\);\s*$/) { - $line = shift @fileContents; - $macros .= $line; - } - my @usedMacros = - map {s/['"\s]//gr} split(/\s*,\s*/, $macros =~ s/loadMacros\((.*)\)\;$/$1/r); - - # Get the macros other than PGML.pl, PGstandard.pl, and PGcourse.pl. - for my $m (@usedMacros) { - push(@macros, $m) unless $m =~ /^(PGML|PGstandard|PGcourse)\.pl$/; - } - } elsif ($line =~ /##\s*KEYWORDS\((.*)\)/) { - @kw = map {s/^'(.*)'$/$1/r} split(/,\s*/, $1); - } elsif ($line =~ /^##\s*DESCRIPTION/) { - $line = shift(@fileContents); - while ($line && $line !~ /^##\s*ENDDESCRIPTION/) { - $description .= ($line =~ s/^##\s+//r) . ' '; - $line = shift(@fileContents); - } - $description =~ s/\s+$//; - } - } - - $files{$_}{description} = $description; - $files{$_}{subjects} = \@subjects; - $files{$_}{terms} = [ keys %words ]; - $files{$_}{keywords} = \@kw; - $files{$_}{macros} = \@macros; - - return; - } - }, - $sampleProblemDir - ); - - # Process the POD in macros in the macros dir. - (undef, my $macro_files) = Pod::Simple::Search->new->inc(0)->survey($c->ce->{pg_dir} . "/macros"); - for my $macroFile (sort keys %$macro_files) { - next if $macroFile =~ /deprecated/; - - my $file = Mojo::File->new($macroFile); - my $fileName = $file->basename; - my $lastModified = $file->stat->mtime; - - if ($files{$fileName}) { - push(@updatedFiles, $files{$fileName}); - next if $files{$fileName}{lastModified} >= $lastModified; - } - - if (!$files{$fileName}) { - $files{$fileName} = { - type => 'macro', - id => scalar(keys %files) + 1, - filename => $fileName, - dir => $file->dirname->to_rel($c->ce->{pg_dir})->to_string - }; - push(@updatedFiles, $files{$fileName}); - } - $files{$fileName}{lastModified} = $lastModified; - - my $root = Pod::Simple::SimpleTree->new->parse_file($file->to_string)->root; - - $files{$fileName}{terms} = $c->extractHeaders($root); - - if (my $nameDescription = extractHeadText($root, 'NAME')) { - (undef, my $description) = split(/\s*-\s*/, $nameDescription, 2); - $files{$fileName}{description} = $description if $description; - } - } - - # Redindex in case files were added or removed. - my $count = 0; - $_->{id} = ++$count for @updatedFiles; - - $searchDataFile->spew(encode_json(\@updatedFiles), 'UTF-8'); - - return $c->render(json => \@updatedFiles); -} - -# Get the stop words. The stop words file is loaded the first time this method is called, -# and is stashed and returned in later calls. -sub stopWords ($c) { - return $c->stash->{stopWords} if $c->stash->{stopWords}; - $c->stash->{stopWords} = {}; - - my $contents = eval { $c->app->home->child('assets', 'stop-words-en.txt')->slurp('UTF-8') }; - return $c->stash->{stopWords} if $@; - - for my $line (split("\n", $contents)) { - chomp $line; - next if $line =~ /^#/ || !$line; - $c->stash->{stopWords}{$line} = 1; - } - - return $c->stash->{stopWords}; -} - -sub processLine ($c, $line) { - my %words; - - # Extract linked macros and problems. - my @linkedFiles = $line =~ /(?:PODLINK|PROBLINK)\('([\w.]+)'\)/g; - $words{$_} = 1 for @linkedFiles; - - # Replace any non-word characters with spaces. - $line =~ s/\W/ /g; - - for my $word (split(/\s+/, $line)) { - next if $word =~ /^\d*$/; - $word = lc($word); - $words{$word} = 1 if !$c->stopWords->{$word}; - } - return keys %words; -} - -# Extract the text for a section from the given POD with a section header title. -sub extractHeadText ($root, $title) { - my @index = grep { ref($root->[$_]) eq 'ARRAY' && $root->[$_][2] eq $title } 0 .. $#$root; - return unless @index == 1; - - my $node = $root->[ $index[0] + 1 ]; - my $str = ''; - for (2 .. $#$node) { - $str .= ref($node->[$_]) eq 'ARRAY' ? $node->[$_][2] : $node->[$_]; - } - return $str; -} - -# Extract terms form POD headers. -sub extractHeaders ($c, $root) { - my %terms = - map { $_ => 1 } - grep { $_ && !$c->stopWords->{$_} } - map { split(/\s+/, $_) } - map { lc($_) =~ s/\W/ /gr } - map { - grep { !ref($_) } - @$_[ 2 .. $#$_ ] - } - grep { ref($_) eq 'ARRAY' && $_->[0] =~ /^head\d+$/ } @$root; - return [ keys %terms ]; + return $c->render(json => getSearchData($c->ce->{webworkDirs}{DATA} . '/sample-problem-search-data.json')); } 1; diff --git a/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm b/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm index 39b164d4ab..3dc0c76b31 100644 --- a/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm +++ b/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm @@ -78,6 +78,7 @@ async sub pre_header_initialize ($c) { effectivePermissionLevel => $db->getPermissionLevel($c->{effectiveUserID})->permission, useMathQuill => $c->{will}{useMathQuill}, useMathView => $c->{will}{useMathView}, + problemData => '{}' }, ); @@ -116,6 +117,7 @@ async sub pre_header_initialize ($c) { effectivePermissionLevel => $db->getPermissionLevel($c->{effectiveUserID})->permission, useMathQuill => $c->{will}{useMathQuill}, useMathView => $c->{will}{useMathView}, + problemData => '{}' }, ); @@ -155,10 +157,9 @@ async sub pre_header_initialize ($c) { } # Disable options that are not applicable for showMeAnother. - $c->{can}{recordAnswers} = 0; - $c->{can}{checkAnswers} = 0; # This is turned on if the showMeAnother conditions are met below. - $c->{can}{getSubmitButton} = 0; - $c->{can}{showProblemGrader} = 0; + $c->{can}{recordAnswers} = 0; + $c->{can}{checkAnswers} = 0; # This is turned on if the showMeAnother conditions are met below. + $c->{can}{getSubmitButton} = 0; if ($c->stash->{isPossible}) { $c->{can}{showCorrectAnswers} = @@ -206,34 +207,17 @@ async sub pre_header_initialize ($c) { showMessages => !$showOnlyCorrectAnswers, showCorrectAnswers => $showOnlyCorrectAnswers || ($c->{will}{checkAnswers} && $c->{will}{showCorrectAnswers}) ? 1 : 0, - debuggingOptions => getTranslatorDebuggingOptions($c->authz, $c->{userID}) + debuggingOptions => getTranslatorDebuggingOptions($c->authz, $c->{userID}), + problemData => $c->{formFields}{problem_data} || '{}' } ); - # Warnings in the renderPG subprocess will not be caught by the global warning handler of this process. - # So rewarn them and let the global warning handler take care of it. - warn $pg->{warnings} if $pg->{warnings}; - debug('end pg processing'); # Update and fix hint/solution options after PG processing $c->{can}{showHints} &&= $pg->{flags}{hintExists}; $c->{can}{showSolutions} &&= $pg->{flags}{solutionExists}; - # Record errors - $c->{pgdebug} = $pg->{debug_messages} if ref $pg->{debug_messages} eq 'ARRAY'; - $c->{pgwarning} = $pg->{warning_messages} if ref $pg->{warning_messages} eq 'ARRAY'; - $c->{pginternalerrors} = $pg->{internal_debug_messages} if ref $pg->{internal_debug_messages} eq 'ARRAY'; - # $c->{pgerrors} is defined if any of the above are defined, and is nonzero if any are non-empty. - $c->{pgerrors} = @{ $c->{pgdebug} // [] } || @{ $c->{pgwarning} // [] } || @{ $c->{pginternalerrors} // [] } - if defined $c->{pgdebug} || defined $c->{pgwarning} || defined $c->{pginternalerrors}; - - # If $c->{pgerrors} is not defined, then the PG messages arrays were not defined, - # which means $pg->{pgcore} was not defined and the translator died. - warn 'Processing of this PG problem was not completed. Probably because of a syntax error. ' - . 'The translator died prematurely and no PG warning messages were transmitted.' - unless defined $c->{pgerrors}; - $c->{pg} = $pg; return; diff --git a/lib/WeBWorK/DB.pm b/lib/WeBWorK/DB.pm index 5ccf5e0eba..2aa588e0d9 100644 --- a/lib/WeBWorK/DB.pm +++ b/lib/WeBWorK/DB.pm @@ -436,13 +436,19 @@ sub abort_transaction { BEGIN { *User = gen_schema_accessor("user"); - *newUser = gen_new("user"); *countUsersWhere = gen_count_where("user"); *existsUserWhere = gen_exists_where("user"); *listUsersWhere = gen_list_where("user"); *getUsersWhere = gen_get_records_where("user"); } +sub newUser { + my ($self, @data) = @_; + my $user = $self->{user}{record}->new(@data); + $user->accommodation_time_factor(1) unless defined $user->accommodation_time_factor; + return $user; +} + sub countUsers { return scalar shift->listUsers(@_) } # Note: This returns a list of user_ids for all users except set level proctors. diff --git a/lib/WeBWorK/DB/Record/User.pm b/lib/WeBWorK/DB/Record/User.pm index b712f3473d..5eeea5780e 100644 --- a/lib/WeBWorK/DB/Record/User.pm +++ b/lib/WeBWorK/DB/Record/User.pm @@ -12,20 +12,21 @@ use warnings; BEGIN { __PACKAGE__->_fields( - user_id => { type => "VARCHAR(100) NOT NULL", key => 1 }, - first_name => { type => "TEXT" }, - last_name => { type => "TEXT" }, - email_address => { type => "TEXT" }, - student_id => { type => "TEXT" }, - status => { type => "TEXT" }, - section => { type => "TEXT" }, - recitation => { type => "TEXT" }, - comment => { type => "TEXT" }, - displayMode => { type => "TEXT" }, - showOldAnswers => { type => "INT" }, - useMathView => { type => "INT" }, - useMathQuill => { type => "INT" }, - lis_source_did => { type => "TEXT" }, + user_id => { type => "VARCHAR(100) NOT NULL", key => 1 }, + first_name => { type => "TEXT" }, + last_name => { type => "TEXT" }, + email_address => { type => "TEXT" }, + student_id => { type => "TEXT" }, + status => { type => "TEXT" }, + accommodation_time_factor => { type => "FLOAT NOT NULL DEFAULT 1" }, + section => { type => "TEXT" }, + recitation => { type => "TEXT" }, + comment => { type => "TEXT" }, + displayMode => { type => "TEXT" }, + showOldAnswers => { type => "INT" }, + useMathView => { type => "INT" }, + useMathQuill => { type => "INT" }, + lis_source_did => { type => "TEXT" }, ); } diff --git a/lib/WeBWorK/File/SetDef.pm b/lib/WeBWorK/File/SetDef.pm index e137ddf544..1599b25848 100644 --- a/lib/WeBWorK/File/SetDef.pm +++ b/lib/WeBWorK/File/SetDef.pm @@ -197,8 +197,8 @@ sub importSetsFromDef ($ce, $db, $setDefFiles, $existingSets = undef, $assign = showMeAnother => $rh_problem->{showMeAnother}, showHintsAfter => $rh_problem->{showHintsAfter}, prPeriod => $rh_problem->{prPeriod}, - attToOpenChildren => $rh_problem->{attToOpenChildren}, - countsParentGrade => $rh_problem->{countsParentGrade} + attToOpenChildren => $rh_problem->{att_to_open_children}, + countsParentGrade => $rh_problem->{counts_parent_grade} ); } diff --git a/lib/WeBWorK/HTML/SingleProblemGrader.pm b/lib/WeBWorK/HTML/SingleProblemGrader.pm index d10de75633..fa7bd24304 100644 --- a/lib/WeBWorK/HTML/SingleProblemGrader.pm +++ b/lib/WeBWorK/HTML/SingleProblemGrader.pm @@ -11,8 +11,9 @@ as a student. use WeBWorK::Localize; use WeBWorK::Utils 'wwRound'; +use WeBWorK::Utils::DateTime qw(before); -sub new ($class, $c, $pg, $userProblem) { +sub new ($class, $c, $pg, $userProblem, $mergedSet) { $class = ref($class) || $class; my $db = $c->db; @@ -43,7 +44,12 @@ sub new ($class, $c, $pg, $userProblem) { recorded_score => $recordedScore, past_answer_id => $userPastAnswerID // 0, comment_string => $comment, - c => $c + c => $c, + # The grader needs to also save the sub_status if reduced scoring is not enabled, + # or if it is but it is before the reduced scoring date. + save_sub_status => !$c->ce->{pg}{ansEvalDefaults}{enableReducedScoring} + || !$mergedSet->enable_reduced_scoring + || before($mergedSet->reduced_scoring_date) }; bless $self, $class; diff --git a/lib/WeBWorK/HTML/StudentNav.pm b/lib/WeBWorK/HTML/StudentNav.pm new file mode 100644 index 0000000000..7591712a8d --- /dev/null +++ b/lib/WeBWorK/HTML/StudentNav.pm @@ -0,0 +1,83 @@ +package WeBWorK::HTML::StudentNav; +use Mojo::Base 'Exporter', -signatures; + +=head1 NAME + +WeBWorK::HTML::StudentNav - student navigation for all users assigned to a set. + +=cut + +our @EXPORT_OK = qw(studentNav); + +sub studentNav ($c, $setID) { + my $userID = $c->param('user'); + + return '' unless $c->authz->hasPermissions($userID, 'become_student'); + + # Find all users for the given set (except the current user) sorted by last_name, then first_name, then user_id. + my @allUserRecords = $c->db->getUsersWhere( + { + user_id => + [ map { $_->[0] } $c->db->listUserSetsWhere({ set_id => $setID, user_id => { '!=' => $userID } }) ] + }, + [qw/last_name first_name user_id/] + ); + + return '' unless @allUserRecords; + + my $eUserID = $c->param('effectiveUser'); + + my $filter = $c->param('studentNavFilter'); + + # Find the previous, current, and next users, and format the student names for display. + # Also create a hash of sections and recitations if there are any for the course. + my @userRecords; + my $currentUserIndex = 0; + my %filters; + for (@allUserRecords) { + # Add to the sections and recitations if defined. Also store the first user found in that section or + # recitation. This user will be switched to when the filter is selected. + my $section = $_->section; + $filters{"section:$section"} = [ $c->maketext('Filter by section [_1]', $section), $_->user_id ] + if $section && !$filters{"section:$section"}; + my $recitation = $_->recitation; + $filters{"recitation:$recitation"} = [ $c->maketext('Filter by recitation [_1]', $recitation), $_->user_id ] + if $recitation && !$filters{"recitation:$recitation"}; + + # Only keep this user if it satisfies the selected filter if a filter was selected. + next + unless !$filter + || ($filter =~ /^section:(.*)$/ && $_->section eq $1) + || ($filter =~ /^recitation:(.*)$/ && $_->recitation eq $1); + + my $addRecord = $_; + $currentUserIndex = @userRecords if $addRecord->user_id eq $eUserID; + push @userRecords, $addRecord; + + # Construct a display name. + $addRecord->{displayName} = + ($addRecord->last_name || $addRecord->first_name + ? $addRecord->last_name . ', ' . $addRecord->first_name + : $addRecord->user_id); + } + my $prevUser = $currentUserIndex > 0 ? $userRecords[ $currentUserIndex - 1 ] : 0; + my $nextUser = $currentUserIndex < $#userRecords ? $userRecords[ $currentUserIndex + 1 ] : 0; + + # Mark the current user. + $userRecords[$currentUserIndex]{currentUser} = 1; + + # Set up the student nav. + return $c->include( + 'HTML/StudentNav/student_nav', + userID => $userID, + eUserID => $eUserID, + userRecords => \@userRecords, + currentUserIndex => $currentUserIndex, + prevUser => $prevUser, + nextUser => $nextUser, + filter => $filter, + filters => \%filters + ); +} + +1; diff --git a/lib/WeBWorK/Localize/webwork2.pot b/lib/WeBWorK/Localize/webwork2.pot index 0d3860417c..79054b475e 100644 --- a/lib/WeBWorK/Localize/webwork2.pot +++ b/lib/WeBWorK/Localize/webwork2.pot @@ -19,7 +19,7 @@ msgstr "" msgid " (version %1)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:263 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:282 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:278 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:297 msgid " Answers Available." msgstr "" @@ -38,6 +38,11 @@ msgstr "" msgid "\"%1\" contains invalid characters." msgstr "" +#. (xml_escape($hardcopy_format) +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:134 +msgid "\"%1\" is not a valid hardcopy format." +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:127 msgid "\"Act as\" a student" msgstr "" @@ -74,7 +79,7 @@ msgstr "" msgid "% Score with Review" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:501 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:506 msgid "% Score:" msgstr "" @@ -83,13 +88,28 @@ msgstr "" msgid "%1 (%2 remaining)" msgstr "" +#. ($user->full_name, $user->user_id) +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:21 +msgid "%1 (%2) wrote:" +msgstr "" + +#. ($user->status) +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:165 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:97 +msgid "%1 (unknown status abbreviation)" +msgstr "" + #. ($c->maketext($self->name) #: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems.pm:121 msgid "%1 (unlimited reusability)" msgstr "" +#. ($_->{displayName}, $_->{setVersion}) +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz/nav.html.ep:50 +msgid "%1 (version %2)" +msgstr "" + #. ($properties{name}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1018 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1008 msgid "%1 Help" msgstr "" @@ -100,12 +120,12 @@ msgid "%1 Icon" msgstr "" #. ($total) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2552 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2553 msgid "%1 OTP secrets copied." msgstr "" #. ($total) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2527 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2528 msgid "%1 OTP secrets reset." msgstr "" @@ -120,22 +140,22 @@ msgid "%1 Problems:" msgstr "" #. ('templates', 'html') -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:180 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:181 msgid "%1 and %2 folders" msgstr "" #. ($achievementID =~ s/_/ /gr) -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:333 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:309 msgid "%1 evaluator" msgstr "" #. ($achievementID =~ s/_/ /gr) -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:340 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:316 msgid "%1 notifications" msgstr "" #. ($count) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2141 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2120 msgid "%1 sets" msgstr "" @@ -145,13 +165,13 @@ msgid "%1 setting" msgstr "" #. ($count, $numUsers) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2127 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2106 msgid "%1 students out of %2" msgstr "" #. ($achievementItem->name, $message) #: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems.pm:93 -msgid "%1 successfuly used. %2" +msgid "%1 successfully used. %2" msgstr "" #. ($rename_oldCourseID, $rename_oldCourseTitle, $rename_newCourseTitle, $rename_oldCourseInstitution, $rename_newCourseInstitution) @@ -160,17 +180,17 @@ msgid "%1 title and institution changed from %2 to %3 and from %4 to %5" msgstr "" #. ($achievementID =~ s/_/ /gr) -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:347 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:323 msgid "%1 users" msgstr "" #. (scalar @userIDsToExport, "$dir/$fileName") -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:458 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:481 msgid "%1 users exported to file %2" msgstr "" #. ($numReplaced, $numAdded, $numSkipped, join(', ', @$skipped) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:432 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:455 msgid "%1 users replaced, %2 users added, %3 users skipped. Skipped users: (%4)" msgstr "" @@ -219,12 +239,12 @@ msgstr "" #. ($c->tag('span', dir => 'ltr', format_set_name_display($setID) #. ($c->tag('span', dir => 'ltr', $prettySetID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Login.pm:27 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1028 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:162 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Login.pm:27 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:957 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:162 msgid "%1: Problem %2" msgstr "" #. ($c->tag('span', dir => 'ltr', format_set_name_display($c->stash('setID') -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:252 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:254 msgid "%1: Problem %2 Show Me Another" msgstr "" @@ -251,7 +271,7 @@ msgstr "" #. (sprintf('%3.1f', $testTime) #. ($timeLeft) #. ($minutes) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/LTIUpdate.pm:93 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:146 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:164 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/LTIUpdate.pm:93 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:145 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:163 msgid "%quant(%1,minute)" msgstr "" @@ -291,43 +311,43 @@ msgid "(%quant(%1,item))" msgstr "" #. ($problemValue) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1040 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:969 msgid "(%quant(%1,point))" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:713 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:714 msgid "(Any unsaved changes will be lost.)" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:11 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:137 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:11 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:123 msgid "(If an action cannot be executed it will not appear.)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1221 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1162 msgid "(This problem will not count toward your grade.)" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/set_list_row.html.ep:34 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/set_list_row.html.ep:33 msgid "(This set is hidden from students.)" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:359 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:342 msgid "(This test is overtime because it was not submitted in the allowed time.)" msgstr "" # $testNoun is either "test" or "submission" #. ($testNoun, $c->formatDateTime($c->{set}->answer_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:170 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:151 msgid "(Your score on this %1 is not available until %2.)" msgstr "" # $testNoun is either "test" or "submission" #. ($testNoun) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:172 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:153 msgid "(Your score on this %1 is not available.)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1276 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1286 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1280 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1290 msgid "(correct)" msgstr "" @@ -335,24 +355,28 @@ msgstr "" msgid "(in target set)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1278 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1288 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1282 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1292 msgid "(incorrect)" msgstr "" #. ($pgScore) #. ($recScore) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1280 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1290 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1284 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1294 msgid "(score %1)" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:37 +msgid "(taken from filenames)" +msgstr "" + #. ($versionID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:164 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:160 msgid "(version %1)" msgstr "" #. ($display_sort_method_name{$secondary_sort_method}) #. ($display_sort_method_name{$ternary_sort_method}) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:141 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:144 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:142 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:145 msgid ", then by %1" msgstr "" @@ -364,11 +388,11 @@ msgstr "" msgid "0 seconds" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2137 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2116 msgid "1 set" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2123 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2102 msgid "1 student" msgstr "" @@ -402,11 +426,11 @@ msgstr "" msgid "

Some servers handle courses taking place in different timezones. If this course is not showing the correct timezone, enter the correct value here. The format consists of unix times, such as \"America/New_York\", \"America/Chicago\", \"America/Denver\", \"America/Phoenix\" or \"America/Los_Angeles\".

Complete list: TimeZoneFiles" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:982 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:985 msgid "

This can be set to one of the dates associated with assignments, or \"Never\". For each assignment, if this setting is \"After the ... \" then if it is after the indicated date, WeBWorK will send scores. If this setting is \"Never\" then there is no date that will force WeBWorK to send scores and only the $LTISendGradesEarlyThreshold can cause scores to be sent. If scores are sent:

  • For 'course' grade passback mode, the assignment will be included in the overall course score calculation.
  • For 'homework' grade passback mode, the assignment's score itself will be sent.

If $LTISendScoresAfterDate is set to \"After the reduced scoring date\" and an assignment has no reduced scoring date or reduced scoring is disabled, the fallback is to use the close date.

For a given assignment, WeBWorK will still send a score to the LMS if the $LTISendGradesEarlyThreshold has been met, regardless of how $LTISendScoresAfterDate is set.

" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1008 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1011 msgid "

This can either be set to a score or set to Attempted. When something triggers a potential grade passback, if it is earlier than $LTISendScoresAfterDate, the condition described by this variable must be met or else no score will be sent.

If this variable is a score, then the set will need to have a score that reaches or exceeds this score for its score to be sent to the LMS (or included in the 'course' score calculation). If this variable is set to Attempted, then the set needs to have been attempted for its score to be sent to the LMS (or included in the 'course' score calculation).

For a regular or jitar set, 'attempted' means that at least one exercise was attempted. For a test, 'attempted' means that either multiple versions exist or there is one version with a graded submission.

" msgstr "" @@ -414,7 +438,11 @@ msgstr "" msgid "

This sets whether the Reduced Scoring system will be enabled. If enabled you will need to set the default length of the reduced scoring period and the value of work done in the reduced scoring period below.

To use this, you also have to enable Reduced Scoring for individual assignments and set their Reduced Scoring Dates by editing the set data.

This works with the avg_problem_grader (which is the default grader) and the std_problem_grader (the all or nothing grader). It will work with custom graders if they are written appropriately.

" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:948 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:835 +msgid "

When students click the Email Instructor button to send feedback, WeBWorK fills in the subject line. Here you can set the subject line. In it, you can have various bits of information filled in with the following escape sequences.

  • %c = course ID
  • %u = user ID
  • %s = set ID
  • %p = problem ID
  • %x = section
  • %r = recitation
  • %% = literal percent sign

If content is between a brace pair, like '{ rec:%r}', then it will only be included in the subject line if all substitutions within the double brace pair are defined and nonempty." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:951 msgid "

When this is true, any time WeBWorK is about to send a score to the LMS, it will first request from the LMS what that score currently is. Then if there is no significant difference between the LMS score and the WeBWorK score, WeBWorK will not follow through with updating the LMS score. This is to avoid frequent insignificant updates to a student score in the LMS. With some LMSs, students may receive notifications each time a score is updated, and setting this variable will prevent too many notifications for them. This does create a two-step process, first querying the current score from the LMS and then actually updating the score (if there is a significant difference). Additional details:

  • If the LMS score is not 100%, but the WeBWorK score is, then even if the LMS score is only insignificantly less than 100%, it will be updated anyway.
  • If the LMS score is not set and the WeBWorK score is 0, this is considered a significant difference and the LMS score will updated to 0. However, the constraints of the $LTISendScoresAfterDate and the $LTISendGradesEarlyThreshold variables (described below) might apply, and the score may still not be updated in this case.
  • \"Significant\" means an absolute difference of 0.001, or 0.1%. At this time this is not configurable.
" msgstr "" @@ -422,7 +450,7 @@ msgstr "" msgid "

When viewing a problem, users may choose different methods of rendering formulas via an options box in the left panel. Here, you can adjust what display modes are listed.

The display modes are

  • plainText: shows the raw LaTeX strings for formulas.
  • images: produces images using the external programs LaTeX and dvipng.
  • MathJax: uses javascript to render mathematics.

You must use at least one display mode. If you select only one, then the options box will not give a choice of modes (since there will only be one active).

" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1447 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1451 msgid "Warning: There may be something wrong with a question in this test. Please inform your instructor including the warning messages below." msgstr "" @@ -451,7 +479,7 @@ msgid "
  • SMAcheckAnswers: Enables the \"Check Answers\" button f msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:821 -msgid "A \"Reveal\" button must be clicked to make a correct answer visible any time that correct answers for a problem are shown. Note that this is always the case for instructors before answers are available to students, and in \"Show Me Another\" problems." +msgid "A \"Reveal\" button must be clicked to make a correct answer visible any time that correct answers for a problem are shown. Note that this is always the case for instructors before answers are available to students (except when the problem grader is open), and in \"Show Me Another\" problems." msgstr "" #. ($add_courseID) @@ -461,7 +489,7 @@ msgid "A course with ID %1 already exists." msgstr "" #. ($courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1172 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1173 msgid "A directory already exists with the name %1. You must first delete this existing course before you can unarchive." msgstr "" @@ -501,20 +529,20 @@ msgstr "" msgid "A hash reference which saves global data for this user. This hash is persistent between evaluations and changes to this variable will be saved in the database." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:71 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:78 msgid "A list of sample problems by category." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:81 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:88 msgid "A list of sample problems by problem technique." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:76 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:83 msgid "A list of sample problems by subject area." msgstr "" #. ($locationID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1806 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1807 msgid "A location with the name %1 already exists in the database. Did you mean to edit that location instead?" msgstr "" @@ -533,7 +561,7 @@ msgstr "" msgid "A new file has been created at \"%1\" with the contents below." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:205 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:194 msgid "A new problem whose path ends in newProblem.pg should be given a new name, for example, \"myNewProblem.pg\"." msgstr "" @@ -541,7 +569,7 @@ msgstr "" msgid "A solution should be provided here." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:297 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:308 msgid "A student might start a timed test close to the close date. This setting allows to either cut them off at the close date or allow them the full time limit." msgstr "" @@ -558,11 +586,11 @@ msgstr "" msgid "A switch to govern the use of a Progress Bar for the student; this also enables/disables the highlighting of the current problem in the side bar, and whether it is correct (✓), in progress (…), incorrect (✗), or unattempted (no symbol)." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:360 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:371 msgid "A test is broken up into pages with this many problems on each page. Students can move from page to page without clicking to grade the test, and their temporary answers will be saved. Use \"0\" to indicate \"all problems on one page\". For tests with many problems, either extreme (1 per page or \"all on one page\") has drawbacks. With 1 per page, the student has many pages and may be frustrated trying to go back and find a particular problem. With \"all on one page\", the student may spend a lot of time on that one page without clicking anything that lets WeBWorK know they are still active, and their session might expire for inactivity before they get around to clicking the grade button. This situation can lead to their typed answers being lost and unrecoverable. Additionally, having many problems load at the same time on one page can put a strain on the server. This is especially worth considering if the test has many dynamically generated images, which can slow things down significantly." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:308 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:319 msgid "A test may be configured to allow students one or more versions. For each version, this is the number of times you will allow them to click to have that version graded. Depending on other settings, they may or may not be able to see scores and feedback following each grading. Use \"0\" to indicate there is no cap on the number of graded submissions." msgstr "" @@ -576,16 +604,16 @@ msgid "ADJ STATUS" msgstr "" #. ($c->{scoreRecordedMessage}[ $probOrder->[$i] ]) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:525 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:531 msgid "ANSWERS NOT RECORDED -- %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1453 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:535 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1394 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:541 msgid "ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1483 -msgid "ATTEMPT NOT ACCEPTED -- Please submit answers again (or request new version if neccessary)." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1424 +msgid "ATTEMPT NOT ACCEPTED -- Please submit answers again (or request new version if necessary)." msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/cancel_edit_form.html.ep:1 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/cancel_edit_form.html.ep:1 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/cancel_edit_form.html.ep:1 @@ -596,7 +624,15 @@ msgstr "" msgid "Abandon export" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:301 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:13 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:114 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:55 +msgid "Accommodation Time Factor" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:126 +msgid "Accomodation time factor for %1 unchanged. A value was given that is not a decimal number or is not greater than or equal to 1." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:308 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:13 msgid "Account Settings" msgstr "" @@ -604,7 +640,7 @@ msgstr "" msgid "Account Settings Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:453 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:303 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:445 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:302 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:305 msgid "Account creation is currently disabled in this course. Please speak to your instructor or system administrator." msgstr "" @@ -613,7 +649,7 @@ msgstr "" msgid "Account settings for %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:395 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:40 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:22 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:402 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:40 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:22 msgid "Accounts Manager" msgstr "" @@ -661,7 +697,7 @@ msgstr "" msgid "Achievement Notification Editor Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:540 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:542 msgid "Achievement Notification for %5" msgstr "" @@ -673,7 +709,7 @@ msgstr "" msgid "Achievement Points Per Problem in Reduced Scoring Period" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:27 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:46 msgid "Achievement Rewards" msgstr "" @@ -681,7 +717,7 @@ msgstr "" msgid "Achievement User Editor Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:535 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:537 msgid "Achievement Users for %5" msgstr "" @@ -714,7 +750,7 @@ msgstr "" msgid "Achievement scores saved to %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:312 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:319 msgid "Achievements" msgstr "" @@ -722,7 +758,7 @@ msgstr "" msgid "Achievements Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:319 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:326 msgid "Achievements Leaderboard" msgstr "" @@ -730,7 +766,7 @@ msgstr "" msgid "Achievements Leaderboard Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:523 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:48 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:525 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:53 msgid "Achievements Manager" msgstr "" @@ -739,7 +775,7 @@ msgid "Achievements Manager Help" msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:278 -msgid "Achievements are a way to gamify WeBWorK. In parallel to a student's regular scores on assignments, they earn \"achievement points\" for (a) answering an exercise correctly, and (b) earning badges. Badges can be for tasks like earning 100% on three assignments, answering five questions correclty on the first attempt, etc. As students earn achivement points, they can \"level up\" as well. An instructor can manage Achievents using the Achievements Manager tool." +msgid "Achievements are a way to gamify WeBWorK. In parallel to a student's regular scores on assignments, they earn \"achievement points\" for (a) answering an exercise correctly, and (b) earning badges. Badges can be for tasks like earning 100% on three assignments, answering five questions correctly on the first attempt, etc. As students earn achievement points, they can \"level up\" as well. An instructor can manage Achievements using the Achievements Manager tool." msgstr "" #: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementList.html.ep:11 @@ -754,25 +790,25 @@ msgstr "" msgid "Act" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/student_stats.html.ep:26 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep:23 msgid "Act as:" msgstr "" #. ($effectiveUserName) -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:26 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:28 msgid "Acting as %1." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:69 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:55 msgid "Action" msgstr "" #. ($actionID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/JobManager.pm:96 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:221 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:204 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/JobManager.pm:96 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:221 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:227 msgid "Action %1 not found" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:10 /opt/webwork/webwork2/templates/HelpFiles/InstructorJobManager.html.ep:47 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:136 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:10 /opt/webwork/webwork2/templates/HelpFiles/InstructorJobManager.html.ep:47 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:122 msgid "Actions:" msgstr "" @@ -793,11 +829,11 @@ msgstr "" msgid "Active Students Problem %1 Grades" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:66 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:163 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:249 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:703 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:166 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:66 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:163 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:249 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:704 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:166 msgid "Add" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:146 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:147 msgid "Add Additional User" msgstr "" @@ -805,7 +841,7 @@ msgstr "" msgid "Add All" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/admin_links.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:17 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:242 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:17 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/admin_links.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:17 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:243 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:17 msgid "Add Course" msgstr "" @@ -813,7 +849,7 @@ msgstr "" msgid "Add Course Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:428 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:168 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:435 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:168 msgid "Add Users" msgstr "" @@ -853,7 +889,7 @@ msgstr "" msgid "Add problems to" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:212 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:201 msgid "Add this problem as the last problem of an existing set, either as a problem or as the set header (the text that appears on the home page of a homework set). You can rearrange the order of the problems later using the \"Sets Manager\"." msgstr "" @@ -882,7 +918,7 @@ msgstr "" #. ($new_file_path, $setID, $targetProblemNumber) #. ($sourceFilePath, $targetSetName, ( $set->assignment_type eq 'jitar' ? join('.', jitar_id_to_seq($targetProblemNumber) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:905 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1977 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:905 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1958 msgid "Added %1 to %2 as problem %3" msgstr "" @@ -892,12 +928,12 @@ msgid "Added %1 to %2 as problem %3." msgstr "" #. (join(', ', @toAdd) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2085 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2086 msgid "Added addresses %1 to location %2." msgstr "" #. ($user->user_id) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:150 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:173 msgid "Added missing permission level for user %1." msgstr "" @@ -915,36 +951,36 @@ msgstr "" msgid "Additional (external) grades can be shown on this page by placing them in the CSV file %1. The first six columns must be (in order): Student ID, Username, Last Name, First Name, Section, Recitation. The remaining columns can list any external grades. To display the grades, the CSV file is merged with the \"Email\" message %2, which will be rendered and displayed below the grade table. The message can be created on the \"Email\" page and the CSV file can be created/uploaded using the \"File Manager\". External grades can only be displayed here and are not included in any totals or statistics." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:872 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:875 msgid "Additional addresses for receiving feedback email" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:233 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:248 msgid "Additional submissions available." msgstr "" #. ($badLocAddr) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1819 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1820 msgid "Address(es) %1 already exist in the database. THIS SHOULD NOT HAPPEN! Please double check the integrity of the WeBWorK database before continuing." msgstr "" #. (join(', ', @noAdd) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2097 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2098 msgid "Address(es) %1 in the add list is(are) already in the location %2, and so were skipped." msgstr "" #. (join(', ', @noDel) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2119 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2120 msgid "Address(es) %1 in the delete list is(are) not in the location %2, and so were skipped." msgstr "" #. ($badAddr) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1794 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1795 msgid "Address(es) %1 is(are) not in a recognized form. Please check your data entry and resubmit." msgstr "" #. ($badAddr) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2109 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2110 msgid "Address(es) %1 is(are) not in a recognized form. Please check your data entry and try again." msgstr "" @@ -988,7 +1024,7 @@ msgstr "" msgid "Adjusted Status Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:45 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:46 msgid "Adobe PDF" msgstr "" @@ -1000,27 +1036,31 @@ msgstr "" msgid "Advice on changing test dates" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:238 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:247 msgid "After Answer Date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:239 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:248 msgid "After Test Version Answer Date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:403 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:414 msgid "After a test version either has no more allowed graded submissions or has its time limit expired, you may configure whether or not to allow students to see the questions and the responses they gave." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:387 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:398 msgid "After a test version either has no more allowed graded submissions or has its time limit expired, you may configure whether or not to allow students to see their scores on that version." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:999 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:512 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:525 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:539 +msgid "After number of attempts is" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1002 msgid "After the answer date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:998 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1001 msgid "After the close date" msgstr "" @@ -1029,16 +1069,16 @@ msgstr "" msgid "After the due date this set enters a reduced scoring period until it closes on %1. All work completed during the reduced scoring period counts for %2% of its value." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:996 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:999 msgid "After the open date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:997 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1000 msgid "After the reduced scoring date" msgstr "" #. ($c->formatDateTime($set->due_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:157 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:149 msgid "Afterward reduced credit can be earned until %1." msgstr "" @@ -1062,7 +1102,7 @@ msgstr "" msgid "All Textbooks" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:55 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:56 msgid "All Users" msgstr "" @@ -1086,11 +1126,11 @@ msgstr "" msgid "All problems will be rerandomized." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2256 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2257 msgid "All selected courses are already hidden." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2325 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2326 msgid "All selected courses are already unhidden." msgstr "" @@ -1114,7 +1154,7 @@ msgstr "" msgid "All sets made visible for all students." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:99 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:112 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:97 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:111 msgid "All students" msgstr "" @@ -1126,7 +1166,7 @@ msgstr "" msgid "Allow Unicode alternatives in student answers" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1060 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1063 msgid "Allow the LMS to update user account data" msgstr "" @@ -1190,12 +1230,12 @@ msgstr "" msgid "Allowed to view usernames on the achievements leaderboard" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:67 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:69 msgid "Allows configuration of certain parameters, such as permission levels, default display mode for equations, and email feedback behavior, on a course by course basis." msgstr "" #. ($ce->{admin_course_id}) -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:140 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:141 msgid "Also add this user to the %1 course." msgstr "" @@ -1204,12 +1244,12 @@ msgid "Amulet of Extension" msgstr "" #. ($courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2426 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2427 msgid "An LMS context id is requested to be assigned to %1 which is set to use LTI 1.3, but that course is missing LTI 1.3 authentication parameters." msgstr "" #. ($courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2406 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2407 msgid "An LMS context id is requested to be assigned to %1, but that course is not configured to use LTI." msgstr "" @@ -1229,7 +1269,7 @@ msgstr "" msgid "An achievement evaluator is a perl script that is run after each problem is submitted which returns a truth value of 0 (didn't earn) or 1 (earn). The evaluator is given access to different variables which contain data about the problem and set that is used to determine if the achievement is earned or not." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:908 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:911 msgid "An address that can be used to log in to the LMS. This is used in messages to users that direct them to go back to the LMS to access something in the WeBWorK course." msgstr "" @@ -1238,7 +1278,7 @@ msgid "An array which lists the hash reference of all the problems in the curren msgstr "" #. ($_, $@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2490 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2491 msgid "An error occurred deleting mapping for %1: %2" msgstr "" @@ -1248,7 +1288,7 @@ msgid "An error occurred deletinglms_context_id: %1" msgstr "" #. ($_, $@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2487 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2488 msgid "An error occurred saving mapping for %1: %2" msgstr "" @@ -1258,7 +1298,7 @@ msgid "An error occurred saving the lms_context_id: %1" msgstr "" #. ($archive_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1039 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1040 msgid "An error occurred while archiving the course %1:" msgstr "" @@ -1269,12 +1309,12 @@ msgstr "" #. ($delete_courseID) #. ($archive_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1071 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:854 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1072 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:855 msgid "An error occurred while deleting the course %1:" msgstr "" #. ($rename_oldCourseID, $rename_newCourseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:727 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:728 msgid "An error occurred while renaming the course %1 to %2:" msgstr "" @@ -1288,7 +1328,7 @@ msgid "An error occurred while trying to send email: %1" msgstr "" #. ($unarchive_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1226 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1227 msgid "An error occurred while unarchiving the course %1:" msgstr "" @@ -1296,6 +1336,10 @@ msgstr "" msgid "An internal server error occured. Please contact the system administrator for assistance." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:37 +msgid "Analyze code with PG Critic" +msgstr "" + #. ($part + 1) #: /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:37 msgid "Answer %1 Score (%):" @@ -1305,7 +1349,7 @@ msgstr "" msgid "Answer Availability Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:345 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:51 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:77 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:345 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:24 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:51 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:77 msgid "Answer Date" msgstr "" @@ -1317,7 +1361,7 @@ msgstr "" msgid "Answer Hash Info" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:370 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:377 msgid "Answer Log" msgstr "" @@ -1333,11 +1377,19 @@ msgstr "" msgid "Answer availability for tests depends on multiple settings. This only indicates the template answer date has passed. See Set Detail page for actual availability." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:96 +msgid "Answer date" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:60 +msgid "Answer date:" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:810 msgid "Answer feedback will be available in problems when returning to a previously worked problem and after answers are available. Students will not need to click \"Submit Answers\" to make this feedback appear. Furthermore, the $showPartialCorrectAnswers variable set in some problems that prevents showing which of the answers are correct is ignored after the answer date." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1295 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1299 msgid "Answer(s) submitted:" msgstr "" @@ -1353,16 +1405,16 @@ msgstr "" msgid "Answers Available" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:137 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:146 msgid "Answers Available Date" msgstr "" #. ($c->formatDateTime($set->answer_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:203 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:172 msgid "Answers available for review on %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:205 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:174 msgid "Answers available for review." msgstr "" @@ -1371,7 +1423,7 @@ msgstr "" msgid "Answers cannot be made available until on or after the close date for set %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1400 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1383 msgid "Answers cannot be made available until on or after the close date." msgstr "" @@ -1379,15 +1431,15 @@ msgstr "" msgid "Any changes made below will be reflected in the achievement for ALL students." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:177 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:73 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:178 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:74 msgid "Any changes made below will be reflected in the set for ALL students." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:175 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:176 msgid "Any changes made below will be reflected in the set for ONLY the student(s) listed above." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:128 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:210 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:128 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:199 msgid "Append" msgstr "" @@ -1396,6 +1448,10 @@ msgstr "" msgid "Append to end of %1 set" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:46 +msgid "Apply to Selected Sets" +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/Levels.html.ep:36 msgid "Applying definitions theoretically and proof writing" msgstr "" @@ -1434,7 +1490,7 @@ msgstr "" msgid "Archive Type" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1110 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1111 msgid "Archive next course" msgstr "" @@ -1465,6 +1521,10 @@ msgstr "" msgid "Are you sure you want to delete the course %1? All course files and data will be destroyed. There is no undo available." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:731 +msgid "Are you sure you want to grade the test? Select \"No\" if you would like to return to the test to enter more answers." +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/InstructorScoring.html.ep:49 msgid "As the checkbox says, this includes a percentage grade column for each set." msgstr "" @@ -1477,7 +1537,7 @@ msgstr "" msgid "Assign" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:61 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:62 msgid "Assign All Sets to Current User" msgstr "" @@ -1485,7 +1545,7 @@ msgstr "" msgid "Assign achievements" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:28 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:34 msgid "Assign and unassign selected exercise sets to selected users." msgstr "" @@ -1493,7 +1553,7 @@ msgstr "" msgid "Assign selected sets to selected users" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:151 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:161 msgid "Assign sets to many students" msgstr "" @@ -1505,7 +1565,7 @@ msgstr "" msgid "Assign this achievement to which users?" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:60 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:64 msgid "Assign this set to which users?" msgstr "" @@ -1517,7 +1577,7 @@ msgstr "" msgid "Assign which achievements?" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:35 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:35 msgid "Assigned" msgstr "" @@ -1534,11 +1594,11 @@ msgid "Assigned achievements to users." msgstr "" #. (link_to( $c->setCountMessage($db->countUserSets($user->user_id) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:100 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:101 msgid "Assigned to %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:433 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:27 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:440 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:33 msgid "Assigner Tool" msgstr "" @@ -1546,7 +1606,7 @@ msgstr "" msgid "Assigner Tool Help" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:89 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:90 msgid "Assignment" msgstr "" @@ -1558,11 +1618,23 @@ msgstr "" msgid "Assignment Default" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:250 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/set_list_row.html.ep:27 +msgid "Assignment Description" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:259 msgid "Assignment Type" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:117 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:119 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:15 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:98 +msgid "Assignment type" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:62 +msgid "Assignment type:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:134 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:136 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:15 msgid "Assignments" msgstr "" @@ -1586,7 +1658,7 @@ msgstr "" msgid "Attachment:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:608 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:583 msgid "Attempt Threshold for Children" msgstr "" @@ -1594,27 +1666,39 @@ msgstr "" msgid "Attempt to upgrade directories and links" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1022 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:565 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1025 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:46 msgid "Attempted" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:36 +msgid "Attempted:" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail/attempts_row.html.ep:2 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:133 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:73 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:13 msgid "Attempts" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:102 +msgid "Attempts per version" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:64 +msgid "Attempts per version:" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/Localize.pm:70 msgid "Audit" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:303 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:309 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:247 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:253 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:302 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:308 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:248 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:254 msgid "Authentication failed. Please speak to your instructor." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/InstructorRPCHandler.pm:40 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm:49 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm:50 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/InstructorRPCHandler.pm:40 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm:69 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/RenderViaRPC.pm:70 msgid "Authentication failed. Log in again to continue." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:133 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:54 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:130 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:40 msgid "Author Info" msgstr "" @@ -1630,7 +1714,7 @@ msgstr "" msgid "Automatically render all problems in the set on this page when \"Save Changes\" or \"Reset Form\" is clicked." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:683 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:684 msgid "Automatically render problems on page load" msgstr "" @@ -1693,7 +1777,7 @@ msgstr "" msgid "Binary" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:413 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:424 msgid "Both Start and Grade" msgstr "" @@ -1709,11 +1793,11 @@ msgstr "" msgid "Browse from:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:883 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:886 msgid "By default, feedback is always sent to all users specified to receive feedback. This variable sets the system to only email feedback to users who have the same section as the user initiating the feedback. I.e., feedback will only be sent to section leaders." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:874 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:877 msgid "By default, feedback is sent to all users above who have permission to receive feedback. Feedback is also sent to any addresses specified here. Separate email address entries with commas." msgstr "" @@ -1729,7 +1813,7 @@ msgstr "" msgid "CLOSE TIME" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1463 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:531 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1404 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:537 msgid "CORRECT ANSWERS SHOWN ONLY -- ANSWERS NOT RECORDED" msgstr "" @@ -1788,7 +1872,7 @@ msgid "Can't delete archive \"%1\": %2" msgstr "" #. ($setID, $TargetUser->user_id,) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:937 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:941 msgid "Can't generate hardcopy for set \"%1\" for user \"%2\". The set is not visible to students." msgstr "" @@ -1818,7 +1902,7 @@ msgstr "" #. ($fullPath) #. ($!) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm:236 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1959 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/FileManager.pm:236 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1940 msgid "Can't write to file %1" msgstr "" @@ -1867,11 +1951,11 @@ msgstr "" msgid "Cannot open %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:288 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:299 msgid "Cap Test Time at Close Date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/PODViewer.pm:47 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:51 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/PODViewer.pm:47 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:47 msgid "Categories" msgstr "" @@ -1916,7 +2000,7 @@ msgstr "" msgid "Change course institution from %1 to %2" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:157 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:167 msgid "Change dates for a set for the whole class." msgstr "" @@ -1932,11 +2016,11 @@ msgstr "" msgid "Change the grades on an assignment for one student." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:160 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:170 msgid "Change the grading on a set for an entire class." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:167 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:177 msgid "Change the number of atttempts allowed on a problem." msgstr "" @@ -1946,11 +2030,11 @@ msgid "Change title from %1 to %2" msgstr "" #. ($fieldInfo{$key}[1], $fieldInfo{$key}[2]) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2879 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2880 msgid "Change type of field from %1 to %2 when upgrading" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:558 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:613 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:502 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:558 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:613 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:525 msgid "Changes abandoned." msgstr "" @@ -1958,7 +2042,7 @@ msgstr "" msgid "Changes in this file have not yet been permanently saved." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:593 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Config.pm:88 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:702 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:564 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:593 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Config.pm:88 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:691 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:594 msgid "Changes saved." msgstr "" @@ -1974,24 +2058,28 @@ msgstr "" msgid "Chapter:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:25 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:34 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:117 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:37 +#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:25 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:34 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:121 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:37 msgid "Check Answers" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:677 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:693 msgid "Check Test" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:946 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:949 msgid "Check a score in the LMS actually needs updating before updating it" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:44 +#: /opt/webwork/webwork2/templates/layouts/system.html.ep:73 /opt/webwork/webwork2/templates/layouts/system.html.ep:78 +msgid "Choose Color Scheme" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:45 msgid "Choose Sample Problem" msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:216 -msgid "Choose a layout/styling theme for PDF hardcopy production from the Prooblem Editor." +msgid "Choose a layout/styling theme for PDF hardcopy production from the Problem Editor." msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:208 @@ -2030,6 +2118,10 @@ msgstr "" msgid "Choose problems from a library and add them to a set." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:18 +msgid "Choose set date type" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/publish_form.html.ep:14 msgid "Choose visibility of the sets to be affected" msgstr "" @@ -2054,7 +2146,7 @@ msgstr "" msgid "Clean course after unarchiving (remove student users, scoring files, log files, temporary edited files)" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:39 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:46 msgid "Clear" msgstr "" @@ -2062,15 +2154,15 @@ msgstr "" msgid "Clear Problem Display" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:123 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:124 msgid "Click a student's name to see the student's homework set. Click a heading to sort the table." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:115 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:116 msgid "Click a student's name to see the student's test summary page. Click a test's version number to see the corresponding test version. Click a heading to sort the table." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:147 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:157 msgid "Click first in the \"Assigned Sets\" column in the student's row. This will take you to a new page where you will click on the link to the assignment where the grade change is to be made." msgstr "" @@ -2082,6 +2174,10 @@ msgstr "" msgid "Click on each of the tabs to view the configuration items. The question mark icon provides access to information about the behavior of the configuration settings." msgstr "" +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:147 +msgid "Click on the \"Select\" checkbox next to the names of the students that additional time is to be assigned, click on the radio button for editing selected users, and then click the \"Edit\" button. Set the \"Accommodation Time Factor\" to the desired multiplier for each student selected (this must be a decimal number that is greater than or equal to 1). The time that a student will have to complete a timed test will be the product of the \"Test Time Limit\" for the test set in the \"Sets Manager\" and the \"Accommodation Time Factor\" set here." +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:122 msgid "Click on the column \"Assigned Sets\" in the student's row. This will take you to a page where you can assign and unassign sets and change the due dates for homework on an individual basis." msgstr "" @@ -2090,7 +2186,7 @@ msgstr "" msgid "Click on the homework set links to edit the grades for this individual student on the homework set. (The grade of each problem is called the \"status\".) You can also change the number of allowed attempts and further modify the individual student's homework set.) You will also be able to change a student's seed which determines the individual values used in the individual version of the student's problem and the weight (how much a problem counts toward the grade.)" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList.html.ep:94 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList.html.ep:99 msgid "Click on the login name to edit individual problem set data, (e.g. due dates) for these students." msgstr "" @@ -2108,7 +2204,7 @@ msgid "Click the \"Use score from last check\" button to set the problem score t msgstr "" #. ('') -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:5 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:73 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:5 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:75 msgid "Click the %1 icon for page and item specific help." msgstr "" @@ -2117,7 +2213,7 @@ msgstr "" msgid "Click the icon %1 for page and item specific help." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:182 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:192 msgid "Clicking on any active link at the top of the column sorts the page by that column. You can do lexigraphic sorts: click on \"First name\" then \"Last name\" to sort by last name, sorting those with the same last name by their first name." msgstr "" @@ -2125,7 +2221,7 @@ msgstr "" msgid "Clicking on the login name link in a student's row allows you to view the student's version of the homework (rather than your own) so that you can more easily answer student questions about homework problems. (A \"acting as xxx\" alert will appear in the upper right corner of each window while you are acting as a student.) You can submit the answers (which will NOT be recorded) to check that the computer is grading the problem correctly. You will also be able to view past answers submitted by the student for each problem. To stop acting in the student's role click the \"Stop acting\" link in the upper right corner of the window." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:196 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:206 msgid "Clicking the email address link will bring up your standard email application so that you can send email to the student. This works even if the student has been dropped from the course. To send email to an entire class or to merge grades with the email message use the \"Email\" page link in the left margin." msgstr "" @@ -2134,18 +2230,32 @@ msgid "Client ID" msgstr "" #. ($clientIP->ip() -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:534 +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:565 +msgid "Client ip address %1 is in the list of addresses from which this assignment may not be worked." +msgstr "" + +#. ($clientIP->ip() +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:536 msgid "Client ip address %1 is not allowed to work this assignment, because the assignment has ip address restrictions and there are no allowed locations associated with the restriction. Contact your professor to have this problem resolved." msgstr "" +#. ($clientIP->ip() +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:561 +msgid "Client ip address %1 is not in the list of addresses from which this assignment may be worked." +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:40 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager.html.ep:202 msgid "Close" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:124 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:344 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:9 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:50 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:73 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:39 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:133 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:344 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:23 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:9 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:50 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:73 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:39 msgid "Close Date" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:95 +msgid "Close date" +msgstr "" + #. ($c->formatDateTime($set->due_date, $ce->{studentDateDisplayFormat}) #. ($c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat}) #: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/ExtendDueDate.pm:72 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/ReducedCred.pm:93 @@ -2170,12 +2280,12 @@ msgstr "" msgid "Closed" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:280 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:295 msgid "Closed." msgstr "" #. ($c->formatDateTime($verSet->due_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:225 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:240 msgid "Closes on %1" msgstr "" @@ -2183,19 +2293,23 @@ msgstr "" msgid "Closes:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:371 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:54 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:125 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:150 +msgid "Code Maintenance" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:372 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:54 msgid "Collapse All Details" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:381 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:68 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:382 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:68 msgid "Collapse All Nesting" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:440 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:441 msgid "Collapse Nested Problems" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:586 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:589 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:587 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:590 msgid "Collapse Problem Details" msgstr "" @@ -2207,11 +2321,11 @@ msgstr "" msgid "Comma separated list of set names that are excluded from all achievements. No achievement points and badges can be earned for submitting problems in these sets. Note that underscores (_) must be used for spaces in set names." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm:202 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:111 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:126 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:65 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:71 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm:202 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:134 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:170 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:126 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:68 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:72 msgid "Comment" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:25 /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:249 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:101 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:25 /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:249 msgid "Comment:" msgstr "" @@ -2228,15 +2342,15 @@ msgid "Complete Code" msgstr "" #. ($c->formatDateTime($c->{set}->answer_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:398 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:381 msgid "Completed results for this assignment are not available until %1." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:401 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:384 msgid "Completed results for this assignment are not available." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:262 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:278 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:277 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:293 msgid "Completed." msgstr "" @@ -2244,7 +2358,7 @@ msgstr "" msgid "Compose Email Message" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1006 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1009 msgid "Condition under which scores will be sent early to an LMS" msgstr "" @@ -2298,6 +2412,10 @@ msgstr "" msgid "Confirm which sets to export." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep:8 +msgid "Congratulations! No PG critic violations found." +msgstr "" + #: /opt/webwork/webwork2/templates/AchievementEvaluator/cheevoMessage.html.ep:15 msgid "Congratulations, you earned a new level!" msgstr "" @@ -2310,15 +2428,15 @@ msgstr "" msgid "Contact the site administrator to ensure that the permissions are set so that the web server can write to this file." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:188 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:215 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:189 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:216 msgid "Content Selection" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:60 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:160 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:60 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:162 msgid "Context ID" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:59 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:156 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:59 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:158 msgid "Context Title" msgstr "" @@ -2326,11 +2444,11 @@ msgstr "" msgid "Contexts" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2742 /opt/webwork/webwork2/templates/ContentGenerator/Login.html.ep:72 /opt/webwork/webwork2/templates/ContentGenerator/LoginProctor.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/TwoFactorAuthentication.html.ep:56 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2743 /opt/webwork/webwork2/templates/ContentGenerator/Login.html.ep:72 /opt/webwork/webwork2/templates/ContentGenerator/LoginProctor.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/TwoFactorAuthentication.html.ep:56 msgid "Continue" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:86 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:83 msgid "Continue Open Test" msgstr "" @@ -2338,7 +2456,7 @@ msgstr "" msgid "Controls if an achievement is evaluated or not." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep:21 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:21 msgid "Convert the code to PGML" msgstr "" @@ -2351,7 +2469,7 @@ msgstr "" msgid "Copy" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:157 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:158 msgid "Copy Components From:" msgstr "" @@ -2371,7 +2489,7 @@ msgstr "" msgid "Copy Single Secret" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:169 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:170 msgid "Copy These Components:" msgstr "" @@ -2387,7 +2505,7 @@ msgstr "" msgid "Copy to (Course ID / User ID)" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:224 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:225 msgid "Copying the course configuration file may copy configuration settings that are specific to the original course instructor. If this is a new course for a new instructor, use the fields above to add the new instructor and do not copy the course configuration file. Then if there is something in the course configuration file that should be carried into the new course, the administrator can copy that manually. Alternatively, do copy the course configuration file, but then the administrator should inspect the new course configuration file and make adjustments for the new instructor." msgstr "" @@ -2395,19 +2513,19 @@ msgstr "" msgid "Core" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:581 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:320 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:301 msgid "Correct" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:648 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:647 msgid "Correct Adjusted Status" msgstr "" -#: /opt/webwork/webwork2/lib/HardcopyRenderedProblem.pm:247 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1339 +#: /opt/webwork/webwork2/lib/HardcopyRenderedProblem.pm:247 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1343 msgid "Correct Answers:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:663 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:662 msgid "Correct Status" msgstr "" @@ -2415,13 +2533,17 @@ msgstr "" msgid "Correct answers" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:47 +msgid "Correct attempts" +msgstr "" + #. ($total_correct, $num_of_problems) #: /opt/webwork/webwork2/templates/ContentGenerator/Problem/siblings.html.ep:17 msgid "Correct: %1/%2" msgstr "" #. ($newBlankProblems, $MAX_NEW_PROBLEMS) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1983 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1964 msgid "Could not add %1 problems to this set. The number must be between 1 and %2" msgstr "" @@ -2447,15 +2569,15 @@ msgstr "" msgid "Counter:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:624 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:36 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:598 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:36 msgid "Counts for Parent" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:941 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:944 msgid "Course" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:163 /opt/webwork/webwork2/templates/ContentGenerator/Home.html.ep:10 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:164 /opt/webwork/webwork2/templates/ContentGenerator/Home.html.ep:10 msgid "Course Administration" msgstr "" @@ -2463,7 +2585,7 @@ msgstr "" msgid "Course Administration Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:448 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:65 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:455 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:67 msgid "Course Configuration" msgstr "" @@ -2471,7 +2593,7 @@ msgstr "" msgid "Course Configuration Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:502 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:517 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:534 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:512 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:525 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:539 msgid "Course Default" msgstr "" @@ -2484,7 +2606,7 @@ msgid "Course ID" msgstr "" #. ($ce->{maxCourseIdLength}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1175 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:264 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:570 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1176 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:264 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:570 msgid "Course ID cannot exceed %1 characters." msgstr "" @@ -2493,7 +2615,7 @@ msgstr "" msgid "Course ID may contain only letters, numbers, hyphens, and underscores, and may have at most %1 characters." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1179 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:258 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:573 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1180 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:258 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:573 msgid "Course ID may only contain letters, numbers, hyphens, and underscores." msgstr "" @@ -2558,7 +2680,7 @@ msgstr "" msgid "Create Location:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:657 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:659 msgid "Create New Test Version" msgstr "" @@ -2630,7 +2752,43 @@ msgstr "" msgid "Currently defined locations are listed below." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2895 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:87 +msgid "Data about the assignment" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:53 +msgid "Data about the assignment:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:186 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:106 +msgid "Data about the environment" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:35 +msgid "Data about the problem" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:126 +msgid "Data about the problem processor" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:75 +msgid "Data about the problem processor:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:28 +msgid "Data about the problem:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:152 +msgid "Data about the user" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:85 +msgid "Data about the user:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2896 msgid "Database tables are ok" msgstr "" @@ -2642,19 +2800,19 @@ msgstr "" msgid "Database tables ok." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1370 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1555 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1371 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1556 msgid "Database:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:182 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:183 msgid "Date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:980 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:983 msgid "Date after which scores will be sent to the LMS" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:91 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:92 msgid "Dates" msgstr "" @@ -2662,7 +2820,7 @@ msgstr "" msgid "Dates for problem sets can be edited by clicking the pencil icon in the \"Set Name\" column next to the set name. To change dates for several sets at once, click the check box in the \"Select\" column and choose \"Edit selected\" from the tasks above." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:855 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:858 msgid "Debug" msgstr "" @@ -2735,11 +2893,11 @@ msgstr "" msgid "Delete course:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2850 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2851 msgid "Delete field when upgrading" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:601 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:602 msgid "Delete it?" msgstr "" @@ -2767,7 +2925,7 @@ msgstr "" msgid "Delete selected users?" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2815 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2816 msgid "Delete table when upgrading" msgstr "" @@ -2786,7 +2944,7 @@ msgid "Deleted %1 sets." msgstr "" #. ($num) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:357 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:381 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:380 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:404 msgid "Deleted %1 users." msgstr "" @@ -2802,12 +2960,12 @@ msgid "Deleted %quant(%1,job)." msgstr "" #. (join(', ', @delLocations) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1921 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1922 msgid "Deleted Location(s): %1" msgstr "" #. (join(', ', @toDel) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2077 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2078 msgid "Deleted addresses %1 from location." msgstr "" @@ -2839,7 +2997,7 @@ msgstr "" msgid "Deletion destroys all achievement-related data and is not undoable!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:221 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:230 msgid "Deny From" msgstr "" @@ -2855,7 +3013,7 @@ msgstr "" msgid "Descending" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:104 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_location_form.html.ep:116 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/edit_table.html.ep:27 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:113 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_location_form.html.ep:116 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/edit_table.html.ep:27 msgid "Description" msgstr "" @@ -2863,7 +3021,7 @@ msgstr "" msgid "Description:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:241 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:238 msgid "Deselect All Test Versions" msgstr "" @@ -2879,19 +3037,19 @@ msgstr "" msgid "Destination User ID" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2586 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2587 msgid "Destination course ID missing." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2605 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2606 msgid "Destination course must be different than source course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2587 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2687 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2588 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2688 msgid "Destination user ID missing." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2601 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2602 msgid "Destination user must be different than source user when copying from same course" msgstr "" @@ -2921,11 +3079,11 @@ msgstr "" msgid "Directory permission errors" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1463 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1647 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:74 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:74 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1464 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1648 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:74 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:74 msgid "Directory structure is missing directories or the webserver lacks sufficient privileges." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1458 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1642 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:71 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:71 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1459 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1643 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:71 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:71 msgid "Directory structure is ok" msgstr "" @@ -2933,7 +3091,7 @@ msgstr "" msgid "Directory structure or permissions need to be repaired." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1438 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1612 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1439 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1613 msgid "Directory structure:" msgstr "" @@ -2954,19 +3112,19 @@ msgstr "" msgid "Disabled" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:267 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:293 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:268 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:294 msgid "Dismiss" msgstr "" -#: /opt/webwork/webwork2/templates/layouts/system.html.ep:154 +#: /opt/webwork/webwork2/templates/layouts/system.html.ep:198 msgid "Dismiss All Messages" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:75 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:132 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:75 msgid "Display Mode" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:386 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/view_problems_line.html.ep:7 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_stats.html.ep:121 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:77 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:387 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/view_problems_line.html.ep:7 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_stats.html.ep:121 msgid "Display Mode:" msgstr "" @@ -2982,10 +3140,14 @@ msgstr "" msgid "Display all possible records" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:29 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:33 msgid "Display choice" msgstr "" +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorStats.html.ep:5 +msgid "Display full set or problem statistics. The main page lists all sets to view. When viewing set statistics, the drop down menus can be used to show stats for individual sections, recitations, or problems. The overall results include all students who are assigned to the set, while the individual problem results only include active (have attempted the problem) students." +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:37 msgid "Display mode for equations" msgstr "" @@ -2994,7 +3156,7 @@ msgstr "" msgid "Display of scores for this test is not allowed." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:41 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:42 msgid "Display options: Show" msgstr "" @@ -3015,7 +3177,7 @@ msgstr "" msgid "Do not unassign students unless you know what you are doing." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:66 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:67 msgid "Do not uncheck a set unless you know what you are doing." msgstr "" @@ -3023,7 +3185,7 @@ msgstr "" msgid "Do not uncheck students, unless you know what you are doing." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:689 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:705 msgid "Do you want to grade this test?" msgstr "" @@ -3031,7 +3193,7 @@ msgstr "" msgid "Documentation" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:118 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:117 msgid "Documentation from source code for PG modules and macro files." msgstr "" @@ -3068,7 +3230,7 @@ msgstr "" msgid "Don't use in an achievement" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1706 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:907 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:45 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:67 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1707 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:865 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:49 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:33 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:67 msgid "Done" msgstr "" @@ -3078,15 +3240,15 @@ msgstr "" #. (tag('span', dir => 'ltr', $display_name) #. ($ver->{id} =~ s/_/ /gr) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:213 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:215 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/set_list_row.html.ep:48 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:210 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:212 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/set_list_row.html.ep:47 msgid "Download %1" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy.html.ep:23 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:74 +#: /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy.html.ep:23 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:98 msgid "Download Hardcopy" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:245 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:242 msgid "Download Hardcopy for Selected Tests" msgstr "" @@ -3121,19 +3283,23 @@ msgid "Drop student from the course" msgstr "" #. ($beginReducedScoringPeriod) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:162 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:154 msgid "Due date %1 has passed." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:829 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:59 +msgid "Due date:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:830 msgid "E-Mail" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:231 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:228 msgid "E-mail Instructor" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:845 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:848 msgid "E-mail verbosity level" msgstr "" @@ -3145,7 +3311,7 @@ msgstr "" msgid "Earned" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1200 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1217 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:48 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:85 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:63 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1060 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:53 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:46 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/view.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:117 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:126 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:136 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:206 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:240 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:260 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:501 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:225 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/info.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/info.html.ep:6 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetList.html.ep:41 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1204 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1221 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:48 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:85 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:63 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:989 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:53 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:46 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/view.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:117 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:126 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:136 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:206 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:240 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:261 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:502 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:225 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/info.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets/info.html.ep:6 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetList.html.ep:41 msgid "Edit" msgstr "" @@ -3155,12 +3321,12 @@ msgid "Edit %1" msgstr "" #. ($link, $userName, $userID, scalar(keys %{ $c->{userSetRecords} }) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:53 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:54 msgid "Edit %1 for %2 (%3) who has been assigned %4 sets." msgstr "" #. ($link, tag('span', dir => 'ltr', format_set_name_display($setID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:167 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:168 msgid "Edit %1 for set %2." msgstr "" @@ -3176,7 +3342,7 @@ msgstr "" msgid "Edit Evaluator" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:255 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:256 msgid "Edit Header" msgstr "" @@ -3184,7 +3350,7 @@ msgstr "" msgid "Edit Location:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:497 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_stats.html.ep:128 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:498 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_stats.html.ep:128 msgid "Edit Problem" msgstr "" @@ -3192,11 +3358,11 @@ msgstr "" msgid "Edit Selected Theme" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep:47 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep:51 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep:48 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep:52 msgid "Edit Set Data" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1088 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:171 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1017 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:171 msgid "Edit Tags" msgstr "" @@ -3212,7 +3378,7 @@ msgstr "" msgid "Edit achievement information" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:50 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:55 msgid "Edit achivements for the course. This link is only present if achievements are enabled for the course." msgstr "" @@ -3234,16 +3400,16 @@ msgid "Edit it" msgstr "" #. (tag('strong', dir => 'ltr', format_set_name_display($setID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:139 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:140 msgid "Edit set %1 for ALL students assigned to this set." msgstr "" #. (link_to( $setID => $c->systemLink( $setDetailPage, params => { editForUser => $user->user_id }) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:110 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:111 msgid "Edit set %1 for this user." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:31 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:29 msgid "Edit sets for the entire class. Change set due dates, create new sets from a set definition file, create new sets, make sets visible/invisible, score assignments. Assign sets to the class." msgstr "" @@ -3321,7 +3487,7 @@ msgstr "" msgid "Editing all sets." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:348 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:371 msgid "Editing all users." msgstr "" @@ -3339,7 +3505,7 @@ msgid "Editing location %1" msgstr "" #. (tag( 'strong', dir => 'ltr', format_set_name_display($setID . ($editingSetVersion ? ",v$editingSetVersion" : '') -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:127 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:128 msgid "Editing problem set %1 for these students: %2" msgstr "" @@ -3351,7 +3517,7 @@ msgstr "" msgid "Editing selected sets." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:348 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:371 msgid "Editing selected users." msgstr "" @@ -3359,11 +3525,11 @@ msgstr "" msgid "Editor" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:480 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:154 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:172 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:13 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:44 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:53 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:487 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:158 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:154 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:173 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:14 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:44 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:58 msgid "Email" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:106 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:133 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:86 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:96 /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:25 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:110 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:134 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:86 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:96 /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:25 msgid "Email Address" msgstr "" @@ -3375,7 +3541,7 @@ msgstr "" msgid "Email Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:440 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:451 msgid "Email Instructor On Failed Attempt" msgstr "" @@ -3404,7 +3570,7 @@ msgstr "" msgid "Email is being sent to %quant(%1,recipient). This job may take several minutes to complete if the class is large. Go to the \"Job Manager\" to see the status of this job." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:13 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:89 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:13 msgid "Email:" msgstr "" @@ -3444,11 +3610,11 @@ msgstr "" msgid "Enable Show Me Another button" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:122 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:108 msgid "Enable Spell Checking" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:77 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:63 msgid "Enable or disable tab-focus mode. When tab-focus mode is off, pressing Tab inside the editor window indents the current line. When tab-focus mode is on Tab and Shift-Tab move focus out of the editor window." msgstr "" @@ -3484,7 +3650,7 @@ msgstr "" msgid "Enables use of the Show Me Another button, which offers the student a newly-seeded version of the current problem, complete with solution (if it exists for that problem)." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:173 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:170 msgid "End" msgstr "" @@ -3496,7 +3662,7 @@ msgstr "" msgid "Enrolled, Drop, etc." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:108 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:88 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:112 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:88 msgid "Enrollment Status" msgstr "" @@ -3531,11 +3697,11 @@ msgid "Enter one of the allowed display mode types above. See 'display modes ent msgstr "" #. ($display_sort_method_name{$primary_sort_method}) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:139 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:140 msgid "Entries are sorted by %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:325 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:332 msgid "Equation Display" msgstr "" @@ -3548,7 +3714,7 @@ msgid "Error adding IP restriction location \"%1\" for set %2: %3" msgstr "" #. ($@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1604 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1585 msgid "Error adding set-level proctor: %1" msgstr "" @@ -3561,12 +3727,12 @@ msgstr "" msgid "Error creating set %1: %2" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:14 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:16 msgid "Error details" msgstr "" #. ($@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:281 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:287 msgid "Error encoding JWT: %1" msgstr "" @@ -3576,12 +3742,12 @@ msgid "Error generating POD for file %1: %2" msgstr "" #. ($@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1580 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1561 msgid "Error getting old set-proctor password from the database: %1. No update to the password was done." msgstr "" #. ($err) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:221 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:227 msgid "Error loading or generating site keys: %1" msgstr "" @@ -3589,7 +3755,7 @@ msgstr "" msgid "Error message:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:12 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:14 msgid "Error messages" msgstr "" @@ -3598,33 +3764,18 @@ msgstr "" msgid "Error sending email to %1: %2" msgstr "" -#. ($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:654 -msgid "Error: Answer date cannot be more than 10 years from now in set %1." -msgstr "" - -#. ($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:663 -msgid "Error: Answer date must come after close date in set %1." -msgstr "" - #. ($setID) #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:652 -msgid "Error: Close date cannot be more than 10 years from now in set %1." +msgid "Error: Answer date must come after close date in set %1." msgstr "" #. ($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:660 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:649 msgid "Error: Close date must come after open date in set %1." msgstr "" #. ($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:650 -msgid "Error: Open date cannot be more than 10 years from now in set %1." -msgstr "" - -#. ($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:685 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:674 msgid "Error: Reduced scoring date must come between the open date and close date in set %1." msgstr "" @@ -3638,7 +3789,7 @@ msgid "Error: no file data was submitted!" msgstr "" #. ($problem_desc, $problem_name, $c->tag('br') -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1224 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1228 msgid "Errors encountered while processing %1. This %2 has been omitted from the hardcopy. Error text: %3" msgstr "" @@ -3647,12 +3798,12 @@ msgid "Errors occurred while generating hardcopy:" msgstr "" #. ("$ce->{webworkDirs}{courses}/$failed_courses[0]/") -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2239 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2240 msgid "Errors occurred while hiding the courses listed below when attempting to create the file hide_directory in the course's directory. Check the ownership and permissions of the course's directory, e.g \"%1\"." msgstr "" #. ("$ce->{webworkDirs}{courses}/$failed_courses[0]/") -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2308 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2309 msgid "Errors occurred while unhiding the courses listed below when attempting delete the file hide_directory in the course's directory. Check the ownership and permissions of the course's directory, e.g \"%1\"." msgstr "" @@ -3672,11 +3823,11 @@ msgstr "" msgid "Evaluator Variables" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2254 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2255 msgid "Except for the errors listed above, all selected courses are already hidden." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2323 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2324 msgid "Except for the errors listed above, all selected courses are already unhidden." msgstr "" @@ -3688,19 +3839,19 @@ msgstr "" msgid "Existing file %1 could not be backed up." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:368 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:48 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:369 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:48 msgid "Expand All Details" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:378 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:61 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:379 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:61 msgid "Expand All Nesting" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:439 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:440 msgid "Expand Nested Problems" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:588 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:589 msgid "Expand Problem Details" msgstr "" @@ -3773,7 +3924,7 @@ msgstr "" msgid "Extend the close date of this test to %1 (an additional 24 hours)." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:145 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:155 msgid "Extend the number of attempts allowed a student on a given problem." msgstr "" @@ -3855,17 +4006,17 @@ msgid "Failed to open %1." msgstr "" #. ($file, $@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1244 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1245 msgid "Failed to remove file %1: %2" msgstr "" #. ($@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1249 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1250 msgid "Failed to remove scoring files: %1" msgstr "" #. ($@) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1254 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1255 msgid "Failed to remove temporary edited files: %1" msgstr "" @@ -3875,7 +4026,7 @@ msgid "Failed to save: %1" msgstr "" #. (ref($_) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:223 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:220 msgid "Failed to send message: %1" msgstr "" @@ -3891,23 +4042,32 @@ msgstr "" msgid "Features:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:330 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:337 msgid "Feedback" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:881 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:884 msgid "Feedback by Section." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2776 +#. (format_set_name_display($set->set_id) +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:8 +msgid "Feedback sent from %1:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:12 +msgid "Feedback sent from:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2777 msgid "Field is ok" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2778 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2779 msgid "Field missing in database" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2780 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2781 msgid "Field missing in schema" msgstr "" @@ -3937,7 +4097,7 @@ msgid "File \"%1\" uploaded successfully" msgstr "" #. ($ce->{courseDirs}{templates}, $fileName) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:619 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:649 msgid "File %1/%2 either does not exist or is not readable." msgstr "" @@ -3951,7 +4111,7 @@ msgstr "" msgid "File %1 is protected and cannot be overwritten. Rename it as:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:443 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:46 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:55 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:450 /opt/webwork/webwork2/templates/HelpFiles/admin_links.html.ep:46 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:62 msgid "File Manager" msgstr "" @@ -3959,7 +4119,7 @@ msgstr "" msgid "File Manager Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:39 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:35 msgid "File not found." msgstr "" @@ -3989,7 +4149,7 @@ msgstr "" msgid "File successfully renamed" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:19 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:20 msgid "File:" msgstr "" @@ -4019,12 +4179,12 @@ msgid "Filter achievements" msgstr "" #. ($recitation) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1391 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:872 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1389 /opt/webwork/webwork2/lib/WeBWorK/HTML/StudentNav.pm:44 msgid "Filter by recitation %1" msgstr "" #. ($section) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1387 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:869 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1385 /opt/webwork/webwork2/lib/WeBWorK/HTML/StudentNav.pm:41 msgid "Filter by section %1" msgstr "" @@ -4044,11 +4204,11 @@ msgstr "" msgid "Finished" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:166 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:167 msgid "First" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:104 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:119 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:65 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:84 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:28 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:108 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:120 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:65 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:84 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:28 msgid "First Name" msgstr "" @@ -4056,31 +4216,31 @@ msgstr "" msgid "First name" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:94 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:80 msgid "Fold all regions." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:85 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:71 msgid "Fold the region that begins on the current line. Triangles in the gutter next to line numbers indicate which regions can be folded." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:86 -msgid "For many macros, this lists all sample problems used by the macro." +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:94 +msgid "For many macros, this lists all sample problems that use the macro." msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm:160 msgid "For security reasons, you cannot specify a message file from a directory higher than the email directory (you can't use ../blah/blah for example). Please specify a different file or move the needed file to the email directory." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:127 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:113 msgid "Force RTL" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:690 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:84 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:691 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:84 msgid "Force problems to be numbered consecutively from one" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:129 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:115 msgid "Force the editor to display text from right-to-left. (Note that this does not persist when reloading the page.)" msgstr "" @@ -4092,12 +4252,8 @@ msgstr "" msgid "Format" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:125 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:164 -msgid "Format Code" -msgstr "" - -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:832 -msgid "Format for the subject line in feedback emails" +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:833 +msgid "Format for the subject of feedback emails" msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:110 @@ -4117,14 +4273,14 @@ msgid "From field must contain a single valid email address." msgstr "" #: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:5 -msgid "From this page you can add new students, edit user data (name, email address, recitation, section, permission level, enrollment status, and password), and export (save) class lists for back-up or use in another course. You can also delete students from the class roster, but this cannot be undone." +msgid "From this page you can add new students, edit user data (name, email address, student ID, enrollment status, accommodation time factor, section, recitation, comment, permission level, and password), and export (save) class lists for back-up or use in another course. You can also delete students from the class roster, but this cannot be undone." msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/Feedback.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:34 msgid "From:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:33 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:37 msgid "Future Assignments" msgstr "" @@ -4144,7 +4300,7 @@ msgstr "" msgid "General Page Information" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:702 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:720 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:669 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:687 msgid "General Parameters" msgstr "" @@ -4152,11 +4308,11 @@ msgstr "" msgid "Generate" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:124 /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy/form.html.ep:183 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:176 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:177 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:148 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:124 /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy/form.html.ep:183 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:173 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:174 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:134 msgid "Generate Hardcopy" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:151 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:137 msgid "Generate a hardcopy of the problem being edited. This does not change the permanent file on the disk. You can generate a hardcopy for different versions of the same problem by changing the seed. You can also change the format to \"PDF\" or \"TeX Source\". If \"PDF\" is selected, then a PDF file will be generated for download, unless there are errors. If errors occur or \"TeX Source\" is selected, then a zip file will be generated for download that contains the TeX source file and resources needed for generating the PDF file using LaTeX." msgstr "" @@ -4168,6 +4324,10 @@ msgstr "" msgid "Generate hardcopy for selected sets and selected users" msgstr "" +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:145 +msgid "Give one student or several students additional time for all timed tests." +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/FullCreditProb.pm:13 msgid "Gives full credit on a single homework problem." msgstr "" @@ -4193,21 +4353,21 @@ msgid "Global data on problem usage is contributed by many institutions using We msgstr "" #. ($problemID, $setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1633 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1614 msgid "Global problem %1 for set %2 not found." msgstr "" #. ($c->{prettyID}, $c->stash('setID') -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:346 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:344 msgid "Global problem %1 not found for set %2." msgstr "" #. ($c->stash('setID') -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:110 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:340 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:108 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:338 msgid "Global set %1 not found." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:81 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:82 msgid "Global set data will be shown instead of user specific data" msgstr "" @@ -4215,20 +4375,20 @@ msgstr "" msgid "Go" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:568 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:569 msgid "Grade" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:564 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:80 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:565 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:80 msgid "Grade Problem" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:684 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:700 msgid "Grade Test" msgstr "" #. ($effectiveUserID) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:684 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:700 msgid "Grade Test for %1" msgstr "" @@ -4236,11 +4396,11 @@ msgstr "" msgid "Grade of Active Students" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:926 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:929 msgid "Grade passback mode" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:302 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:313 msgid "Graded Submissions per Version" msgstr "" @@ -4248,7 +4408,7 @@ msgstr "" msgid "Grader" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:307 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:314 msgid "Grades" msgstr "" @@ -4256,7 +4416,7 @@ msgstr "" msgid "Grades Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm:97 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm:98 msgid "Grades have been saved for all current users." msgstr "" @@ -4292,7 +4452,7 @@ msgstr "" msgid "Guest:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:33 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:36 msgid "HTTP Headers" msgstr "" @@ -4308,11 +4468,11 @@ msgstr "" msgid "Hardcopy Format:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:357 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:363 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:364 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:370 msgid "Hardcopy Generator" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:96 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:105 msgid "Hardcopy Header" msgstr "" @@ -4337,11 +4497,19 @@ msgstr "" msgid "Hardcopy Theme:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:231 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:16 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:93 +msgid "Hardcopy header file" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:57 +msgid "Hardcopy header file:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:232 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:16 msgid "Headers" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/admin_links.html.ep:54 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:372 /opt/webwork/webwork2/templates/layouts/help_macro.html.ep:6 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/admin_links.html.ep:54 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:348 /opt/webwork/webwork2/templates/layouts/help_macro.html.ep:6 msgid "Help" msgstr "" @@ -4349,7 +4517,7 @@ msgstr "" msgid "Here is a list of the variables the evaluator has access to. Unless indicated, changes to the variables will not be saved. Evaluators are run in the same order they are listed on the achievement editor page and are only run if the achievement has not been earned. Keep this in mind when using persistent global data." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:419 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:421 msgid "Here is a new version of your problem." msgstr "" @@ -4357,7 +4525,7 @@ msgstr "" msgid "Hidden" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:350 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:45 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:351 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:45 msgid "Hide All" msgstr "" @@ -4369,18 +4537,10 @@ msgstr "" msgid "Hide Courses" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:593 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:568 msgid "Hide Hints from Students" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/instructor_buttons.html.ep:10 -msgid "Hide Problem Grader" -msgstr "" - -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:726 -msgid "Hide Problem Graders" -msgstr "" - #: /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:46 msgid "Hide all rendered problems on the page." msgstr "" @@ -4408,7 +4568,7 @@ msgstr "" msgid "Histogram showing the percent grade of active students for problem %1 and the adjusted percent grade with review. The number of students in each percent range is: %2. The number of students in each percent range after review is: %3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:941 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:255 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:944 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:264 msgid "Homework" msgstr "" @@ -4424,6 +4584,14 @@ msgstr "" msgid "I couldn't find the file [ACHIEVEMENT_DIR]/surprise_message.txt!" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:171 +msgid "IP Address" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:102 +msgid "IP Address:" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/File/SetDef.pm:163 msgid "IP restriction location \"%1\" for set %2 already exists." msgstr "" @@ -4484,7 +4652,7 @@ msgstr "" msgid "If selected, this adds spaces between the fields to align the commas, which makes the columns easy to read when in text form but it can confuse some spreadsheet applications since the extra spaces violate the csv standard (although Excel handles them with no problem). This will give a visual form of the CSV file that is easy to read on the page. If you want a reliable .csv file for use in any spreadsheet application unclick the \"Pad Fields\" option. You can download the .csv file immediately by clicking on the link with the filename chosen above, or you can download it using the \"File Manager\" from the scoring directory." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:199 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:188 msgid "If the original problem cannot be edited than the path name must be changed in order to be allowed to save the problem. Adding \"local/\" to the beginning of the original path is the default solution. All locally created and edited files will then appear in a subdirectory named \"local\"." msgstr "" @@ -4492,15 +4660,15 @@ msgstr "" msgid "If the test was timed, granting the user an additional version may be preferred to changing its dates." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:634 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:608 msgid "If this flag is set then this problem will count toward the grade of its parent problem. In general the adjusted status on a problem is the larger of the problem's status and the weighted average of the status of its child problems which have this flag enabled." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:450 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:461 msgid "If this is enabled then instructors with the ability to receive feedback emails will be notified whenever a student runs out of attempts on a problem and its children without receiving an adjusted status of 100%." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:435 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:446 msgid "If this is enabled then students will be unable to attempt a problem until they have completed all of the previous problems and their child problems if necessary." msgstr "" @@ -4509,18 +4677,18 @@ msgid "If this is selected, a success index is listed in each csv file. The succ msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:793 -msgid "If this is set to \"preview\", hitting the enter key on a homework problem page activates the \"Preview My Answers\" button. If this is set to \"submit\", then the enter key activates the \"Submit Answers\" button instead. Or if that button is not present, it will activate the \"Check Answers\" button. Or if that button is also not present, it will activate the \"Preview My Answers\" button. A third option is \"conservative\". In this case, the enter key behaves like \"preview\" when the \"Submit\" button is available and there are only finitely many attempts allowed. Otherise the enter key behaves like \"submit\". Note that this is only affects homework problem pages, not test/quiz pages, and not instructor pages like the PG Editor and the Library Browser." +msgid "If this is set to \"preview\", hitting the enter key on a homework problem page activates the \"Preview My Answers\" button. If this is set to \"submit\", then the enter key activates the \"Submit Answers\" button instead. Or if that button is not present, it will activate the \"Check Answers\" button. Or if that button is also not present, it will activate the \"Preview My Answers\" button. A third option is \"conservative\". In this case, the enter key behaves like \"preview\" when the \"Submit\" button is available and there are only finitely many attempts allowed. Otherwise the enter key behaves like \"submit\". Note that this is only affects homework problem pages, not test/quiz pages, and not instructor pages like the PG Editor and the Library Browser." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:970 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:973 msgid "If this is set to true, then each time a user submits an answer or grades a test, that will trigger WeBWorK possibly reporting a score to the LMS. However, several other configuration settings might still prevent WeBWorK from actually submitting a score to the LMS. If this is set to false, then grades will only be sent to the LMS with mass updates (either triggered by the instructor using the LTI Grade Update tool, or at mass update intervals)." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1062 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1065 msgid "If this is set to true, then when a user enters WeBWorK using LTI from an LMS, their user account data in WeBWorK will be updated to match the data from the LMS. This applies to first name, last name, section, recitation, and email address. If a user's information changes in the LMS then it will change in WeBWorK the next time the user enters WeBWorK from the LMS. Any changes to the user data that are made in WeBWorK will be overwritten. So if this is set to true, you may want to review the settings in the Permissions tab for who is allowed to change their own name and email address." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:918 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:921 msgid "If this is set, all users (including the instructor) must enter the WeBWorK course through the LMS. If a user reaches the regular WeBWorK login screen, they receive a message directing them back to the LMS." msgstr "" @@ -4546,7 +4714,7 @@ msgstr "" msgid "If you upload your file on the web with the name: %1 and also create an email message with the name %2 with the approriate %3 variables then not only can you email the message with the embedded grades to the students, but files with those exact names are automatically appended to the \"Grades\" page seen by the students." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:617 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:647 msgid "Illegal '/' character in input." msgstr "" @@ -4575,7 +4743,7 @@ msgstr "" msgid "Import how many sets?" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:29 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:33 msgid "Import sets with names" msgstr "" @@ -4637,10 +4805,14 @@ msgstr "" msgid "Include success index columns" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:587 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:321 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:302 msgid "Incorrect" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:48 +msgid "Incorrect attempts" +msgstr "" + #. ($total_incorrect, $num_of_problems) #: /opt/webwork/webwork2/templates/ContentGenerator/Problem/siblings.html.ep:42 msgid "Incorrect: %1/%2" @@ -4680,11 +4852,11 @@ msgstr "" msgid "Institution" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:578 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:584 msgid "Instructor Comment:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1328 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1332 msgid "Instructor Feedback:" msgstr "" @@ -4692,7 +4864,7 @@ msgstr "" msgid "Instructor Links Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:376 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:14 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:383 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:14 msgid "Instructor Tools" msgstr "" @@ -4714,7 +4886,7 @@ msgid "Invalid %1 in file: %2" msgstr "" #. ($action) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2579 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2580 msgid "Invalid action %1." msgstr "" @@ -4729,7 +4901,7 @@ msgid "Invalid file name \"%1\". All email file names must end with the \".msg\" msgstr "" #. ($headerType) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2091 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2070 msgid "Invalid headerType %1" msgstr "" @@ -4737,7 +4909,7 @@ msgstr "" msgid "Invalid line in file \"%1\": ||%2||" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:482 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:505 msgid "Invalid security code." msgstr "" @@ -4757,7 +4929,7 @@ msgstr "" msgid "JITAR Set" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:550 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:552 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:60 msgid "Job Manager" msgstr "" @@ -4774,23 +4946,23 @@ msgstr "" msgid "Jobs sorted by %1 in %plural(%2,ascending,descending) order, then by %3 in %plural(%4,ascending,descending) order,and then by %5 in %plural(%6,ascending,descending) order." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:483 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:494 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:470 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:499 msgid "Jump to Problem:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:258 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:267 msgid "Just in Time Assessment and Review" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1105 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1095 msgid "Just-In-Time Parameters" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:67 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:53 msgid "Key Binding" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:115 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:101 msgid "Key Map" msgstr "" @@ -4802,67 +4974,67 @@ msgstr "" msgid "LAST NAME" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1143 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:12 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1146 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:12 msgid "LMS Context ID" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1119 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1122 msgid "LMS access token AUD for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1120 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1123 msgid "LMS access token AUD used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1112 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1115 msgid "LMS access token URL for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1113 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1116 msgid "LMS access token URL used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1126 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1129 msgid "LMS authorization request URL for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1127 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1130 msgid "LMS authorization request URL used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1091 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1094 msgid "LMS client ID for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1092 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1095 msgid "LMS client ID used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1098 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1101 msgid "LMS deployment ID for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1099 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1102 msgid "LMS deployment ID used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1084 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1087 msgid "LMS platform ID for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1085 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1088 msgid "LMS platform ID used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1105 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1108 msgid "LMS public keyset URL for LTI 1.3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1106 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1109 msgid "LMS public keyset URL used to validate logins from an LMS using LTI 1.3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1074 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1077 msgid "LMS shared secret for LTI 1.1 authentication" msgstr "" @@ -4870,10 +5042,14 @@ msgstr "" msgid "LOCAL Usage" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1231 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1236 msgid "LTI" msgstr "" +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:222 +msgid "LTI 1.3 Registration" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:36 msgid "LTI Configuration" msgstr "" @@ -4891,7 +5067,7 @@ msgstr "" msgid "LTI Grade Mode" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:545 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:60 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:547 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:48 msgid "LTI Grade Update" msgstr "" @@ -4903,7 +5079,7 @@ msgstr "" msgid "LTI Mass Update" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:58 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:154 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:13 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:58 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:156 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:13 msgid "LTI Version" msgstr "" @@ -4943,19 +5119,15 @@ msgstr "" msgid "Language" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:169 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:170 msgid "Last" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:576 -msgid "Last Answer" -msgstr "" - #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:32 msgid "Last Full Update" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:105 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:126 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:66 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:85 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:35 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:109 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:127 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:66 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:85 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:35 msgid "Last Name" msgstr "" @@ -4967,7 +5139,11 @@ msgstr "" msgid "Last name" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:118 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:237 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:59 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:41 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:48 +msgid "Last submission:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:118 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:241 msgid "Latest Answers" msgstr "" @@ -5007,19 +5183,23 @@ msgstr "" msgid "Library Broswer Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:438 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:37 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:445 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:37 msgid "Library Browser" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1490 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:93 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:93 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:499 +msgid "Limit to" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1491 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:93 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:93 msgid "Link structure is missing links, or links point to the wrong place." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1685 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1686 msgid "Link structure is missing links, or the webserver lacks sufficient privileges, or links point to the wrong place." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1487 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1681 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:90 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1488 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1682 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/archive_course_confirm.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/rename_course_confirm.html.ep:90 msgid "Link structure is ok" msgstr "" @@ -5027,7 +5207,7 @@ msgstr "" msgid "Link structure needs to be repaired." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1468 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1652 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1469 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1653 msgid "Link structure:" msgstr "" @@ -5055,7 +5235,7 @@ msgstr "" msgid "Live equation rendering" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:173 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:170 msgid "Loading..." msgstr "" @@ -5084,16 +5264,16 @@ msgid "Location" msgstr "" #. ($locationID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1965 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2001 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1966 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2002 msgid "Location %1 does not exist in the WeBWorK database. Please check your input (perhaps you need to reload the location management page?)." msgstr "" #. ($locationID, join(', ', @addresses) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1853 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1854 msgid "Location %1 has been created, with addresses %2." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1909 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1910 msgid "Location deletion requires confirmation." msgstr "" @@ -5121,27 +5301,27 @@ msgstr "" msgid "Log In Again" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:11 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:12 msgid "Log Out" msgstr "" #. ($add_courseID) #. ($rename_oldCourseID) #. ($rename_newCourseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:448 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:680 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:756 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:448 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:680 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:757 msgid "Log into %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1284 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1285 msgid "Log into Course" msgstr "" #. ($userName) -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:9 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:10 msgid "Logged in as %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:197 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:203 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:223 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:108 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:198 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:204 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:230 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:108 msgid "Login" msgstr "" @@ -5149,7 +5329,7 @@ msgstr "" msgid "Login Info" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:103 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:64 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:83 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:218 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:36 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:107 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:64 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:83 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:219 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:36 msgid "Login Name" msgstr "" @@ -5161,11 +5341,11 @@ msgstr "" msgid "Login:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:296 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:303 msgid "Logout" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:68 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:54 msgid "Mac alternate" msgstr "" @@ -5203,7 +5383,7 @@ msgstr "" msgid "Makes a new copy of the file you are editing at the location relative to the course's achievement notifications ([ACHEVNOTIFYDIR]) directory, and sets the new file to be the email notification template for this achievement." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:188 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:177 msgid "Makes a new copy of the file you are editing at the location relative to the course's templates ([TMPL]) directory. You may choose to replace the current problem in the current set, append to the end to then end of the current set as a new problem, or create a problem that is not attached to a problem set." msgstr "" @@ -5239,7 +5419,7 @@ msgstr "" msgid "Manage users. Note, only admin users have access to the course administration tools." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:423 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:213 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:430 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:213 msgid "Manual Grader" msgstr "" @@ -5248,15 +5428,15 @@ msgid "Manual Grader Help" msgstr "" #. ($c->tag('span', dir => 'ltr', format_set_name_display($c->stash->{set}->set_id) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm:186 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemGrader.pm:205 msgid "Manual Grader for %1: Problem %2" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:62 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:50 msgid "Manually initiate an LTI grade passback for selected sets or users. This link is only visible if LTI grade passback is enabled for the course." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:172 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:182 msgid "Many of these editing activities can also be done more quickly from the \"Instructor Tools\" page where students and sets can be selected simultaneously. The \"Instructor Tools\" page is useful for quick editing of one or two students. The initial setup of the class can be done best from this page. Importing and exporting class lists can only be done from this page. Deleting students can only be done from this page." msgstr "" @@ -5264,7 +5444,7 @@ msgstr "" msgid "Mark Correct" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:611 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:612 msgid "Mark Correct?" msgstr "" @@ -5280,14 +5460,18 @@ msgstr "" msgid "Math" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:110 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:21 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:109 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:20 msgid "Math Objects" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:482 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:493 msgid "Max Attempts" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:42 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:33 +msgid "Max attempts" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/view_problems_line.html.ep:23 msgid "Max. Shown:" msgstr "" @@ -5304,10 +5488,24 @@ msgstr "" msgid "Merge file:" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:18 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:17 +msgid "Message delivered to multiple recipients. Consider using reply-all." +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:13 msgid "Message file:" msgstr "" +#. ($user->full_name, $user->user_id, $ce->{institutionName}, $problem ? link_to(format_set_name_display($set->set_id) +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:12 +msgid "Message from %1 (%2) via WeBWorK at %3 (sent from %4)." +msgstr "" + +#. ($user->full_name, $user->user_id, $ce->{institutionName}) +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:5 +msgid "Message from %1 (%2) via WeBWorK at %3." +msgstr "" + #. ("$emailDirectory/$output_file") #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SendMail.pm:274 msgid "Message saved to file %1." @@ -5327,7 +5525,7 @@ msgstr "" msgid "Messages can be saved to a message file (which must end in the \".msg\" extension). Use the \"Message file\" drop down menu to select which message file to load, or \"None\" to use a blank message. To save a new message, use the \"Save as\" button after entering in a valid filename. The \"Save as\" button will not overwrite currently saved messages. To edit a currently saved message first select it using the drop down menu, then click the \"Save\" button to save any changes. Use the \"File Manager\" to delete messages, located in the \"[TMPL]/email\" directory." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:25 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:22 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:28 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:22 msgid "Method" msgstr "" @@ -5339,7 +5537,7 @@ msgstr "" msgid "Miscellaneous" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1779 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1780 msgid "Missing required input data. Please check that you have filled in all of the create location fields and resubmit." msgstr "" @@ -5347,15 +5545,15 @@ msgstr "" msgid "Mode in which the LANG and DIR settings for a single problem are determined." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:465 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:466 msgid "Move" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:479 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:466 msgid "Move to Page:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:474 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:461 msgid "Move to Problem:" msgstr "" @@ -5384,7 +5582,7 @@ msgstr "" msgid "NO OF FIELDS" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/AchievementsLeaderboard.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:25 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/edit_table.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/export_table.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:113 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:231 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:164 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:12 /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:10 +#: /opt/webwork/webwork2/templates/ContentGenerator/AchievementsLeaderboard.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:157 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:25 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/edit_table.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/export_table.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:113 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:235 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:165 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:12 /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:10 msgid "Name" msgstr "" @@ -5404,7 +5602,7 @@ msgstr "" msgid "Name the new set" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementList.html.ep:30 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:88 /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementList.html.ep:30 msgid "Name:" msgstr "" @@ -5412,7 +5610,7 @@ msgstr "" msgid "Necromancers Charm" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1000 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:237 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:501 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:518 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:535 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:36 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1003 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:246 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:512 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:525 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:539 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:36 msgid "Never" msgstr "" @@ -5448,7 +5646,7 @@ msgstr "" msgid "New folder name:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:10 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:11 msgid "New problem template" msgstr "" @@ -5456,7 +5654,11 @@ msgstr "" msgid "New set name" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:965 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:967 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:969 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:484 +msgid "Next Page" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:895 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:897 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:899 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:484 msgid "Next Problem" msgstr "" @@ -5469,27 +5671,31 @@ msgid "Next page" msgstr "" #. (% $c->formatDateTime($nextTime, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:152 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:149 msgid "Next test will be available by %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:155 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:167 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:219 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:293 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:345 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:380 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:398 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:432 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:447 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:571 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:599 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:631 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:78 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:691 /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy/form.html.ep:141 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:57 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/delete_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/delete_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/delete_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/reset_2fa_form.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:154 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:176 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:198 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:73 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:164 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:176 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:228 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:304 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:356 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:391 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:409 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:443 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:458 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:574 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:605 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:73 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:707 /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy/form.html.ep:141 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:57 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/delete_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/delete_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/delete_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/reset_2fa_form.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:154 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:176 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:198 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:73 msgid "No" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:161 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:589 +msgid "No Attempts Remaining" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:162 msgid "No Course" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:218 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:219 msgid "No Description" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2554 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2555 msgid "No OTP secrets copied." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2529 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2530 msgid "No OTP secrets reset." msgstr "" @@ -5501,7 +5707,7 @@ msgstr "" msgid "No Target Set Selected" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:54 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:168 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:54 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:172 msgid "No WeBWorK course was found associated to this LMS course. If this is an error, please contact the WeBWorK system administrator." msgstr "" @@ -5509,7 +5715,7 @@ msgstr "" msgid "No achievement badges have been assigned yet." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:65 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:89 msgid "No achievement rewards are available for this assignment." msgstr "" @@ -5551,15 +5757,15 @@ msgstr "" msgid "No changes specified. You must mark the checkbox of the item(s) to be changed and enter the change data." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1406 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1389 msgid "No changes were saved!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:395 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:418 msgid "No class list file provided." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:155 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:272 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:155 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:278 msgid "No content was selected." msgstr "" @@ -5588,7 +5794,7 @@ msgid "No courses found" msgstr "" #. ($setID, $problemID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:819 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:780 msgid "No data exists for set %1 and problem %2" msgstr "" @@ -5612,12 +5818,12 @@ msgstr "" msgid "No jobs in queue." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1988 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1989 msgid "No location specified to edit. Please check your input data." msgstr "" #. ($badID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1899 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1900 msgid "No location with name %1 exists in the database" msgstr "" @@ -5641,7 +5847,7 @@ msgstr "" msgid "No merge file selected." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:145 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:142 msgid "No more tests available." msgstr "" @@ -5649,11 +5855,11 @@ msgstr "" msgid "No new Achievement ID specified. No new achievement created. File not saved." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:669 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:671 msgid "No new versions of this test are available, because the test is not open or its time limit has expired." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:640 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:642 msgid "No new versions of this test are available, because you have already taken the maximum number allowed." msgstr "" @@ -5661,7 +5867,7 @@ msgstr "" msgid "No password" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:79 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:82 msgid "No problems matched the given parameters." msgstr "" @@ -5674,7 +5880,7 @@ msgid "No recipients selected. Please select one or more recipients from the lis msgstr "" #. ($setID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:53 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:54 msgid "No record for global set %1." msgstr "" @@ -5690,32 +5896,32 @@ msgstr "" msgid "No sets selected for scoring." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:67 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:109 msgid "No sets shown. Choose one of the options above to list the sets in the course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2082 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2061 msgid "No source filePath specified" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:120 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:121 msgid "No students shown. Choose one of the options above to list the students in the course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:244 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:259 msgid "No submissions. Over time." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:306 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:307 msgid "No tests taken." msgstr "" #. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:820 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:781 msgid "No user specific data exists for user %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:396 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:419 msgid "No users added." msgstr "" @@ -5728,24 +5934,24 @@ msgid "No valid OTP secrets to reset. Skipping all." msgstr "" #. ($locationID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2142 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2143 msgid "No valid changes submitted for location %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:252 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:253 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:252 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:250 msgid "No versions of this test have been taken." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:941 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:248 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:63 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/view_problems_line.html.ep:16 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:944 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:247 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:63 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/view_problems_line.html.ep:16 msgid "None" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:903 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:8 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:861 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:8 msgid "None Specified" msgstr "" #. (tag('b', join(', ', @$unassignedUsers) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:77 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:78 msgid "None of the selected users are assigned to this set: %1" msgstr "" @@ -5757,7 +5963,7 @@ msgstr "" msgid "Not Visible" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:33 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:36 msgid "Not logged in." msgstr "" @@ -5766,7 +5972,7 @@ msgstr "" msgid "Not saving dates for %1!" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:595 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:613 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:43 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:54 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:31 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:43 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:611 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:629 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:43 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:54 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:31 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/ShowMeAnother/messages.html.ep:43 msgid "Note" msgstr "" @@ -5788,15 +5994,15 @@ msgstr "" #. (tag('i', $text) #. (tag('i', $pg->{result}{msg}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:233 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:590 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:214 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:606 msgid "Note: %1" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:716 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:741 msgid "Note: grading the test grades all problems, not just those on this page." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:234 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:235 msgid "Notes regarding copying the course configuration file" msgstr "" @@ -5804,7 +6010,7 @@ msgstr "" msgid "Notifications" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:909 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:47 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:69 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:867 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:51 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:35 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:69 msgid "Now" msgstr "" @@ -5812,15 +6018,27 @@ msgstr "" msgid "Number" msgstr "" +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:589 +msgid "Number incorrect is" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_stats.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:58 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:94 msgid "Number of Students" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:37 +msgid "Number of correct attempts:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:38 +msgid "Number of incorrect attempts:" +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementList.html.ep:39 msgid "Number:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1133 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:876 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1134 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:877 msgid "OK" msgstr "" @@ -5828,15 +6046,15 @@ msgstr "" msgid "OPL Problem Levels Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2705 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2706 msgid "OTP Secret is empty - Skipping" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2659 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2660 msgid "OTP Secret is not empty - Overwritting" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2622 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2623 msgid "OTP secret is empty - Skipping" msgstr "" @@ -5869,7 +6087,7 @@ msgstr "" msgid "One additional test version added to this test." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:907 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:903 msgid "One or more of the problems in this test have not been assigned to you." msgstr "" @@ -5885,11 +6103,11 @@ msgstr "" msgid "One-time password setup QR code" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:414 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:425 msgid "Only Start" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:381 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:399 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:392 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:410 msgid "Only after set answer date" msgstr "" @@ -5905,15 +6123,15 @@ msgstr "" msgid "Only this permission level and higher get buttons for sending email to the instructor." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:53 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:39 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:54 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:39 msgid "Open" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:31 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:35 msgid "Open Assignments" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:110 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:342 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:7 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:45 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:61 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:119 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:342 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:7 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:45 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:61 msgid "Open Date" msgstr "" @@ -5921,7 +6139,15 @@ msgstr "" msgid "Open Problem Library" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:274 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:547 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:94 +msgid "Open date" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:58 +msgid "Open date:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:275 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:548 msgid "Open in New Window" msgstr "" @@ -5929,17 +6155,17 @@ msgstr "" msgid "Open in new window" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:268 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:283 msgid "Open." msgstr "" #. ($beginReducedScoringPeriod) #. ($c->formatDateTime($set->due_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:152 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:172 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:144 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:164 msgid "Open. Due %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:266 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:281 msgid "Open. Submitted." msgstr "" @@ -5951,11 +6177,11 @@ msgstr "" msgid "Optional Modules" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:340 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:351 msgid "Order Problems Randomly" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:349 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:360 msgid "Order problems randomly or not. If you will be manually reviewing student answers, you might not want to order problems randomly to facilitate assembly line grading." msgstr "" @@ -5968,7 +6194,7 @@ msgid "Other Options" msgstr "" # Context is "7 Out Of 10" -#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:179 +#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:180 msgid "Out Of" msgstr "" @@ -6004,6 +6230,14 @@ msgstr "" msgid "PDF hardcopy for selected users, for selected sets" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:44 +msgid "PG Critic Help" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep:4 +msgid "PG Critic Violations" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Problem/checkboxes.html.ep:37 msgid "PG Info" msgstr "" @@ -6020,15 +6254,15 @@ msgstr "" msgid "PG Sample Problems" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:663 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:664 msgid "PG debug messages" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:671 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:672 msgid "PG internal errors" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:125 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:124 msgid "PG markdown syntax used to format WeBWorK questions. This interactive lab can help you to learn the techniques." msgstr "" @@ -6036,37 +6270,32 @@ msgstr "" msgid "PG problem file" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:647 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:648 msgid "PG question failed to render" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:661 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:662 msgid "PG question processing error messages" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:667 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:149 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:668 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:153 msgid "PG warning messages" msgstr "" -# Doesn't need to be translated -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:32 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:43 -msgid "PGML" -msgstr "" - -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep:30 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:30 msgid "PGML Conversion Help" msgstr "" # Doesn't need to be translated -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:116 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:25 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:115 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:24 msgid "POD" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:249 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:256 msgid "POD Index" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:257 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:264 msgid "POD Viewer" msgstr "" @@ -6074,11 +6303,7 @@ msgstr "" msgid "POD for Macro Files" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:106 -msgid "POD for macros and sample problem code and snippets" -msgstr "" - -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1472 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:541 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1413 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:547 msgid "PREVIEW ONLY -- ANSWERS NOT RECORDED" msgstr "" @@ -6113,7 +6338,7 @@ msgstr "" msgid "Parsers" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:113 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:104 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:93 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail/restricted_login_proctor_password_row.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Login.html.ep:64 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:60 /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:18 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:136 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:105 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:93 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail/restricted_login_proctor_password_row.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Login.html.ep:64 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:60 /opt/webwork/webwork2/templates/HelpFiles/Options.html.ep:18 msgid "Password" msgstr "" @@ -6122,7 +6347,7 @@ msgstr "" msgid "Past Answers for %1, set %2, problem %3" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:34 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:38 msgid "Past Due Assignments" msgstr "" @@ -6138,7 +6363,7 @@ msgstr "" msgid "Percent Score" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:503 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:501 msgid "Percent of Students" msgstr "" @@ -6154,15 +6379,15 @@ msgstr "" msgid "Perfect" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep:14 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:14 msgid "Perltidy Help" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep:9 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:9 msgid "Perltidy is a reformatting function that attempts to format code in a standard way. It does not change the functionality of the code and in general is desired to have a common problem layout." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:112 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:110 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:92 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:78 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:135 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:111 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:92 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:79 msgid "Permission Level" msgstr "" @@ -6171,7 +6396,7 @@ msgstr "" msgid "Permission Level: %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:863 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:866 msgid "Permission levels for receiving feedback email" msgstr "" @@ -6183,11 +6408,11 @@ msgstr "" msgid "Pick a target set above to add this problem to." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:920 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:52 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:74 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:878 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:56 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:40 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:74 msgid "Pick date and time" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2215 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2216 msgid "Place a file named \"hide_directory\" in a course or other directory and it will not show up in the courses list on the WeBWorK home page. It will still appear in the Course Administration listing." msgstr "" @@ -6195,6 +6420,10 @@ msgstr "" msgid "Platform ID" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:51 +msgid "Please choose a set date type." +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/delete_form.html.ep:18 msgid "Please confirm it is okay to delete selected achievements permanently." msgstr "" @@ -6244,19 +6473,23 @@ msgstr "" msgid "Please input a file name to export to that does not contain forward slashes." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1889 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1890 msgid "Please provide a location name to delete." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:54 +msgid "Please select a date." +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/import_form.html.ep:27 msgid "Please select a file to import from." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:49 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:50 msgid "Please select a problem." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:72 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:76 msgid "Please select a set definition file to import." msgstr "" @@ -6264,19 +6497,19 @@ msgstr "" msgid "Please select at least one achievement." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:163 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:166 msgid "Please select at least one set and try again." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:14 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:58 msgid "Please select at least one set." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:154 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:157 msgid "Please select at least one user and try again." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:18 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:93 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:18 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:94 msgid "Please select at least one user." msgstr "" @@ -6310,10 +6543,10 @@ msgstr "" #. ($saveMode) #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:1282 -msgid "Please use radio buttons to choose the method for saving this file. Uknown saveMode: %1." +msgid "Please use radio buttons to choose the method for saving this file. Unknown saveMode: %1." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:28 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:29 msgid "Plese enter a file with path relative to the course templates directory." msgstr "" @@ -6350,11 +6583,11 @@ msgstr "" msgid "Prepare which sets for export?" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:266 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:287 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:247 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:268 msgid "Press \"Grade Test\" now!" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:261 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:242 msgid "Press \"Grade Test\" soon!" msgstr "" @@ -6362,11 +6595,11 @@ msgstr "" msgid "Preview Message" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:30 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:112 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:35 +#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:13 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:30 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:116 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:35 msgid "Preview My Answers" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:674 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:690 msgid "Preview Test" msgstr "" @@ -6374,7 +6607,11 @@ msgstr "" msgid "Preview the message before sending using the \"Preview Message\" button. The preview shows the email that would be sent to the first selected student or the instructor if no students were selected. The preview will also list all of the students that would receive their own personalized message. If a merge file was selected, the preview will also indicate which (if any) recipient's merge file data could not be found." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:950 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:952 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:954 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:477 +msgid "Previous Page" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:880 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:882 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:884 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:477 msgid "Previous Problem" msgstr "" @@ -6386,12 +6623,12 @@ msgstr "" msgid "Primary Actions" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:374 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:357 msgid "Print Test" msgstr "" # Short for Problem -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:306 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:287 msgid "Prob" msgstr "" @@ -6405,7 +6642,7 @@ msgstr "" #. ($c->{setRecord}->assignment_type eq 'jitar' ? join('.', jitar_id_to_seq($_) #. ($set->assignment_type eq 'jitar' ? join('.', jitar_id_to_seq($_) #. ($problemNumber) -#: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/DuplicateProb.pm:29 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/DuplicateProb.pm:36 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:382 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:790 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:800 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:811 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:263 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:58 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:62 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader/siblings.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:232 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/siblings.html.ep:43 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:41 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:45 +#: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/DuplicateProb.pm:29 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/DuplicateProb.pm:36 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:382 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:788 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:798 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:809 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:240 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:58 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:62 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader/siblings.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:232 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/siblings.html.ep:24 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:41 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:45 msgid "Problem %1" msgstr "" @@ -6440,7 +6677,7 @@ msgid "Problem %1 weight increased from %2 to %3." msgstr "" #. ($i + 1) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:549 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:555 msgid "Problem %1." msgstr "" @@ -6456,11 +6693,23 @@ msgstr "" msgid "Problem Display/Answer Checking" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:453 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:35 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:460 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:35 msgid "Problem Editor" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:958 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:959 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:961 +#: /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:11 +msgid "Problem Grader" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:39 +msgid "Problem ID" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:30 +msgid "Problem ID:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:888 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:889 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:891 msgid "Problem List" msgstr "" @@ -6476,11 +6725,11 @@ msgstr "" msgid "Problem Score (%):" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:20 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:200 /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:223 +#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:20 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:201 /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:223 msgid "Problem Score Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:54 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:80 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:33 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:45 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:15 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:50 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:87 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:33 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:45 msgid "Problem Techniques" msgstr "" @@ -6489,15 +6738,15 @@ msgstr "" msgid "Problem creating set \"%1\": %2" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:602 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:577 msgid "Problem files may have hints included in their code. Use this option to suppress showing students these hints. Note that even if hints are not suppressed, there is a threshold number of attempts that a student must make before they have the option to view a hint." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:239 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:243 msgid "Problem has a different source file than the currently rendered problem." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:233 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:237 msgid "Problem has an essay answer that needs to be graded." msgstr "" @@ -6535,7 +6784,15 @@ msgstr "" msgid "Problem number to reset incorrect attempts" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2083 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:107 +msgid "Problem randorder" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:69 +msgid "Problem randorder:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2062 msgid "Problem source is drawn from a grouping set" msgstr "" @@ -6543,7 +6800,7 @@ msgstr "" msgid "Problem source is drawn from a grouping set and cannot be directly rendered or edited." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:12 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader/siblings.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:339 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:3 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/instructor-selectors.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:192 /opt/webwork/webwork2/templates/ContentGenerator/Problem/siblings.html.ep:2 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:9 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:17 +#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:12 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader/siblings.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:340 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:3 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/instructor-selectors.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:193 /opt/webwork/webwork2/templates/ContentGenerator/Problem/siblings.html.ep:2 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:9 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:17 msgid "Problems" msgstr "" @@ -6551,7 +6808,7 @@ msgstr "" msgid "Problems Added" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:53 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:35 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:57 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:49 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:35 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:57 msgid "Problems by Macro" msgstr "" @@ -6567,7 +6824,7 @@ msgstr "" msgid "Problems have been assigned to all current users." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:354 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:365 msgid "Problems per Page" msgstr "" @@ -6579,7 +6836,7 @@ msgstr "" msgid "Proctor" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:408 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:419 msgid "Proctor Authorization Type" msgstr "" @@ -6607,23 +6864,23 @@ msgstr "" msgid "Proctor:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:257 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:266 msgid "Proctored Test" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:343 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:350 msgid "Proctored Test %2" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:350 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:357 msgid "Proctored Test %2 Proctor Login" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:418 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:429 msgid "Proctored tests always require authorization to start the test. \"Both Start and Grade\" will require either login proctor authorization or a password specific to this set to start the test, and grade proctor authorization to grade the test. \"Only Start\" requires either grade proctor authorization or a password specific to this set to start and no authorization to grade." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1127 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1117 msgid "Proctoring Parameters" msgstr "" @@ -6643,6 +6900,14 @@ msgstr "" msgid "RECITATION" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:44 +msgid "Random seed" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:34 +msgid "Random seed:" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:199 msgid "Randomize" msgstr "" @@ -6651,7 +6916,7 @@ msgstr "" msgid "Randomize Seed" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:356 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:357 msgid "Randomize Seeds" msgstr "" @@ -6667,11 +6932,11 @@ msgstr "" msgid "Really delete the items listed above?" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:110 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:105 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/student_stats.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:212 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:64 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:133 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:169 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:90 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:105 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:213 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:65 msgid "Recitation" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:21 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:100 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:21 msgid "Recitation:" msgstr "" @@ -6687,7 +6952,7 @@ msgstr "" #. ($recipient) #. ($studentID) #. ($c->{studentID}) -#: /opt/webwork/webwork2/lib/Mojolicious/WeBWorK/Tasks/SendInstructorEmail.pm:53 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:132 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/student_stats.html.ep:8 +#: /opt/webwork/webwork2/lib/Mojolicious/WeBWorK/Tasks/SendInstructorEmail.pm:53 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:132 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep:5 msgid "Record for user %1 not found." msgstr "" @@ -6699,15 +6964,15 @@ msgstr "" msgid "Reduced Scoring" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:32 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:36 msgid "Reduced Scoring Assignments" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:172 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:343 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:8 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:12 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:47 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:66 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:181 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:343 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:8 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:12 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_form.html.ep:47 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:66 msgid "Reduced Scoring Date" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:161 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:170 msgid "Reduced Scoring Enabled" msgstr "" @@ -6716,7 +6981,7 @@ msgid "Reduced Scoring Period" msgstr "" #. ($c->formatDateTime($set->due_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:167 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:159 msgid "Reduced credit can still be earned until %1." msgstr "" @@ -6739,11 +7004,7 @@ msgstr "" msgid "Reduced:" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:166 -msgid "Reformat the code using perltidy or a conversion to PGML. Using perltidy will change the code in the editor window, and save changes to the temporary file. In some cases (if the code contains backslashes or double tildes) this can result in odd spacing in the code. The convert to PGML feature changes the code in text blocks in the code to use PGML features. Generally the conversion of many of the formatting and LaTeX is performed correctly, however answer blanks need attention. In either case, make sure to inspect the formatted code, and edit further or revert if needed." -msgstr "" - -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep:7 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:7 msgid "Reformat the code using perltidy." msgstr "" @@ -6763,11 +7024,16 @@ msgstr "" msgid "Regular Assignment" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:39 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:43 msgid "Regular Assignments" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:232 +#. (scalar(@{ $_->explanation->{sampleProblems} }) +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep:30 +msgid "Related sample %plural(%1,problem):" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:241 msgid "Relax Location Restrictions" msgstr "" @@ -6781,7 +7047,7 @@ msgid "Remaining" msgstr "" #. ('00:00:00') -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:271 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:252 msgid "Remaining time: %1" msgstr "" @@ -6789,12 +7055,12 @@ msgstr "" msgid "Remember Me" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:432 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:434 msgid "Remember to return to your original problem when you're finished here!" msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/NoReducedCred.pm:15 -msgid "Remove reduced scoring penalties from an open assignemnt. You will have to resubmit any problems that have already been penalized to earn full credit on them." +msgid "Remove reduced scoring penalties from an open assignment. You will have to resubmit any problems that have already been penalized to earn full credit on them." msgstr "" #. ($c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat}) @@ -6823,15 +7089,15 @@ msgstr "" msgid "Rename file as:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:486 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:487 msgid "Render" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:347 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:42 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:348 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:42 msgid "Render All" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:483 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:484 msgid "Render Problem" msgstr "" @@ -6839,7 +7105,7 @@ msgstr "" msgid "Render all problems on the page. This does not reload the page or save or reset changes." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:141 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:127 msgid "Render or re-render the problem, course info file, or set header being edited. This does not change the permanent file on the disk. You can view different versions of the same problem by changing the seed. You can also change the manner in which the mathematics is typeset. If \"Open in new window\" is checked, then the problem will open in a new tab or window showing the problem as it will be rendered for students in the set." msgstr "" @@ -6847,7 +7113,7 @@ msgstr "" msgid "Rendering Problems" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:344 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:36 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:345 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:36 msgid "Renumber Problems" msgstr "" @@ -6892,20 +7158,20 @@ msgstr "" msgid "Replaces the second problem with a copy of the first." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:143 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:140 msgid "Report Bugs in this Problem" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/admin_links.html.ep:58 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:378 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/admin_links.html.ep:58 /opt/webwork/webwork2/templates/ContentGenerator/Base/links.html.ep:354 msgid "Report bugs" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:151 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:148 msgid "Report bugs in a WeBWorK question/problem using this link. The very first time you do this you will need to register with an email address so that information on the bug fix can be reported back to you." msgstr "" #. ($upgrade_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1369 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1602 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1370 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1603 msgid "Report for course %1:" msgstr "" @@ -6919,16 +7185,16 @@ msgstr "" msgid "Request New Version" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:18 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:19 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:19 msgid "Request information" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1179 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1120 msgid "Request new version now." msgstr "" #. ($setName) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:472 +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:473 msgid "Requested set \"%1\" is a proctored test, but no valid proctor authorization has been obtained." msgstr "" @@ -6938,12 +7204,12 @@ msgid "Requested set '%1' could not be found in the database for user %2." msgstr "" #. ($setName, $node_name) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:458 +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:459 msgid "Requested set '%1' is a homework assignment but the test content generator %2 was called. Try re-entering the set from the problem sets listing page." msgstr "" #. ($setName, $node_name) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:452 +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:453 msgid "Requested set '%1' is a test but the regular homework assignment content generator %2 was called. Try re-entering the set from the problem sets listing page." msgstr "" @@ -6953,13 +7219,13 @@ msgid "Requested set '%1' is not assigned to user %2." msgstr "" #. ($setName) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:436 +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:434 msgid "Requested set '%1' is not available yet." msgstr "" #. ($setName) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:430 -msgid "Requested set '%1' is not yet open." +#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:428 +msgid "Requested set '%1' is not available." msgstr "" #. ($verNum, $setName) @@ -6972,7 +7238,7 @@ msgstr "" msgid "Requested version (%1) of set '%2' is not assigned to user %3." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:916 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:919 msgid "Require users to log in through the LMS" msgstr "" @@ -6980,15 +7246,15 @@ msgstr "" msgid "Required" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:528 -msgid "Rerandomize After" +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:533 +msgid "Rerandomize" msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/browse_library_panel_advanced.html.ep:104 msgid "Reset" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:197 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:712 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:30 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:198 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:713 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:30 msgid "Reset Form" msgstr "" @@ -7014,12 +7280,12 @@ msgid "Reset the number of attempts on problem %1." msgstr "" #. ($num) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:468 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:491 msgid "Reset two factor authentication for %1 users." msgstr "" #. ($num) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:490 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:513 msgid "Reset two factor authentication for %quant(%1,user)." msgstr "" @@ -7053,7 +7319,7 @@ msgstr "" msgid "Restored backup from %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:214 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:223 msgid "Restrict Access by Location" msgstr "" @@ -7061,15 +7327,15 @@ msgstr "" msgid "Restrict Locations" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:425 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:436 msgid "Restrict Problem Progression" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:185 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:194 msgid "Restrict Release by Set(s)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:220 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:229 msgid "Restrict To" msgstr "" @@ -7077,7 +7343,7 @@ msgstr "" msgid "Restrict or sort the students displayed" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:310 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:291 msgid "Result" msgstr "" @@ -7086,7 +7352,7 @@ msgstr "" msgid "Result for job %1" msgstr "" -#: /opt/webwork/webwork2/lib/FormatRenderedProblem.pm:153 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:237 +#: /opt/webwork/webwork2/lib/FormatRenderedProblem.pm:153 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:238 msgid "Results for this submission" msgstr "" @@ -7102,7 +7368,7 @@ msgstr "" msgid "Return to your work" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:129 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:38 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh_edit.html.ep:20 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:217 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:129 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:38 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh_edit.html.ep:20 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:206 msgid "Revert" msgstr "" @@ -7116,11 +7382,11 @@ msgstr "" msgid "Reverted to original file \"%1\"." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:219 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:208 msgid "Reverts to the copy of the file saved on the disk or to a backup file. All unsaved editing changes will be lost. This option is only active when a temporary file or a backup file exists. You may also delete backups that have been made with this tab." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:179 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:189 msgid "Review of column functions:" msgstr "" @@ -7160,27 +7426,27 @@ msgstr "" msgid "Sample Problem Home" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:264 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:271 msgid "Sample Problem Index" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:279 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:286 msgid "Sample Problem Viewer" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:104 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:32 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:39 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:104 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:32 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/viewer.html.ep:39 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:14 msgid "Sample Problems" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:70 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:77 msgid "Sample Problems by Category" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:85 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:92 msgid "Sample Problems by Macro" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:75 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:82 msgid "Sample Problems by Subject Area" msgstr "" @@ -7194,15 +7460,19 @@ msgstr "" msgid "Sample Problems for Techniques: %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:82 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:106 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:17 +msgid "Sample problem code with documentation." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:78 msgid "Sample problem not found." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:38 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep:39 msgid "Sample problem:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementEditor.pm:18 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm:15 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:126 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:108 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:73 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:40 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh_edit.html.ep:23 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:243 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:175 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:84 /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:275 /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:13 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:174 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementEditor.pm:18 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm:15 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:126 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:108 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:73 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:40 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh_edit.html.ep:23 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:247 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:175 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:84 /opt/webwork/webwork2/templates/HTML/SingleProblemGrader/grader.html.ep:276 /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:13 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:163 msgid "Save" msgstr "" @@ -7215,11 +7485,11 @@ msgstr "" msgid "Save Account Settings" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementEditor.pm:19 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm:16 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:127 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh_edit.html.ep:27 /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:16 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:185 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementEditor.pm:19 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm:16 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:127 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh_edit.html.ep:27 /opt/webwork/webwork2/templates/HelpFiles/InstructorAchievementNotificationEditor.html.ep:16 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:174 msgid "Save As" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Config.html.ep:83 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:196 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:711 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:22 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Config.html.ep:83 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:197 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:712 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetDetail.html.ep:22 msgid "Save Changes" msgstr "" @@ -7239,7 +7509,7 @@ msgstr "" msgid "Save as:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/save_edit_form.html.ep:1 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/save_edit_form.html.ep:1 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:114 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:82 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/save_edit_form.html.ep:1 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/save_edit_form.html.ep:1 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/save_edit_form.html.ep:1 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:115 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:83 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/save_edit_form.html.ep:1 msgid "Save changes" msgstr "" @@ -7247,7 +7517,7 @@ msgstr "" msgid "Save file to:" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:176 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:165 msgid "Save the contents of the editor window to the file on disk and re-render the problem. If \"Open in new window\" is checked, then the problem will open in a new tab or window showing the problem as it will be rendered for students in the set. If \"Create backup\" is checked then a backup of the current file on disk will be created before overwriting it with the contents of the editor window. If a backup already exists, then a \"Delete oldest backup\" check box will be present. If that is checked, then the oldest backup will be deleted when \"Save\" is clicked. These backups can be reverted to and managed on the \"Revert\" tab." msgstr "" @@ -7264,7 +7534,7 @@ msgstr "" msgid "Saved answers" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2494 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2495 msgid "Saved course map." msgstr "" @@ -7274,15 +7544,15 @@ msgstr "" msgid "Saved to file \"%1\"" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2784 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2785 msgid "Schema and database field definitions do not agree" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2771 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2772 msgid "Schema and database table definitions do not agree" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:52 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:89 /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:9 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:276 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:176 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:171 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetList.html.ep:66 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementList.pm:52 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:89 /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:9 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:276 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:177 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:168 /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemSetList.html.ep:66 msgid "Score" msgstr "" @@ -7290,7 +7560,7 @@ msgstr "" msgid "Score (%)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:195 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:204 msgid "Score Required for Release" msgstr "" @@ -7302,7 +7572,7 @@ msgstr "" msgid "Score selected set(s) and save to:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:303 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:284 msgid "Score summary for last submission:" msgstr "" @@ -7337,7 +7607,7 @@ msgstr "" msgid "Scoring (\".csv\") files" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:475 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:482 msgid "Scoring Download" msgstr "" @@ -7345,7 +7615,7 @@ msgstr "" msgid "Scoring Message" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:470 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:43 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:477 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:43 msgid "Scoring Tools" msgstr "" @@ -7353,7 +7623,7 @@ msgstr "" msgid "Scoring Tools Help" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:330 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:331 msgid "Screen and Hardcopy set header information cannot be overridden for individual students." msgstr "" @@ -7369,23 +7639,23 @@ msgstr "" msgid "Scroll of Resurrection" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:47 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:54 msgid "Search macros" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:55 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:62 msgid "Search sample problems" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:36 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:37 +#: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:43 /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer.html.ep:44 msgid "Search the documentation" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:109 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:32 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:89 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:110 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:104 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/student_stats.html.ep:18 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:206 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:57 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:38 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:132 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:168 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementUserEditor.html.ep:32 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:89 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:110 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:104 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:207 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:58 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:38 msgid "Section" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:17 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/browse_library_panel_advanced.html.ep:33 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/browse_library_panel_simple.html.ep:30 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:99 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:17 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/browse_library_panel_advanced.html.ep:33 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/browse_library_panel_simple.html.ep:30 msgid "Section:" msgstr "" @@ -7394,28 +7664,33 @@ msgstr "" msgid "Section: %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:169 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:178 msgid "See \"Reduced Scoring Date\"." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:211 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:220 msgid "See \"Restrict Release by Set(s)\"." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:337 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:348 msgid "See \"Time Interval for New Versions\"." msgstr "" +#. (link_to( ($_->policy =~ s/^Perl::Critic::Policy:://r) +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep:21 +msgid "See %1." +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/sample_problem.html.ep:71 msgid "See Also" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:544 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:547 msgid "Seed" msgstr "" #. (defined $record{seed} && $record{seed} ne '' ? $record{seed} : maketext('unknown') -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:37 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:36 msgid "Seed: %1" msgstr "" @@ -7423,7 +7698,7 @@ msgstr "" msgid "Select" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:82 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:83 msgid "Select All Sets" msgstr "" @@ -7435,6 +7710,10 @@ msgstr "" msgid "Select Course IDs" msgstr "" +#: /opt/webwork/webwork2/templates/HTML/StudentNav/student_nav.html.ep:29 +msgid "Select Student to Act As" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_otp_secrets_form.html.ep:52 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_otp_secrets_form.html.ep:84 msgid "Select User ID" msgstr "" @@ -7459,6 +7738,10 @@ msgstr "" msgid "Select a Set from this Course" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz/nav.html.ep:40 +msgid "Select a Test to Review" +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/AdminArchiveCourse.html.ep:5 msgid "Select a course to create a .tar.gz archive of, which contains a dump of the database and all course files (templates, configuration files, etc). Each course can only have a single archive. Creating an archive of a previously archived course will delete the old archive." msgstr "" @@ -7503,7 +7786,7 @@ msgstr "" msgid "Select all jobs" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:34 /opt/webwork/webwork2/templates/ContentGenerator/LTI/content_item_selection.html.ep:37 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:72 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:77 /opt/webwork/webwork2/templates/ContentGenerator/LTI/content_item_selection.html.ep:37 msgid "Select all sets" msgstr "" @@ -7527,7 +7810,11 @@ msgstr "" msgid "Select course(s) to hide or unhide." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:18 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:18 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:25 +msgid "Select filename below" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:24 msgid "Select filenames below" msgstr "" @@ -7629,7 +7916,7 @@ msgstr "" msgid "Select which users in the %1 course to copy over to the newly created course. The WeBWorK administrators need to be added to the course in order for them to access the course. Unselecting them will make it so WeBWorK administrators cannot directly login to the course." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:114 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:100 msgid "Select your favorite theme for the large text window." msgstr "" @@ -7669,7 +7956,7 @@ msgstr "" msgid "Send Instructor Email" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:54 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:59 msgid "Send email to students." msgstr "" @@ -7717,7 +8004,7 @@ msgstr "" msgid "Set Actions" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:903 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:967 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:971 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:980 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail/ip_locations_row.html.ep:11 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:861 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:927 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:954 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:960 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:969 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail/ip_locations_row.html.ep:11 msgid "Set Default" msgstr "" @@ -7725,7 +8012,7 @@ msgstr "" msgid "Set Definition Files" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:216 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:220 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:217 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:221 msgid "Set Description" msgstr "" @@ -7733,11 +8020,11 @@ msgstr "" msgid "Set Detail Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:412 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:419 msgid "Set Detail for set %2" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:88 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:97 msgid "Set Header" msgstr "" @@ -7746,10 +8033,14 @@ msgstr "" msgid "Set Header for set %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm:197 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm:197 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:91 msgid "Set ID" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:55 +msgid "Set ID:" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LoginProctor.pm:102 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/info.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/info.html.ep:3 msgid "Set Info" msgstr "" @@ -7758,7 +8049,7 @@ msgstr "" msgid "Set LMS context ids for courses to map LMS courses to WeBWorK courses for content item selection." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:20 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:64 msgid "Set List" msgstr "" @@ -7766,15 +8057,19 @@ msgstr "" msgid "Set Name" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:203 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:204 msgid "Set Parameters" msgstr "" +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:81 +msgid "Set Statistics" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:23 msgid "Set Status Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:705 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:672 msgid "Set Values" msgstr "" @@ -7791,6 +8086,14 @@ msgstr "" msgid "Set definition (\".def\") files" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:92 +msgid "Set header file" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:56 +msgid "Set header file:" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Base/set_status.html.ep:23 msgid "Set is closed." msgstr "" @@ -7825,7 +8128,7 @@ msgstr "" msgid "Sets" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:406 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:29 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:413 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:27 msgid "Sets Manager" msgstr "" @@ -7833,12 +8136,12 @@ msgstr "" msgid "Sets Manager Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:401 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:408 msgid "Sets assigned to %1" msgstr "" #. ($userName, $userID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:87 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:88 msgid "Sets assigned to %1 (%2)" msgstr "" @@ -7846,7 +8149,7 @@ msgstr "" msgid "Sets assigned to student Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:928 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:931 msgid "Sets how grades will be passed back from WeBWorK to the LMS.
    course
    Sends a single grade back to the LMS. This grade is calculated out of the total question set that has been assigned to a user and made open. Therefore it can appear low, since it counts problem sets with future due dates as zero.
    homework
    Sends back a score for each problem set (including for each quiz). To use this, the external links from the LMS must be problem set specific. For example, webwork.myschool.edu/webwork2/course-name/problem_set_name. If the problem set name has space characters, they should be underscores in these addresses. Also, to initialize the communication between WeBWorK and the LMS, the user must follow each of these external learning tools at least one time. Since there must be a separate external tool link for each problem set, this option requires more maintenance of the LMS course.
    " msgstr "" @@ -7856,7 +8159,7 @@ msgid "Sets sorted by %1 in %plural(%2,ascending,descending) order, and then by msgstr "" #. ($c->maketext(FIELD_PROPERTIES() -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:330 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:353 msgid "Sets sorted by %1 in %plural(%2,ascending,descending) order, then by %3 in %plural(%4,ascending,descending) order,and then by %5 in %plural(%6,ascending,descending) order." msgstr "" @@ -7864,7 +8167,7 @@ msgstr "" msgid "Sets the order in which achievements are listed and evaluated. Achievements in the \"level\" category are always listed and evaluated after all other achievements." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1051 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1054 msgid "Sets the time in seconds to periodically update the LMS scores. WeBWorK will update all scores on the LMS if it has been longer than this time since the completion of the last update. This is only an approximate time. Mass updates of this nature may put significant strain on the server, and should not be set to happen too frequently. -1 disables these periodic updates." msgstr "" @@ -7885,7 +8188,7 @@ msgstr "" msgid "Setup One-Time Password Authentication" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:37 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:41 msgid "Shift dates so that the earliest is" msgstr "" @@ -7898,31 +8201,39 @@ msgstr "" msgid "Show %1 more like this" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:36 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:40 msgid "Show By Date" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:42 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:46 msgid "Show By Type" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:722 /opt/webwork/webwork2/templates/ContentGenerator/Problem/instructor_buttons.html.ep:5 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:121 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:127 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:39 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:134 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:746 /opt/webwork/webwork2/templates/ContentGenerator/Problem/instructor_buttons.html.ep:5 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:125 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:131 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:39 msgid "Show Correct Answers" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:79 +msgid "Show Correct Answers:" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:24 msgid "Show Date & Size" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:511 -msgid "Show Hints After" +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:519 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:135 +msgid "Show Hints" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:80 +msgid "Show Hints:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1133 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1136 msgid "Show LTI parameters (for debugging)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:495 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:570 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:55 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:91 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:506 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:572 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:55 /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:91 msgid "Show Me Another" msgstr "" @@ -7930,16 +8241,16 @@ msgstr "" msgid "Show Me Another Exhausted" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1598 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:759 -msgid "Show Past Answers" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:133 +msgid "Show Old Answers" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/instructor_buttons.html.ep:14 -msgid "Show Problem Grader" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:78 +msgid "Show Old Answers:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:730 -msgid "Show Problem Graders" +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1539 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:774 +msgid "Show Past Answers" msgstr "" #: /opt/webwork/webwork2/templates/HelpFiles/Hardcopy.html.ep:29 @@ -7950,23 +8261,31 @@ msgstr "" msgid "Show Problem Source File:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:392 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:403 msgid "Show Problems on Finished Versions" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:374 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:385 msgid "Show Scores on Finished Versions" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:136 +msgid "Show Solutions" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:81 +msgid "Show Solutions:" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:223 msgid "Show Total Homework Grade on Grades Page" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/student_nav.html.ep:77 +#: /opt/webwork/webwork2/templates/HTML/StudentNav/student_nav.html.ep:76 msgid "Show all students" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz/nav.html.ep:91 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz/nav.html.ep:100 msgid "Show all tests" msgstr "" @@ -7974,7 +8293,7 @@ msgstr "" msgid "Show automatic answer feedback" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:105 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:91 msgid "Show available autocompletions at the current cursor location." msgstr "" @@ -8028,12 +8347,12 @@ msgid "Showing %1 out of %2 achievements." msgstr "" #. (scalar @{ $c->{visibleSetIDs} }, scalar @{ $c->{allSetIDs} }) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:120 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:121 msgid "Showing %1 out of %2 sets." msgstr "" #. (scalar(keys %{ $c->{visibleUserIDs} }) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList.html.ep:88 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList.html.ep:93 msgid "Showing %1 out of %2 users" msgstr "" @@ -8054,15 +8373,15 @@ msgstr "" msgid "Showing all sets." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Problem/student_nav.html.ep:70 +#: /opt/webwork/webwork2/templates/HTML/StudentNav/student_nav.html.ep:69 msgid "Showing all students" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz/nav.html.ep:81 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz/nav.html.ep:90 msgid "Showing all tests" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:266 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:289 msgid "Showing all users." msgstr "" @@ -8096,7 +8415,7 @@ msgstr "" msgid "Showing matching sets." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:272 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:295 msgid "Showing matching users." msgstr "" @@ -8104,7 +8423,7 @@ msgstr "" msgid "Showing problem for:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:26 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:27 msgid "Showing progress for:" msgstr "" @@ -8120,7 +8439,7 @@ msgstr "" msgid "Showing selected sets." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:269 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:292 msgid "Showing selected users." msgstr "" @@ -8132,7 +8451,7 @@ msgstr "" msgid "Shows how many instructors and students have been assigned this problem set, out of the total number in the class. Clicking on this link allows you to assign the set to users, unassign this set from users, and to individually edit the assignment for specific users. For changing dates for individual users there are also shortcuts from the \"Instructor Tools\" link." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:853 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:856 msgid "Simple" msgstr "" @@ -8200,7 +8519,7 @@ msgstr "" msgid "Source Course ID" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:464 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:475 msgid "Source File" msgstr "" @@ -8212,23 +8531,31 @@ msgstr "" msgid "Source User IDs" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2584 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2686 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2585 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2687 msgid "Source course ID missing." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1667 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1695 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1733 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:40 +msgid "Source file" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1648 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1677 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1714 msgid "Source file paths cannot include .. or start with /: your source file path was modified." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2585 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:31 +msgid "Source file:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2586 msgid "Source user ID missing." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:124 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:110 msgid "Spell check the text of the file that your are editing. Note that there will be many spelling errors in the code parts of your file." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:854 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:857 msgid "Standard" msgstr "" @@ -8236,7 +8563,7 @@ msgstr "" msgid "Standard Deviation" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:172 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:169 msgid "Start" msgstr "" @@ -8244,7 +8571,7 @@ msgstr "" msgid "Start LTI Grade Update" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:136 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:139 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:133 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:136 msgid "Start New Test" msgstr "" @@ -8256,7 +8583,7 @@ msgstr "" msgid "State" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:82 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:87 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:485 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:39 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:492 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/siblings.html.ep:9 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:39 msgid "Statistics" msgstr "" @@ -8265,25 +8592,24 @@ msgid "Statistics Help" msgstr "" #. ($c->tag('span', dir => 'ltr', format_set_name_display($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:73 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:72 msgid "Statistics for %1" msgstr "" #. ($c->tag('span', dir => 'ltr', format_set_name_display($setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:77 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:76 msgid "Statistics for %1 problem %2" msgstr "" -#. ($c->{studentID}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:71 -msgid "Statistics for student %1" +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:557 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:167 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:45 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:289 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:151 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:50 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:167 +msgid "Status" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:554 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:308 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:151 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats/set_stats.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:50 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:170 -msgid "Status" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:35 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:98 +msgid "Status:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:29 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/login_status.html.ep:31 msgid "Stop Acting" msgstr "" @@ -8291,15 +8617,15 @@ msgstr "" msgid "Stop Archiving" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1105 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1106 msgid "Stop archiving courses" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:107 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:67 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:87 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:101 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:43 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:111 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:67 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:87 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:101 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:43 msgid "Student ID" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:9 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:91 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers/student_entry_report.html.ep:9 msgid "Student ID:" msgstr "" @@ -8307,7 +8633,7 @@ msgstr "" msgid "Student Name" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:67 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:72 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:507 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:41 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:67 /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:509 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/siblings.html.ep:8 /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:41 msgid "Student Progress" msgstr "" @@ -8349,7 +8675,7 @@ msgstr "" msgid "Subject Area Problems" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:52 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/SampleProblemViewer.pm:48 msgid "Subject Areas" msgstr "" @@ -8391,7 +8717,7 @@ msgid "Success index is the square of the score divided by the number of attempt msgstr "" #. ($archive_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1051 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1052 msgid "Successfully archived the course %1." msgstr "" @@ -8417,17 +8743,17 @@ msgstr "" #. ($delete_courseID) #. ($archive_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1083 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:864 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1084 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:865 msgid "Successfully deleted the course %1." msgstr "" #. ($rename_oldCourseID, $rename_newCourseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:748 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:749 msgid "Successfully renamed the course %1 to %2" msgstr "" #. ($unarchive_courseID, $new_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1262 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1263 msgid "Successfully unarchived %1 to the course %2" msgstr "" @@ -8439,15 +8765,15 @@ msgstr "" msgid "TA:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2766 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2767 msgid "Table defined in database but missing in schema" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2761 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2762 msgid "Table defined in schema but missing in database" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2757 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2758 msgid "Table is ok" msgstr "" @@ -8463,12 +8789,12 @@ msgstr "" msgid "Task" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:44 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/hardcopy_form.html.ep:42 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:45 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/hardcopy_form.html.ep:42 msgid "TeX Source" msgstr "" #. ($problems->[ $probOrder->[$i] ]->problem_id) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:553 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:559 msgid "Template ID: %1" msgstr "" @@ -8476,11 +8802,11 @@ msgstr "" msgid "Template Substitutions" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:256 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:265 msgid "Test" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:336 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:343 msgid "Test %2" msgstr "" @@ -8488,27 +8814,32 @@ msgstr "" msgid "Test Default" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1078 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1068 msgid "Test Parameters" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:185 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:186 msgid "Test Time" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:274 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:283 msgid "Test Time Limit" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:255 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:236 msgid "Test Time Notification" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:166 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:163 msgid "Test Versions" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:242 +#. ($c->{completedTime}) +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:338 +msgid "Test completed on %1." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:257 msgid "Test not yet submitted." msgstr "" @@ -8516,7 +8847,7 @@ msgstr "" msgid "Test/Quiz" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:40 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:44 msgid "Tests/Quizzes" msgstr "" @@ -8524,11 +8855,11 @@ msgstr "" msgid "Text" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:110 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:96 msgid "Text Editor Options" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:60 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:46 msgid "Text Editor Window" msgstr "" @@ -8552,7 +8883,7 @@ msgstr "" msgid "The \"Score\" tab will export achievement data to a CSV file that can be downloaded. The export contains the global data including number of achievement points and current level of each student. In addition for each selected achievement, a column for if the achievement was earned (1) or not earned (0) will be added to the CSV." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:191 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:201 msgid "The Assigned sets column (x/y) indicates that x sets out of y sets avaiable have been assigned to this student. Click this link to assign or unassign sets to this student, to adjust due dates, or to adjust the grades on an assignment for a student." msgstr "" @@ -8560,11 +8891,11 @@ msgstr "" msgid "The Set Detail page can be viewed in one of two distinct modes:" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:186 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:196 msgid "The login name column links allow you to \"act as\" a student." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:188 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:198 msgid "The pencil in the login column allows you to edit that student's data." msgstr "" @@ -8635,15 +8966,15 @@ msgid "The archive filename may not contain a path component" msgstr "" #. ($filename, $ce->{mail}{maxAttachmentSize}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:187 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:184 msgid "The attached file \"%1\" exceeds the allowed attachment size of %quant(%2,megabyte)." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:617 -msgid "The child problems for this problem will become visible to the student when they either have more incorrect attempts than is specified here, or when they run out of attempts, whichever comes first. Use -1 to indicate that child problems should only be available after a student runs out of attempts." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:591 +msgid "The child problems for this problem will become visible to the student when they either have more incorrect attempts than is specified here, or when they run out of attempts, whichever comes first. Select \"No Attempts Remaining\" to indicate that child problems should only be available after a student runs out of attempts." msgstr "" -#. ('href="http://webwork.maa.org/wiki/Classlist_Files#Format_of_classlist_files" target="Webworkdocs"', 'demoCourse.lst', '.csv', '.lst') +#. ('href="https://wiki.openwebwork.org/wiki/Classlist_Files#Format_of_classlist_files" target="Webworkdocs"', 'demoCourse.lst', '.csv', '.lst') #: /opt/webwork/webwork2/templates/HelpFiles/InstructorFileManager.html.ep:43 msgid "The classlist files are stored in the templates directory and provide a convenient way to enter a large number of students into your class. To view the format for ClassList files see the ClassList specification or download the %2 file and use it as a model. ClassList files can be prepared using a spreadsheet and then saved as %3 (comma separated values) text files. However, to access as a classlist file, the file suffix needs to be changed to %4, which can be done with the \"Rename\" button." msgstr "" @@ -8653,17 +8984,17 @@ msgstr "" msgid "The close date must be on or after the open date for set %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1395 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1378 msgid "The close date must be on or after the open date." msgstr "" #. ($courseID, $_) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2448 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2449 msgid "The context id for %1 is requested to be set to be the same as that of %2, and both courses are configured to use LTI 1.1, but the consumer keys for the two courses are either not both set or are the same." msgstr "" #. ($courseID, $_,) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2466 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2467 msgid "The context id for %1 is requested to be set to be the same as that of %2, but the two courses are configured to use LTI 1.3 with the same LTI 1.3 authentication parameters." msgstr "" @@ -8671,7 +9002,7 @@ msgstr "" msgid "The correct answers shown in feedback are instructor previews and will only be shown to students after the answer date." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:615 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:631 msgid "The correct answers shown in feedback are instructor previews and will only be shown to students when answers are available." msgstr "" @@ -8746,7 +9077,7 @@ msgstr "" msgid "The directory you specified doesn't exist" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:847 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:850 msgid "The email verbosity level controls how much information is automatically added to feedback emails. Levels are
    1. Simple: send only the feedback comment and context link
    2. Standard: as in Simple, plus user, set, problem, and PG data
    3. Debug: as in Standard, plus the problem environment (debugging data)
    " msgstr "" @@ -8841,7 +9172,7 @@ msgid "The file you are trying to download doesn't exist" msgstr "" #. ($filename) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:178 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Feedback.pm:175 msgid "The filetype of the attached file \"%1\" is not allowed." msgstr "" @@ -8864,11 +9195,15 @@ msgstr "" msgid "The following %plural(%1,file) found in the archive %plural(%1,is,are) protected and were not extracted." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2260 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep:11 +msgid "The following PG issues should be fixed:" +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2261 msgid "The following courses were successfully hidden:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2329 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2330 msgid "The following courses were successfully unhidden:" msgstr "" @@ -8880,8 +9215,12 @@ msgstr "" msgid "The following files have been selected for archiving. Select the type of archive and any subset of the requested files." msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep:44 +msgid "The following general Perl issues should be fixed:" +msgstr "" + #. (tag('b', join(', ', @$unassignedUsers) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:70 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:71 msgid "The following users are NOT assigned to this set and will be ignored: %1" msgstr "" @@ -8899,12 +9238,12 @@ msgid "The goal value of the achievement counter." msgstr "" #. (join('.', @{ $problemSeqs[ $children_counts_indexs[0] ] }) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1293 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1234 msgid "The grade for this problem is the larger of the score for this problem, or the score of problem %1." msgstr "" #. (join(', ', map({ join('.', @{ $problemSeqs[$_] }) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1303 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1244 msgid "The grade for this problem is the larger of the score for this problem, or the weighted average of the problems: %1." msgstr "" @@ -8948,21 +9287,11 @@ msgstr "" msgid "The institution associated with the course %1 is now %2" msgstr "" -#. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:386 -msgid "The instructor account with user id %1 does not exist. Instructor accounts must be created manually." -msgstr "" - -#. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:565 -msgid "The instructor account with user id %1 does not exist. Please create the account manually via WeBWorK." -msgstr "" - #: /opt/webwork/webwork2/templates/HelpFiles/InstructorJobManager.html.ep:13 msgid "The job id is an automatically incremented integer. It is used internally to uniquely identify jobs. It is also used to reference jobs in messages on this page." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:117 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:103 msgid "The key maps that are available are \"default\", \"emacs\", \"sublime\", and \"vim\". The \"default\" key map has the standard behavior of a browser text area. You can use Ctrl-C to copy, Ctrl-V to paste, Ctrl-F to search, etc. If you are more comfortable with the \"emacs\" or \"vim\" text editors then you may choose to use one of those key maps instead." msgstr "" @@ -8978,11 +9307,7 @@ msgstr "" msgid "The login name cannot be changed. (It is the primary key for the student's data.) If you make a mistake in the login name at the beginning of the course (before any work has been done) then it is best to simply add a new student with the correct entry and drop the student with the bad login name. (See drop and delete students below.) If the login name must be changed after a user has started working assignments, then contact your system administrator, who can use the webwork2 \"bin/change_user_id\" script to change the user id." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorStats.html.ep:5 -msgid "The main page allows access to set and student statistics. When selecting a student, their grades page is shown, which lists set totals and per problem grades for each set assigned to the student. When selecting a set, various statistics and histograms are shown for the overall grades of students who are currently enrolled or auditing the course." -msgstr "" - -#. ('href="http://webwork.maa.org/wiki" target="ww_wiki"', 'href="http://webwork.maa.org/wiki/Instructors" target="ww_wiki"') +#. ('href="https://wiki.openwebwork.org/wiki" target="ww_wiki"', 'href="https://wiki.openwebwork.org/wiki/Instructors" target="ww_wiki"') #: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:9 msgid "The main page for WeBWorK documentation is the webwork wiki while specific help for instructors setting up a course are in the instructors' section." msgstr "" @@ -8996,11 +9321,11 @@ msgstr "" msgid "The name of course information file (located in the templates directory). Its contents are displayed in the right panel next to the list of homework sets." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:897 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:900 msgid "The name of the LMS" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:899 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:902 msgid "The name of the LMS. This is used in messages to users that direct them to go back to the LMS to access something in the WeBWorK course." msgstr "" @@ -9065,11 +9390,6 @@ msgstr "" msgid "The permission level to view usernames on the achievements leaderboard. Consider that achievement points can be closely tied to student grades before showing user names to students." msgstr "" -#. ($setName) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:444 -msgid "The prerequisite conditions have not been met for set '%1'." -msgstr "" - #. (q(down menu to change which student's seed and answers are shown. Use the "Mark Correct" checkbox to set) #: /opt/webwork/webwork2/templates/HelpFiles/InstructorProblemGrader.html.ep:11 msgid "The problem is shown at the top with the seed and answers of the selected student. Use the drop " @@ -9088,7 +9408,7 @@ msgstr "" msgid "The reduced scoring date must be between the open date and the close date for set %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1390 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1373 msgid "The reduced scoring date should be between the open date and close date." msgstr "" @@ -9101,13 +9421,13 @@ msgstr "" msgid "The requested LMS Context ID is the same as that of another course that is also configured to use LTI 1.3, but this course and that course have the same LTI 1.3 authentication parameters. This is not allowed, and so this setting was not saved." msgstr "" -#. ($tempFile) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:287 +#. (xml_escape($tempFile) +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:291 msgid "The requested file \"%1\" does not exist on the server." msgstr "" #. (join('.', @seq) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1346 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1287 msgid "The score for this problem can count toward score of problem %1." msgstr "" @@ -9120,12 +9440,12 @@ msgstr "" msgid "The second row of the problem collection area is for browsing directories. The OPL will be there as well as any other directories that you may set up (for example Contrib). If this is selected, all subdirectories containing problems will be listed." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:485 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:508 msgid "The security code is required." msgstr "" #. (stash('setID') -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet.html.ep:13 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet.html.ep:18 msgid "The selected problem set (%1) is not a valid set for %2." msgstr "" @@ -9174,7 +9494,7 @@ msgstr "" msgid "The solution shown is an instructor preview and will only be shown to students after the answer date." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:597 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:613 msgid "The solution shown is an instructor preview and will only be shown to students when answers are available." msgstr "" @@ -9199,7 +9519,7 @@ msgid "The temporary file %1 is not in the course templates directory and cannot msgstr "" #. ($setVersionID) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:368 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:351 msgid "The test (which is version %1) may no longer be submitted for a grade." msgstr "" @@ -9238,7 +9558,7 @@ msgstr "" msgid "The title of the course %1 is now %2" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:196 +#: /opt/webwork/webwork2/templates/ContentGenerator/Grades/student_stats.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:197 msgid "The top number is the percent score on the problem. A period (.) indicates a problem has not been attempted. The bottom number is the number of incorrect attempts." msgstr "" @@ -9279,7 +9599,7 @@ msgstr "" msgid "The webwork server must be able to write to these directories. Please correct the permssion errors." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:90 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:113 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:90 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:99 msgid "Theme" msgstr "" @@ -9298,11 +9618,16 @@ msgstr "" msgid "There are %1 matching WeBWorK problems" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1587 +#. ('%d') +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:728 +msgid "There are %1 problems with unanswered questions." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1588 msgid "There are database fields that do not have the same type as the field defined in the schema for at least one table." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1426 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1427 msgid "There are database fields that do not have the same type as the field defined in the schema for at least one table. Check the checkbox by the field to change its type when upgrading the course. Warning: This can fail which may corrupt the table. If you have not archived this course, then do that now before upgrading if you want to change the type of any of these fields." msgstr "" @@ -9315,11 +9640,11 @@ msgid "There are database fields that do not have the same type as the field def msgstr "" #. (map { $_ ? $c->formatDateTime($_, 'datetime_format_short') -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1374 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1357 msgid "There are errors in the dates. Open Date: %1 , Close Date: %2, Answer Date: %3" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1410 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1411 msgid "There are extra database fields which are not defined in the schema and were part of the key for at least one table. These fields must be deleted and the table indexes rebuilt. Warning: This will destroy all data contained in the field and is not undoable!" msgstr "" @@ -9327,7 +9652,7 @@ msgstr "" msgid "There are extra database fields which are not defined in the schema and were part of the key for at least one table. These fields need to be deleted and the table indexes need to be rebuilt. This will be done when upgrading the course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1575 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1576 msgid "There are extra database fields which are not defined in the schema for at least one table." msgstr "" @@ -9335,15 +9660,15 @@ msgstr "" msgid "There are extra database fields which are not defined in the schema for at least one table. They can be removed when upgrading the course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1395 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1396 msgid "There are extra database fields which are not defined in the schema for at least one table. Check the checkbox by the field to delete it when upgrading the course. Warning: Deletion destroys all data contained in the field and is not undoable!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1564 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1565 msgid "There are extra database tables which are not defined in the schema." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1380 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1381 msgid "There are extra database tables which are not defined in the schema. " msgstr "" @@ -9355,7 +9680,7 @@ msgstr "" msgid "There are many options available at the bottom:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:56 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:60 msgid "There are no assignments available to you at this time." msgstr "" @@ -9381,11 +9706,11 @@ msgstr "" msgid "There is NO undo for this function. Do not use it unless you know what you are doing! When you unassign a student using this button, or by unchecking their name, you destroy all of the data for assignment %1 for this student." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:67 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:68 msgid "There is NO undo for unassigning a set." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:120 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:121 msgid "There is NO undo for unassigning sets. Do not do so unless you know what you are doing! When you unassign sets by unchecking set names and clicking save, you destroy all of the data for those sets for this student." msgstr "" @@ -9393,7 +9718,11 @@ msgstr "" msgid "There is NO undo for unassigning students." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:402 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:729 +msgid "There is a problem with unanswered questions." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:404 msgid "There is a solution available." msgstr "" @@ -9402,12 +9731,12 @@ msgstr "" msgid "There is no additional grade information. A message about additional grades can go in [TMPL]/email/%1. It is merged with the file [Scoring]/%2. These files can be edited using the \"Email\" link and the \"File Manager\" link in the left margin." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:410 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:412 msgid "There is no solution available for this problem." msgstr "" #. ($continueTimeLeft) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:25 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:22 msgid "There is no time remaining on the currently open test. Click continue below and then click \"Grade Test\" within %1 seconds to submit the test for a grade." msgstr "" @@ -9415,7 +9744,7 @@ msgstr "" msgid "There is no undo for deleting files or directories!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:407 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:409 msgid "There is no written solution available for this problem, but you can still view the correct answers." msgstr "" @@ -9423,15 +9752,15 @@ msgstr "" msgid "There is one main theme to choose from: math4. It has three variants: math4-green, math4-red, and math4-yellow. The theme specifies a unified look and feel for the WeBWorK course web pages." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:365 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:362 msgid "There was an error during the login process. Please speak to your instructor or system administrator if this recurs." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:123 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:243 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:261 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:297 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:422 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:432 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:466 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:505 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:109 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:213 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:234 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:84 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:97 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:120 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:243 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:261 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:296 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:418 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:487 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:109 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:214 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:235 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:84 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:97 msgid "There was an error during the login process. Please speak to your instructor or system administrator." msgstr "" -#. ('href="https://webwork.maa.org/wiki/Set_Definition_Files" target="Webworkdocs"') +#. ('href="https://wiki.openwebwork.org/wiki/Set_Definition_Files" target="Webworkdocs"') #: /opt/webwork/webwork2/templates/HelpFiles/InstructorFileManager.html.ep:32 msgid "These are stored in the templates directory. The format of Set Definition files is described in the Set Definition specification. Set definition files are mainly useful for transferring set assignments from one course to another and are created when exporting a problem set from the \"Sets Manager\". Each set definition file contains a list of problems used and the dates and times. These definitions can be imported into the current course." msgstr "" @@ -9511,7 +9840,7 @@ msgstr "" msgid "This course uses an external authentication system. You've authenticated through that system, but aren't allowed to log in to this course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:177 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:186 msgid "This date should be on or after the open date, and earlier or equal to the close date. Answers submitted between the reduced scoring date and the close date are scaled down by a factor that you can set in the Course Config page. If reduced scoring is being used, note that students will consider the reduced scoring date to be the \"due date\", since that is the date when they can no longer earn 100% for problems." msgstr "" @@ -9559,29 +9888,29 @@ msgstr "" msgid "This homework set contains no problems." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1190 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1131 msgid "This homework set is closed." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1188 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1129 msgid "This homework set is not yet open." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:560 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:563 msgid "This is a number between 0 and 1 indicating the student's score for the problem. Change this to 1 to manually award full credit on this problem." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:477 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:488 msgid "This is a relative weight to be attached to the problem, either in the context of scoring the set, or in the context of calculating a score for a collection of sets." msgstr "" #. ($hours, $minutes) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:109 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:106 msgid "This is a timed test. You will have %quant(%1,hour) and %quant(%2,minute) to complete the test." msgstr "" #. ($hours, $minutes) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:119 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:116 msgid "This is a timed test. You will have %quant(%1,hour,hours,)%quant(%2,minute,minutes,) to complete the test." msgstr "" @@ -9589,32 +9918,32 @@ msgstr "" msgid "This is done by first entering the user as a student and then changing the permission level of the user. First edit the user by clicking on the pencil next to their name (or using the technique above for several users), then change their permssion level -- an entry blank at the far right of the screen, you may have to scroll to see it. The permission levels are" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:153 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:163 msgid "This is done from the \"Sets Manager\" or from the \"Instructor Tools\" page if you wish to assign a set to all students or a large group of students (e.g. a section)." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:158 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:168 msgid "This is done from the \"Sets Manager\" or from the \"Instructor Tools\" page." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:168 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:178 msgid "This is done from the \"Sets Manager\" page or the \"Instructor tools\" page." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:115 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:124 msgid "This is generally the date when students can begin visiting the set and submitting answers. Prior to this date, if the set is assigned to a user and it is flagged \"visible\", they can see that it exists and when it will open, but cannot view the problems. If using \"course\" grade passback to an LMS, only those sets that are past their open date are factored in to the overall course grade that is passed back. Note that certain permissions can be changed so that the details explained here are no longer true." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:142 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:151 msgid "This is generally the date when students can click a checkbox to see the expected correct answers to problems in the set. If a problem has a coded solution, this is also when thy can click to see that solution. Note that certain permissions can be changed so that the details explained here are no longer true. This date must come on or after the close date." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:129 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:138 msgid "This is generally the date when students can no longer use the \"Submit\" button to submit an answer and have it assessed for credit. However students can still visit the set, type or select answers, and use the \"Check Answers\" button to be assessed without credit. Note that certain permissions can be changed so that the details explained here are no longer true. This date must come on or after the open date." msgstr "" #: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:63 -msgid "This is most easily done by importing a class list. The class list can be uploaded from your workstation to the server using the File Manager page. The class list must be a file ending in .lst and must have a specific format. Once the file has been uploaded to the server the file will appear in the import action pop-up list (5th action). demoCourse.lst is available for most courses and adds the \"practice users\" which activate guest logins to the class list." +msgid "This is most easily done by importing a class list. The class list can be uploaded from your workstation to the server using the File Manager page. The class list must be a file ending in .lst and must have a specific format. Once the file has been uploaded to the server the file will appear in the import action pop-up list (5th action). demoCourse.lst is available for most courses and adds the \"practice users\" which activate guest logins to the class list." msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:39 @@ -9673,44 +10002,35 @@ msgstr "" msgid "This is where email messages and templates are saved. You can upload or download files in this directory if you wish to save the files for later." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:62 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:48 msgid "This is where you edit the code of the problem. Type Ctrl-Enter while this window has focus to re-render the problem. In addition, the following keyboard shortcuts are available." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:702 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:718 msgid "This is your last submission. If you say yes, then your answers will be final, and you will not be able to continue to work this test version." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:706 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:722 msgid "This is your only submission. If you say yes, then your answers will be final, and you will not be able to continue to work this test version." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/ReducedCred.pm:34 +#: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm:39 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/NoReducedCred.pm:34 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/ReducedCred.pm:34 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm:39 msgid "This item won't work unless your instructor enables the reduced scoring feature. Let your instructor know that you received this message." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm:39 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/NoReducedCred.pm:34 /opt/webwork/webwork2/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm:39 -msgid "This item won't work unless your instructor enables the reduced scoring feature. Let your instructor know that you recieved this message." -msgstr "" - -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:27 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:26 msgid "This link gives details for many macros. It links to documentation embedded in the macro files themselves." msgstr "" -#. ('PGMLLab/PGML-lab.pg') -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:48 -msgid "This links to a WeBWorK \"problem\" which allows you to try out fragments of PGML code. This link will not be available if the file %1 is not located in the templates directory of the course." +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:35 +msgid "This links to a WeBWorK \"problem\" which allows you to try out fragments of PGML code." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:18 -msgid "This links to a list of problem authoring techniques." -msgstr "" - -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:24 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:23 msgid "This links to a page describing Math Object usage." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:57 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:43 msgid "This links to problem authoring information on the WeBWorK wiki." msgstr "" @@ -9718,15 +10038,19 @@ msgstr "" msgid "This may be Mathjax, images, or plainText. Only the options that are enabled for the course will be available to select. This option is only visible if there is more than one display mode enabled for the course." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1145 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1148 msgid "This must be set in order to utilize LTI content selection. The WeBWorK content item URL must be set for the external tool in the LMS first. Then if content selection from the LMS is attempted, you will be shown the LMS context ID. Enter the context ID shown here, and then you will be able to select assignments from this course, and import them into the LMS." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:549 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:552 msgid "This number is used to control how the random elements of the problem will be generated. Change this number to rerandomize a student's version." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep:23 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:39 +msgid "This option analyzes the code with PG Critic which gives suggestions on using modern PG constructs and ensures that the code conforms to current best-practices." +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep:23 msgid "This option converts the text blocks in the problem code to PGML and updates the loadMacros to include PGML and drop others. This can be used as a first pass of the conversion, however the author will still need to ensure the problem functions. One area of attention should be the answer blanks, which may not be converted correctly." msgstr "" @@ -9807,7 +10131,7 @@ msgstr "" msgid "This permission level and higher can use the problem grader (both the grader that is available on a problem page and the set-wide probelem grader)." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1282 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1532 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1223 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1473 msgid "This problem has open subproblems. You can visit them by using the links to the left or visiting the set page." msgstr "" @@ -9816,11 +10140,11 @@ msgid "This problem is not valid." msgstr "" #. ($prettyID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:420 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:421 msgid "This problem uses the same source file as number %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:373 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:374 msgid "This problem will not count toward your grade." msgstr "" @@ -9843,7 +10167,7 @@ msgid "This sample mail would be sent to %1" msgstr "" #. (join('.', @seq) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1355 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1296 msgid "This score for this problem does not count for the score of problem %1 or for the set." msgstr "" @@ -9852,16 +10176,16 @@ msgstr "" msgid "This scoring message is generated from [TMPL]/email/%1. It is merged with the file [Scoring]/%2. These files can be edited using the \"Email\" link and the \"File Manager\" link in the left margin." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1076 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1079 msgid "This secret word is used to validate logins from an LMS using LTI 1.1. This secret word must match the word configured in the LMS." msgstr "" #. (tag('strong', dir => 'ltr', format_set_name_display($setID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:159 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:160 msgid "This set %1 is assigned to %2." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:694 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:695 msgid "This set doesn't contain any problems yet." msgstr "" @@ -9874,7 +10198,7 @@ msgstr "" msgid "This set has a set-level proctor password to authorize logins. Enter the password below." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:366 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:70 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:367 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:76 msgid "This set is hidden from students." msgstr "" @@ -9887,7 +10211,7 @@ msgstr "" msgid "This set is not assigned to any students." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:365 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:68 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:366 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:74 msgid "This set is visible to students." msgstr "" @@ -9895,84 +10219,96 @@ msgstr "" msgid "This set or problem is not valid." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:190 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:199 msgid "This set will be unavailable to students until they have earned the \"Score Required for Release\" on the sets specified in this field. The sets should be written as a comma separated list." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:281 -msgid "This sets a number of minutes for each version of a test, once it is started. Use \"0\" to indicate no time limit. If there is a time limit, then there will be an indication that this is a timed test on the main \"Assignments\" page. Additionally the student will be sent to a confirmation page beefore they can begin." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:290 +msgid "This sets a number of minutes for each version of a test, once it is started. Use \"0\" to indicate no time limit. If there is a time limit, then there will be an indication that this is a timed test on the main \"Assignments\" page. Additionally the student will be sent to a confirmation page before they can begin. Note that the actual time a student will have to complete a timed test is the product of this time limit and the accommodation time factor set for the student in the accounts manager." msgstr "" #: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:100 msgid "This should be done cautiously. Once a student is deleted from a course their data is lost forever and cannot be recovered. They can be added to the course as a new student, but all of their assignment data has been permanently deleted." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2102 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2081 msgid "This source file does not exist!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2101 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2080 msgid "This source file is a directory!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2103 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2082 msgid "This source file is not a plain file!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2100 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2079 msgid "This source file is not readable!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:521 -msgid "This specifies the number of attempts before hints are shown to students. The value of -2 uses the default from course configuration. The value of -1 disables hints. Note that this will only have an effect if the problem has a hint." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:527 +msgid "This specifies the number of attempts before hints are shown to students. If \"Never\" is selected, then hints are disabled. Note that this will only have an effect if the problem has a hint." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:538 -msgid "This specifies the rerandomization period: the number of attempts before a new version of the problem is generated by changing the Seed value. The value of -1 uses the default from course configuration. The value of 0 disables rerandomization." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:541 +msgid "This specifies the rerandomization period: the number of attempts before a new version of the problem is generated by changing the Seed value. Randomization is disabled if \"Never\" is selected." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:715 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:717 msgid "This test is closed. No new test versions may be taken." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:779 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:781 msgid "This test is not yet open." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:81 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:78 msgid "This test requires a proctor password to continue." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:126 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:123 msgid "This test requires a proctor password to start." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:829 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:828 msgid "This test version is past due, but has not been graded. You can still grade the test for this user." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:502 /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:508 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:400 /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:407 msgid "This user is not allowed to log in to this course" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:21 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:152 +msgid "Three code maintenance tools can be utilized. First, the code can be reformatted using perltidy. Using perltidy will change the code in the editor window, and save changes to the temporary file. In some cases (if the code contains backslashes or double tildes) this can result in odd spacing in the code. Second the code can be converted to PGML. This changes the code in text blocks to use PGML features. Generally the conversion of much of the formatting and LaTeX is performed correctly. However, answer blanks need attention. In any case, make sure to inspect the formatted code, and edit further or revert if needed. Third, the code can be analyzed by the \"PG Critic.\" This checks that the code does not use old or deprecated features of PG and conforms to current best-practices in problem authoring, and offers suggestions on how to fix issues that are found." +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:24 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:21 msgid "Time" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:315 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:326 msgid "Time Interval for New Versions" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:188 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:189 msgid "Time Remaining" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1049 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1052 msgid "Time in seconds to periodically update LMS grades (-1 to disable)" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:103 +msgid "Time interval" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:65 +msgid "Time interval:" +msgstr "" + #. ($c->{elapsedTime}, sprintf('%.0f', 10 * ($c->{set}->due_date - $c->{set}->open_date) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:355 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:336 msgid "Time taken on test: %1 min (%2 min allowed)." msgstr "" @@ -9988,13 +10324,13 @@ msgstr "" msgid "Title for course displayed on the Assignments page" msgstr "" -#. (sprintf('%.0f', $restriction) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:239 +#. (sprintf('%.0f', $set->restricted_status * 100) +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Sets.pm:272 msgid "To access this set you must score at least %1% on set %2." msgstr "" -#. (sprintf('%.0f', $restriction) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:245 +#. (sprintf('%.0f', $set->restricted_status * 100) +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Sets.pm:278 msgid "To access this set you must score at least %1% on the following sets: %2." msgstr "" @@ -10002,11 +10338,11 @@ msgstr "" msgid "To assign one or more sets to an individual student click in the column \"Assigned Sets\" in the student's row. This will take you to a page where you can assign and unassign sets and change the due dates for homework on an individual basis." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:78 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:79 msgid "To change status (scores or grades) for this student for one set, click on the individual set link." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:150 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:151 msgid "To copy components from an existing course, select the course and check which components to copy." msgstr "" @@ -10014,7 +10350,7 @@ msgstr "" msgid "To drop a student or students, select them for editing as described above and then set the pop-up list to enrolled, drop, or audit. Dropped students cannot log in to the course, are not assigned new sets and are not sent email. They can be re-enrolled simply by changing their status back to enrolled. No data is lost, any assignments assigned before they were dropped are restored unchanged." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:147 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:148 msgid "To edit a specific student version of this set, edit (all of) her/his assigned sets." msgstr "" @@ -10034,7 +10370,7 @@ msgstr "" msgid "To use the Email merge feature, upload a CSV with calculated grades to the scoring directory using the \"File Manager\"." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:908 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:46 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:68 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:866 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:50 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:34 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:68 msgid "Today" msgstr "" @@ -10042,11 +10378,11 @@ msgstr "" msgid "Toggle Sidebar" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:100 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:86 msgid "Toggle block comment. (Only has effect inside PGML blocks.)" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:96 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:82 msgid "Toggle comment." msgstr "" @@ -10054,11 +10390,11 @@ msgstr "" msgid "Toggle each of the options to include or not include in the output." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:490 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Stats.pm:488 msgid "Top Score" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:135 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:132 msgid "Top level of author information on the wiki." msgstr "" @@ -10070,11 +10406,11 @@ msgstr "" msgid "Total Points:" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:382 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:393 msgid "Totals only (not problem scores)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:383 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:394 msgid "Totals only, only after answer date" msgstr "" @@ -10102,17 +10438,17 @@ msgstr "" msgid "Type:" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:23 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:32 /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:23 msgid "URI" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:906 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:909 msgid "URL for the LMS" msgstr "" #. ($achievementName) #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/AchievementNotificationEditor.pm:217 -msgid "Unable to change the achievement notification template for achivement %1. Unknown error." +msgid "Unable to change the achievement notification template for achievement %1. Unknown error." msgstr "" #. ($achievementName) @@ -10140,6 +10476,10 @@ msgstr "" msgid "Unable to change the source file path for set %1, problem %2. Unknown error." msgstr "" +#: /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvanced.pm:452 /opt/webwork/webwork2/lib/WeBWorK/Authen/LTIAdvantage.pm:312 +msgid "Unable to create a WeBWorK user. Please speak to your instructor or system administrator." +msgstr "" + #. ($c->shortPath($delFilePath) #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:1345 msgid "Unable to delete backup file \"%1\"." @@ -10160,7 +10500,7 @@ msgstr "" msgid "Unable to disable the achievement notification template for achievement %1. Unknown error." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:574 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:573 msgid "Unable to generate a valid test version. This is usually caused by invalid usage of grouping sets or a database error. Please speak to your instructor to fix the error. A system administrator can obtain more details on this error from the logs." msgstr "" @@ -10173,7 +10513,7 @@ msgstr "" msgid "Unable to make \"%1\" the set header for %2." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:648 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:649 msgid "Unable to obtain error messages from within the PG question." msgstr "" @@ -10222,7 +10562,7 @@ msgstr "" msgid "Unarchive Course Help" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1295 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1296 msgid "Unarchive More" msgstr "" @@ -10247,11 +10587,11 @@ msgstr "" msgid "Unclassified Problems" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:95 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:81 msgid "Unfold all regions." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:92 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:78 msgid "Unfold the region that begins on the current line." msgstr "" @@ -10264,7 +10604,7 @@ msgid "Union" msgstr "" #. ($value) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:56 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:57 msgid "Unknown: %1" msgstr "" @@ -10273,7 +10613,7 @@ msgstr "" msgid "Unkown saveMode: %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:488 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:499 msgid "Unlimited" msgstr "" @@ -10302,11 +10642,11 @@ msgstr "" msgid "Unsupported archive type in file \"%1\"" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:104 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:105 msgid "Update Display" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:88 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:89 msgid "Update Grades" msgstr "" @@ -10314,7 +10654,7 @@ msgstr "" msgid "Update Interval" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:968 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:971 msgid "Update LMS grade with each submission" msgstr "" @@ -10331,7 +10671,7 @@ msgstr "" msgid "Update aborted. No sets selected." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:69 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:70 msgid "Update selected sets:" msgstr "" @@ -10339,7 +10679,7 @@ msgstr "" msgid "Update the checked courses?" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:51 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/LTIUpdate.html.ep:52 msgid "Update user:" msgstr "" @@ -10381,7 +10721,7 @@ msgstr "" msgid "Updated grades via LTI of all sets assigned to user %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2019 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2020 msgid "Updated location description." msgstr "" @@ -10390,11 +10730,11 @@ msgid "Upgrade" msgstr "" #. ($upgrade_courseID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1364 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1365 msgid "Upgrade %1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1277 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1278 msgid "Upgrade Course" msgstr "" @@ -10414,7 +10754,7 @@ msgstr "" msgid "Upgrade courses from a previous version of WeBWorK." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1694 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1695 msgid "Upgrade process completed" msgstr "" @@ -10422,20 +10762,20 @@ msgstr "" msgid "Upload" msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:57 +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:64 msgid "Upload, download and delete text files, including scoring spread sheets, set definition files, class list spread sheets, and \"PG\" problems." msgstr "" #. ($item->remaining_title($c) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:43 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:63 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:73 msgid "Use %1" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:17 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:60 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:67 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:36 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:91 msgid "Use Achievement Reward" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:295 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:296 msgid "Use Default Header File" msgstr "" @@ -10542,7 +10882,7 @@ msgstr "" msgid "Use this page to send emails to active (enrolled or auditing) students. Emails can be sent to all active students or selected students. Use the \"Students\" form to sort, filter, or format how the user name is displayed. If multiple filters are selected and the \"Intersection\" radio button is used, the filters will be applied in sequence, narrowing the results list. If the \"Union\" button is used, the updated list will be the union of all results lists from the multiple filters. Click \"Refresh List\" to apply any changes. Use control-click or shift-click to select multiple students to email." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:158 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:167 msgid "Use this to hide the existence of this set from students, even when it is assigned to them." msgstr "" @@ -10587,7 +10927,7 @@ msgid "User %1 is not authorized to proctor test logins in this course." msgstr "" #. ($userID) -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:37 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:38 msgid "User %1 not found." msgstr "" @@ -10595,28 +10935,32 @@ msgstr "" msgid "User Actions" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm:196 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:97 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/reset_otp_secrets_confirm.html.ep:8 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ShowAnswers.pm:196 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:98 /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/reset_otp_secrets_confirm.html.ep:8 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:156 msgid "User ID" msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:94 -msgid "User ID may contain only numbers, letters, hyphens, periods, and underscores." +msgid "User ID may contain only numbers, letters, hyphens, periods, commas, at symbols, and underscores." msgstr "" #. ($_) #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:275 -msgid "User ID number %1 may only contain letters, numbers, hyphens, periods, commas, and underscores." +msgid "User ID number %1 may only contain letters, numbers, hyphens, periods, commas, at symbols, and underscores." +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:87 +msgid "User ID:" msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/PODViewer.html.ep:18 msgid "User Interface" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:704 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:26 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:671 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail/set_date_table.html.ep:26 msgid "User Overrides" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2654 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2655 msgid "User does not exist - Skipping" msgstr "" @@ -10641,7 +10985,7 @@ msgid "User-Set Actions" msgstr "" #. ($user, $setID, $j) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1253 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1243 msgid "UserProblem missing for user=%1 set=%2 problem=%3. This may indicate database corruption." msgstr "" @@ -10653,7 +10997,7 @@ msgstr "" msgid "Users" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:418 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Routes.pm:425 msgid "Users Assigned to Set %2" msgstr "" @@ -10661,7 +11005,7 @@ msgstr "" msgid "Users Assigned to Set Help" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:98 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list.html.ep:99 msgid "Users List" msgstr "" @@ -10682,10 +11026,10 @@ msgid "Users at this level and higher are allowed to change their password. Norm msgstr "" #: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:548 -msgid "Users with at least this permission level get a link in the left panel for reporting bugs to the bug tracking system at bugs.webwork.maa.org." +msgid "Users with at least this permission level get a link in the left panel for reporting issues at github.com/openwebwork/webwork2." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:865 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:868 msgid "Users with these permission levels will be sent feedback emails from students when they use the feedback button." msgstr "" @@ -10713,7 +11057,7 @@ msgstr "" msgid "Usually means students must demonstrate understanding of facts. This is more than regurgitating the fact. We use this category for simple and direct applications of algorithms the student has studied. There should be no judgement involved in choosing the method. This would include a simple application of a rule for differentiation (e.g., can combine rules for sums and constant multiples with one more advanced rule) or for integrals." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:98 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:41 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:98 msgid "Value" msgstr "" @@ -10721,6 +11065,10 @@ msgstr "" msgid "Value of work done in Reduced Scoring Period" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:32 +msgid "Value:" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/ConfigObject.pm:67 msgid "Variable Documentation" msgstr "" @@ -10735,23 +11083,55 @@ msgid "Version" msgstr "" #. ($ver->{version}) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:183 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:180 msgid "Version %1" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:169 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:106 +msgid "Version creation time" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:68 +msgid "Version creation time:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:108 +msgid "Version last attempt time" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:70 +msgid "Version last attempt time:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:105 +msgid "Version time limit" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:67 +msgid "Version time limit:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:166 msgid "Versions" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:47 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:48 msgid "Versions of a set can only be edited for one user at a time." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:331 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:342 msgid "Versions per Interval" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:45 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:145 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:216 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:258 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:267 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:278 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:551 +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:104 +msgid "Versions per interval" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:66 +msgid "Versions per interval:" +msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager.html.ep:29 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/refresh.html.ep:45 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:145 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:216 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:258 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:267 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:279 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:552 msgid "View" msgstr "" @@ -10759,10 +11139,14 @@ msgstr "" msgid "View Problems" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:708 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:710 msgid "View Test Version" msgstr "" +#: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:61 +msgid "View and manage jobs in the job queue." +msgstr "" + #: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:42 msgid "View details of student perofrmance either by individual or by set." msgstr "" @@ -10771,27 +11155,19 @@ msgstr "" msgid "View equations as" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats.html.ep:18 -msgid "View statistics by set" -msgstr "" - -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats.html.ep:19 -msgid "View statistics by student" -msgstr "" - #: /opt/webwork/webwork2/templates/HelpFiles/instructor_links.html.ep:40 msgid "View statistics of students' performance on homework either by individual or by set." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress.html.ep:14 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/index.html.ep:9 msgid "View student progress by set" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress.html.ep:15 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/index.html.ep:24 msgid "View student progress by student" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:123 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:139 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm:123 /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:125 msgid "View/Reload" msgstr "" @@ -10806,7 +11182,7 @@ msgstr "" #. ($course_info_path) #. ($c->{problem}->source_file) #. ($screenSetHeader) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1567 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:92 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:99 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1508 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSet.pm:98 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:99 msgid "Viewing temporary file: %1" msgstr "" @@ -10814,7 +11190,7 @@ msgstr "" msgid "Visibility" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Utils/FilterRecords.pm:142 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/publish_form.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:5 +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/FilterRecords.pm:142 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:97 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/publish_form.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep:5 msgid "Visible" msgstr "" @@ -10822,15 +11198,19 @@ msgstr "" msgid "Visible Sets" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:149 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:158 msgid "Visible to Students" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:61 +msgid "Visible:" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/FileManager/delete.html.ep:9 msgid "Warning" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:13 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:138 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/warning_output.html.ep:13 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:142 msgid "Warning messages" msgstr "" @@ -10855,7 +11235,7 @@ msgid "Warning: This will make users need to setup two factor authentication aga msgstr "" #. ($problem_desc, $c->tag('br') -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1208 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:1212 msgid "Warnings encountered while processing %1. Error text: %2" msgstr "" @@ -10868,11 +11248,11 @@ msgstr "" msgid "WeBWorK © %1 | theme: %2 | ww_version: %3 | pg_version %4" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:117 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:253 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:117 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:259 msgid "WeBWorK Assignments" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:3 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:4 msgid "WeBWorK Error" msgstr "" @@ -10892,7 +11272,7 @@ msgstr "" msgid "WeBWorK expects many files to be in certain locations. The following describe this. Note that by default the File Manager shows the \"templates\" directory. Other directories mentioned below are at the same level and need to be accessed by going up a directory by clicking the \"^\" button above the file list." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:6 +#: /opt/webwork/webwork2/templates/ContentGenerator/Base/error_output.html.ep:8 msgid "WeBWorK has encountered a software error while attempting to process this problem. It is likely that there is an error in the problem itself. If you are a student, report this error message to your professor to have it corrected. If you are a professor, please consult the error output below for more information." msgstr "" @@ -10900,7 +11280,7 @@ msgstr "" msgid "WeBWorK has encountered warnings while processing your request. If this occurred when viewing a problem, it was likely caused by an error or ambiguity in that problem. Otherwise, it may indicate a problem with the WeBWorK system itself. If you are a student, report these warnings to your professor to have them corrected. If you are a professor, please consult the warning output below for more information." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:366 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:368 msgid "WeBWorK was unable to generate a different version of this problem. Close this tab, and return to the original problem." msgstr "" @@ -10908,7 +11288,7 @@ msgstr "" msgid "WeBWorK was unable to generate a paper copy of this homework set. Please inform your instructor." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:471 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:482 msgid "Weight" msgstr "" @@ -10932,8 +11312,8 @@ msgstr "" msgid "What field should filtered users match on?" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:505 -msgid "When a student has more attempts than is specified here they will be able to view another version of this problem. If set to -1 the feature is disabled and if set to -2 the course default is used." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:514 +msgid "When a student has more attempts than is specified here they will be able to view another version of this problem. The \"Show Me Another\" feature is is disabled if \"Never\" is selected." msgstr "" #. (q/between pages, which will overwrite the student's saved answers./) @@ -10945,7 +11325,7 @@ msgstr "" msgid "When editing users a column for editing passwords will be shown. The text input in this column will show \"password set\" for users that have a password, and \"no password set\" for users that do not have a password. To set or change the password for a user enter the new password in the column for that user. To delete the password for a user check the checkbox to the right. This means that the user will not be able to sign into the course using a password." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:243 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:252 msgid "When location restrictions are applied (see \"Restrict Access by Location\") you may choose to relax those restrictions after the answer date. In the case of a test, the set's answer date and the date of an individual version may differ, and you can choose which answer date to use. For a set that is not a test, both options are interpreted as the regular set answer date." msgstr "" @@ -10953,10 +11333,6 @@ msgstr "" msgid "When numerical answers are checked, most test if the student's answer is close enough to the programmed answer be computing the error as a percentage of the correct answer. This value controls the default for how close the student answer has to be in order to be marked correct.

    A value such as 0.1 means 0.1 percent error is allowed.

    " msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:834 -msgid "When students click the Email Instructor button to send feedback, WeBWorK fills in the subject line. Here you can set the subject line. In it, you can have various bits of information filled in with the following escape sequences.

    • %c = course ID
    • %u = user ID
    • %s = set ID
    • %p = problem ID
    • %x = section
    • %r = recitation
    • %% = literal percent sign
    " -msgstr "" - #: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:20 msgid "When the class is very large not all students will be displayed. Using the first action on this page you can show only the students from a given recitation or from a given section, or only students whose login or last name fits a pattern match. The second action will sort the students currently being displayed. You can also sort the displayed students by clicking on the active links at the top of each column." msgstr "" @@ -10969,7 +11345,7 @@ msgstr "" msgid "When this is on students will see a line on the Grades page which has their total cumulative homework score. This score includes all sets assigned to the student." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1135 +#: /opt/webwork/webwork2/lib/WeBWorK/ConfigValues.pm:1138 msgid "When this is true, then when a user enters WeBWorK from an external tool link in the LMS, the bottom of the screen will display the data that the LMS passed to WeBWorK. This may be useful to debug LTI, especially because different LMS systems have different parameters." msgstr "" @@ -10981,10 +11357,6 @@ msgstr "" msgid "When viewing progress for a single student, their grades page is shown which lists set totals and per problem grades for each set assigned to the student. This shows the same information as the statistics page for the student." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorStats.html.ep:11 -msgid "When viewing set statistics, the drop down menus can be used to show stats for individual sections, recitations, or problems. The overall results include all students who are assigned to the set, while the individual problem results only include active (have attempted the problem) students." -msgstr "" - #: /opt/webwork/webwork2/templates/HelpFiles/InstructorStudentProgress.html.ep:9 msgid "When viewing student progress for a set, the score for the set and the status for problems in the set are listed for all students. The table can be sorted by clicking the links in the table header. Click the student's name to access the student's set. When viewing progress for a test, additional columns can be shown/hidden by updating the display at the top" msgstr "" @@ -11003,20 +11375,20 @@ msgstr "" msgid "When you unassign by unchecking a student's name, you destroy all of the data for assignment %1 for this student. You will then need to reassign the set to these students and they will receive new versions of the problems. Make sure this is what you want to do before unchecking students." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:71 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:72 msgid "When you uncheck a homework set (and save the changes), you destroy all of the data for that set for this student. If you reassign the set, the student will receive a new version of each problem. Make sure this is what you want to do before unchecking sets." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:112 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:111 msgid "Wiki summary page for MathObjects" msgstr "" #. ($c->formatDateTime($set->open_date, $ce->{studentDateDisplayFormat}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:255 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:434 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:134 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:255 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Grades.pm:434 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:130 msgid "Will open on %1." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:261 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:270 msgid "With \"Homework\", students visit each problem one at a time. They submit answers for one problem at a time and immediately receive feedback. With \"Test\", students will submit all answers for all problems at once. They may or may not receive feedback right away depending upon other settings. Also a \"Test\" can have a time limit, where the student needs to start between the open date and the close date, but once started has only so much time. Also a \"Test\" can be configured to allow taking new, re-randomized versions. A \"Proctored Test\" is the same as a \"Test\", but in order to begin, either a classwide password specific to this set is needed, or a higher level user must enter their username and password on the student's screen. A \"Just in Time Assessment and Review\" set is like a \"Homework\" set, but can be configured to introduce more exercises when a student answers a given exercise incorrectly so many times." msgstr "" @@ -11060,11 +11432,11 @@ msgstr "" msgid "Write permissions have not been enabled in the templates directory. No changes can be made." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:154 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:166 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:294 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:346 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:379 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:397 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:431 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:446 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:570 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:598 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:630 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:77 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:690 /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy/form.html.ep:136 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:57 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/delete_form.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/delete_form.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/delete_form.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/reset_2fa_form.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:154 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:176 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:198 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:72 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:163 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:175 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:305 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:357 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:390 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:408 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:442 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:457 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:573 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:604 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:72 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:706 /opt/webwork/webwork2/templates/ContentGenerator/Hardcopy/form.html.ep:136 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/default_table.html.ep:57 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/delete_form.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/delete_form.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/set_list_field.html.ep:39 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/delete_form.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/reset_2fa_form.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:154 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:176 /opt/webwork/webwork2/templates/ContentGenerator/Options.html.ep:198 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/problem_list_row.html.ep:72 msgid "Yes" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:134 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:131 msgid "You are acting as another user and do not have permission to start a new test for other users." msgstr "" @@ -11074,15 +11446,15 @@ msgid "You are acting as user %1 and do not have the permission to create a new msgstr "" #. ($effectiveUserID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:652 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:654 msgid "You are acting as user %1. If you continue, you will create a new version of this test for that user, which will count against their allowed maximum number of versions for the current time interval. In general, this is not what you want to do. Please be sure that you want to do this before clicking the \"Create New Test Version\" button below. Alternatively, click \"Cancel\"." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:378 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:380 msgid "You are currently checking answers to a different version of your problem. These answers will not be recorded, and you should remember to return to your original problem once you are done here." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:391 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:393 msgid "You are currently previewing answers to a different version of your problem - these will not be recorded, and you should remember to return to your original problem once you are done here." msgstr "" @@ -11093,38 +11465,38 @@ msgstr "" #. (% $ce->{pg}{ansEvalDefaults}{reducedScoringValue} * 100) #. ($ce->{pg}{ansEvalDefaults}{reducedScoringValue} * 100) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:232 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:18 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:213 /opt/webwork/webwork2/templates/ContentGenerator/Problem/messages.html.ep:18 msgid "You are in the Reduced Scoring Period. All work counts for %1% of the original." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:151 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:144 msgid "You are not allowed to act as a student." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:156 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:149 msgid "You are not allowed to assign homework sets." msgstr "" #. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:370 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:393 msgid "You are not allowed to delete %1." msgstr "" #. ($userSet->set_id, $c->tx->remote_address) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:250 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:253 msgid "You are not allowed to generate a hardcopy for %1 from your IP address, %2." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:153 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:146 msgid "You are not allowed to modify homework sets." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:159 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/Index.pm:152 msgid "You are not allowed to modify student data." msgstr "" #. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:481 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:504 msgid "You are not allowed to reset two factor authenticatio for %1." msgstr "" @@ -11132,15 +11504,15 @@ msgstr "" msgid "You are not allowed to send email." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:329 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:331 msgid "You are not allowed to use Show Me Another for this problem." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail.html.ep:8 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress.html.ep:2 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail.html.ep:8 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Stats.html.ep:5 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress.html.ep:2 msgid "You are not authorized to access instructor tools" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:65 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:200 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:6 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Assigner.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:31 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:34 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:30 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Scoring.html.ep:6 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:4 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:65 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:206 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AddUsers.html.ep:6 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Assigner.html.ep:4 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Index.html.ep:11 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:16 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemGrader.html.ep:31 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:35 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:31 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/Scoring.html.ep:6 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SetMaker.html.ep:15 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList.html.ep:14 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UsersAssignedToSet.html.ep:4 msgid "You are not authorized to access instructor tools." msgstr "" @@ -11156,7 +11528,7 @@ msgstr "" msgid "You are not authorized to edit achievements." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:31 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:32 msgid "You are not authorized to edit user specific information." msgstr "" @@ -11168,15 +11540,15 @@ msgstr "" msgid "You are not authorized to manage course files" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:39 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep:21 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:40 msgid "You are not authorized to modify problems." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:41 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:42 msgid "You are not authorized to modify set definition files." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:69 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:204 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:35 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvanced.pm:69 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/LTIAdvantage.pm:210 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList.html.ep:36 msgid "You are not authorized to modify sets." msgstr "" @@ -11192,7 +11564,7 @@ msgstr "" msgid "You are not authorized to modify the course configuration." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:233 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:211 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetList.pm:233 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:234 msgid "You are not authorized to perform this action." msgstr "" @@ -11212,29 +11584,29 @@ msgstr "" msgid "You are not authorized to view past answers" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:240 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:243 msgid "You are not permitted to generate a hardcopy for a set with hidden work." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:225 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:228 msgid "You are not permitted to generate a hardcopy for an unopened set." msgstr "" #. ($c->{showMeAnother}{MaxReps},) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:341 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:343 msgid "You are only allowed to click on Show Me Another %quant(%1,time,times) per problem. Close this tab, and return to the original problem." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:263 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:284 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:244 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:265 msgid "You are out of time!" msgstr "" #. (q/student's answers as you move between test pages, preview, or check answers. / . 'If you are planing to submit answers for this student, click "View Test Version" ' . 'below to continue. If you only want to view the test version, click "Cancel" ' . 'below, then disable the permission to record answers when acting as a student ' . 'before viewing open test versions.', $effectiveUserID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:705 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:707 msgid "You are trying to view an open test version for %1 and have the permission to submit answers for that user. This is dangerous, as your answers can overwrite the " msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:159 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:145 msgid "You can also click \"Edit Selected Theme\" to edit a hardcopy theme. The new theme will be saved to the templates/hardcopyThemes folder." msgstr "" @@ -11324,23 +11696,23 @@ msgstr "" msgid "You can't view files of that type" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:949 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:950 msgid "You cannot archive the course you are currently using." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:826 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:827 msgid "You cannot delete the course you are currently using." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:365 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:388 msgid "You cannot delete yourself!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2537 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2646 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2538 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2647 msgid "You cannot overwrite your OTP secret with one from another course or user!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:476 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:499 msgid "You cannot reset two factor authentication for yourself!" msgstr "" @@ -11348,7 +11720,7 @@ msgstr "" msgid "You cannot specify an absolute path" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:58 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:70 msgid "You cannot use achievement rewards when acting as another user." msgstr "" @@ -11356,11 +11728,11 @@ msgstr "" msgid "You didn't enter any message." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:292 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:296 msgid "You do not have permission to access the requested file \"%1\"." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:148 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:151 msgid "You do not have permission to change the hardcopy theme." msgstr "" @@ -11368,12 +11740,16 @@ msgstr "" msgid "You do not have permission to edit this file." msgstr "" -#. ($hardcopy_format) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:140 +#. (xml_escape($hardcopy_format) +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Hardcopy.pm:142 msgid "You do not have permission to generate hardcopy in %1 format." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1120 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:14 +msgid "You do not have permission to list assignments in this course." +msgstr "" + +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1056 msgid "You do not have permission to view the details of this error." msgstr "" @@ -11389,56 +11765,56 @@ msgstr "" msgid "You don't have any rewards!" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:344 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:325 msgid "You exceeded the allowed time." msgstr "" #. ($c->{numAttemptsLeft}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:296 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:277 msgid "You have %1 attempt(s) remaining on this test." msgstr "" #. ($c->{numAttemptsLeft}, $c->{numAttemptsLeft} - 1) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:697 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:713 msgid "You have %1 submissions remaining for this test. If you say yes, then you will have %quant(%2,submission) remaining. Once all submissions have been used, your answers will be final and you will not be able to continue to work this test version." msgstr "" #. ($problem->max_attempts - $attempts) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1229 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1170 msgid "You have %negquant(%1,unlimited attempts,attempt,attempts) remaining." msgstr "" #. ($attempts_before_rr) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1176 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1117 msgid "You have %quant(%1,attempt,attempts) left before new version will be requested." msgstr "" #. ($hours, $minutes) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:44 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:41 msgid "You have %quant(%1,hour) and %quant(%2,minute) remaining to complete the currently open test." msgstr "" #. ($hours, $minutes) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:54 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:51 msgid "You have %quant(%1,hour,hours,)%quant(%2,minute,minutes,) remaining to complete the currently open test." msgstr "" #. ($minutes, $seconds) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:64 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:61 msgid "You have %quant(%1,minute) and %quant(%2,second) remaining to complete the currently open test." msgstr "" #. ($seconds) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:72 +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/version_list.html.ep:69 msgid "You have %quant(%1,second) remaining to complete the currently open test." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:677 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:679 msgid "You have already taken all available versions of this test in the current time interval. You may take the test again after the time interval has expired." msgstr "" #. ($attempts) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1202 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1143 msgid "You have attempted this problem %quant(%1,time,times)." msgstr "" @@ -11450,15 +11826,15 @@ msgstr "" msgid "You have been sent an email with instructions on how to set up an authenticator app to generate one-time passwords. Follow the instructions in that email, and then enter the security code shown below." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:278 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:259 msgid "You have less than 1 minute to complete this test." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:258 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:239 msgid "You have less than 45 seconds left!" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:257 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:238 msgid "You have less than 90 seconds left to complete this assignment. You should finish it soon!" msgstr "" @@ -11482,15 +11858,15 @@ msgstr "" msgid "You have specified an illegal working directory!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:491 -msgid "You may cap the number of attempts a student can use for the problem. Use -1 to indicate unlimited attempts." +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:501 +msgid "You may cap the number of attempts a student can use for the problem. Select \"Unlimited\" to allow an unlimited number of attempts." msgstr "" #: /opt/webwork/webwork2/templates/HelpFiles/AdminUnarchiveCourse.html.ep:15 msgid "You may check the box to \"clean\" the unarchived course. This will remove student users and their associated data from the database after the course is unarchived. It will also remove the log files, any files in the scoring folder, and any temporary edited files." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:423 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:425 msgid "You may check your answers to this problem without affecting the maximum number of tries to your original problem." msgstr "" @@ -11498,7 +11874,7 @@ msgstr "" msgid "You may choose a course to copy components from. Select the course and which components to copy. If the course is not a true course (like the modelCourse) then only the templates and html folders, and the simple and course config files can be copied. The \"simple config\" file contains the settings made in the \"Course Config\" page. The \"course config\" file should only be copied if you know what you are doing." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:225 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:234 msgid "You may choose to restrict student access to this set to specified locations. Alternatively, you may choose to block access from specified locations. Locations are defined by the WeBWorK administrator by IP address or address range. The list of defined locations will appear after saving this option with \"Restrict To\" or \"Deny From\"." msgstr "" @@ -11507,11 +11883,11 @@ msgstr "" msgid "You may choose to show any of the following data. Correct answers, hints, and solutions are only available %1 after the answer date of the assignment." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:68 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:69 msgid "You may not change this user's password!" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:63 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep:64 msgid "You may not change your own password here!" msgstr "" @@ -11519,15 +11895,15 @@ msgstr "" msgid "You may not follow symbolic links" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2516 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2702 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2517 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2703 msgid "You may not reset your own OTP secret!" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:322 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:333 msgid "You may set a time interval in minutes. Within this time interval, students may start new randomized versions of the test. However they may only start as many new versions as you set for \"Versions per Interval\". When the time interval ends, the cap is reset. This feature is intended to allow students an immediate retake, but require them to take a break (and perhaps study more) after too many low scoring attempts in close succession. Use \"0\" to indicate an infinite time interval, which is what you want for an absolute cap on the number of new versions overall." msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:369 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:352 msgid "You may still check your answers." msgstr "" @@ -11539,35 +11915,35 @@ msgstr "" msgid "You may trigger a grade update for all users or just one user." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:194 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorPGProblemEditor.html.ep:183 msgid "You may want to create an unattached problem if you are using the current problem as a model for a new problem. You can add the new file to a homework set from the Library Browser or via the set detail page of the \"Sets Manager\"." msgstr "" -#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:162 +#: /opt/webwork/webwork2/templates/HelpFiles/InstructorUserList.html.ep:172 msgid "You might want to do this if you want to give full credit to everyone on a particular problem that was not worded correctly, or wasn't working properly. This is done from the \"Sets Manager\" page or the \"Instructor Tools\" page." msgstr "" -#. ($ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} ? link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) -#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:10 +#. ($ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} ? link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) +#: /opt/webwork/webwork2/templates/ContentGenerator/ProblemSets.html.ep:11 msgid "You must access assignments from your Course Management System (%1)." msgstr "" +#. ($ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} ? $c->link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) +#: /opt/webwork/webwork2/lib/WeBWorK/Utils/Sets.pm:298 +msgid "You must access this assignment from %1 before you can start." +msgstr "" + #. ($c->{showMeAnother}{TriesNeeded} - $c->{problem}->num_correct - $c->{problem}->num_incorrect) #: /opt/webwork/webwork2/templates/ContentGenerator/Problem/submit_buttons.html.ep:86 msgid "You must attempt this problem %quant(%1,more time) before this feature is available" msgstr "" #. ($c->{showMeAnother}{TriesNeeded}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:354 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:356 msgid "You must attempt this problem %quant(%1,time,times) before Show Me Another is available." msgstr "" -#. ($ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} ? $c->link_to( $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ProblemSets.pm:195 -msgid "You must log into this set via your Learning Management System (%1)." -msgstr "" - -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:943 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:944 msgid "You must select a course to archive" msgstr "" @@ -11596,7 +11972,7 @@ msgstr "" msgid "You must specify a course ID." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1165 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1207 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1316 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2197 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2271 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:824 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:947 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1166 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1208 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:1317 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2198 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2272 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:825 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:948 msgid "You must specify a course name." msgstr "" @@ -11632,11 +12008,6 @@ msgstr "" msgid "You must specify an file name in order to save a new file." msgstr "" -#. ($LMS) -#: /opt/webwork/webwork2/lib/WeBWorK/Authz.pm:491 -msgid "You must use your Learning Management System (%1) to access this set. Try logging in to the Learning Management System and visiting the set from there." -msgstr "" - #: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm:412 msgid "You need to select a \"Target Set\" before you can edit it." msgstr "" @@ -11661,17 +12032,17 @@ msgstr "" #. (wwRound(0, compute_reduced_score($ce, $problem, $set, $pg->{result}{score}, $c->submitTime) #. (% wwRound(0, $rh_result->{problem_result}{score} * 100) #. (wwRound(0, $rh_result->{problem_result}{score} * 100) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1210 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:53 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:29 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1151 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:54 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:29 msgid "You received a score of %1 for this attempt." msgstr "" #. (join('.', @{ $problemSeqs[$next_id] }) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1322 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1263 msgid "You will not be able to proceed to problem %1 until you have completed, or run out of attempts, for this problem and its graded subproblems." msgstr "" #. (join('.', @{ $problemSeqs[$next_id] }) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1334 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1275 msgid "You will not be able to proceed to problem %1 until you have completed, or run out of attempts, for this problem." msgstr "" @@ -11735,44 +12106,44 @@ msgid "Your message was sent successfully." msgstr "" #. (wwRound(0, $problem->status * 100) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1220 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Problem.pm:1161 msgid "Your overall recorded score is %1. %2" msgstr "" #. ('' . wwRound(2, $c->{recordedScore}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:194 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:212 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:175 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:193 msgid "Your recorded score for this version is %1/%2 (%3%)." msgstr "" #. ($setVersionID, '' . wwRound(2, $c->{recordedScore}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:336 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:317 msgid "Your recorded score on this test (version %1) is %2/%3 (%4%)." msgstr "" # $testNounNum is either "test (#)" or "submission (#)" #. ($testNounNum) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:159 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:140 msgid "Your score on this %1 WAS recorded." msgstr "" # $testNoun is either "test" or "submission" #. ($testNoun, $c->{attemptScore}, $c->{totalPossible}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:165 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:146 msgid "Your score on this %1 is %2/%3." msgstr "" # $testNounNum is either "test (#)" or "submission (#) #. ($testNounNum) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:155 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:136 msgid "Your score on this %1 was NOT recorded." msgstr "" #. ($c->{attemptScore}, $c->{totalPossible}) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:207 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:188 msgid "Your score on this (checked, not recorded) submission is %1/%2." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1039 /opt/webwork/webwork2/lib/WeBWorK/Utils/ProblemProcessing.pm:134 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1035 /opt/webwork/webwork2/lib/WeBWorK/Utils/ProblemProcessing.pm:134 msgid "Your score was not recorded because there was a failure in storing the problem record to the database." msgstr "" @@ -11784,20 +12155,20 @@ msgstr "" msgid "Your score was not recorded because this problem has not been assigned to you." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1061 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1057 msgid "Your score was not recorded because this problem set version is not open." msgstr "" #. ($elapsed, # Assume the allowed time is an even number of minutes. ($set->due_date - $set->open_date) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1075 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1071 msgid "Your score was not recorded because you have exceeded the time limit for this test. (Time taken: %1 min; allowed: %2 min.)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1064 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1060 msgid "Your score was not recorded because you have no attempts remaining on this set version." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1079 /opt/webwork/webwork2/lib/WeBWorK/Utils/ProblemProcessing.pm:225 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:58 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:31 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/GatewayQuiz.pm:1075 /opt/webwork/webwork2/lib/WeBWorK/Utils/ProblemProcessing.pm:225 /opt/webwork/webwork2/templates/RPCRenderFormats/default.html.ep:59 /opt/webwork/webwork2/templates/RPCRenderFormats/default.json.ep:31 msgid "Your score was not recorded." msgstr "" @@ -11820,7 +12191,7 @@ msgstr "" msgid "Your score will be sent to %1 at a later time." msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:522 +#: /opt/webwork/webwork2/lib/WeBWorK/Authen.pm:533 msgid "Your session has timed out due to inactivity. Please log in again." msgstr "" @@ -11854,7 +12225,7 @@ msgstr "" msgid "account settings for one user" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:204 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:205 msgid "achievements" msgstr "" @@ -11879,7 +12250,7 @@ msgstr "" msgid "all course users" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/import_form.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:64 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/AchievementList/import_form.html.ep:19 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:68 msgid "all current users" msgstr "" @@ -11887,11 +12258,11 @@ msgstr "" msgid "all jobs" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2135 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2114 msgid "all sets" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2121 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2100 msgid "all students" msgstr "" @@ -11900,12 +12271,12 @@ msgid "alphabetically" msgstr "" #. ($count, $numSets) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2139 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2118 msgid "an impossible number of sets: %1 out of %2" msgstr "" #. ($count, $numUsers) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2125 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2104 msgid "an impossible number of users: %1 out of %2" msgstr "" @@ -11933,16 +12304,20 @@ msgstr "" msgid "assignments and dates for one user" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:198 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:199 msgid "assignments/sets" msgstr "" +#: /opt/webwork/webwork2/templates/layouts/system.html.ep:75 +msgid "auto" +msgstr "" + #: /opt/webwork/webwork2/lib/WeBWorK/Utils/FilterRecords.pm:69 msgid "blank" msgstr "" # Context is "Append ____ blank problem template(s) to end of homework set" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:705 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:706 msgid "blank problem template(s) to end of homework set" msgstr "" @@ -11950,30 +12325,38 @@ msgstr "" msgid "by last login date" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:48 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserDetail.html.ep:49 msgid "class list data" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:47 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:29 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_lti_course_map_form.html.ep:47 /opt/webwork/webwork2/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep:48 msgid "close" msgstr "" +#: /opt/webwork/webwork2/templates/layouts/system.html.ep:62 +msgid "close sidebar" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/SampleProblemViewer/sample_problem.html.ep:91 msgid "copy to clipboard" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:222 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:223 msgid "course configuration file" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:216 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:217 msgid "course institution (will override \"Institution\" input above)" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:210 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:211 msgid "course title (will override \"Course Title\" input above)" msgstr "" +#: /opt/webwork/webwork2/templates/layouts/system.html.ep:74 +msgid "dark" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager/sort_button.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager/sort_button.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager/sort_button.html.ep:34 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_button.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/sort_button.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/sort_button.html.ep:10 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/sort_button.html.ep:22 /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/sort_button.html.ep:34 msgid "descending" msgstr "" @@ -11982,11 +12365,11 @@ msgstr "" msgid "disabled achievements" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:131 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:132 msgid "email address" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:54 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ShowAnswers/past-answers-table.html.ep:57 msgid "empty" msgstr "" @@ -12014,7 +12397,7 @@ msgstr "" msgid "finished" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:130 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:131 msgid "first name" msgstr "" @@ -12023,7 +12406,7 @@ msgid "for" msgstr "" #. ($j, $setID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1248 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1238 msgid "global %1 for set %2 not found." msgstr "" @@ -12035,7 +12418,7 @@ msgstr "" msgid "guest" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2171 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:794 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:913 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2172 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:795 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:914 msgid "hidden" msgstr "" @@ -12043,11 +12426,11 @@ msgstr "" msgid "html directory" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:361 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:362 msgid "if status less than 1" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:719 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:749 msgid "illegal character in input: '/'" msgstr "" @@ -12059,12 +12442,12 @@ msgstr "" msgid "index" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:164 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep:165 msgid "individual user settings" msgstr "" #. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:516 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:539 msgid "insufficient permission to edit %1" msgstr "" @@ -12072,15 +12455,19 @@ msgstr "" msgid "jobs that match on selected field" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:129 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:130 msgid "last name" msgstr "" +#: /opt/webwork/webwork2/templates/layouts/system.html.ep:74 +msgid "light" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/manage_location_form.html.ep:87 msgid "locations selected below" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:88 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:89 msgid "login" msgstr "" @@ -12088,7 +12475,7 @@ msgstr "" msgid "login ID" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:135 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:136 msgid "login name" msgstr "" @@ -12096,10 +12483,6 @@ msgstr "" msgid "login_proctor" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:614 -msgid "max" -msgstr "" - #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:8 msgid "multiple sets" msgstr "" @@ -12112,6 +12495,10 @@ msgstr "" msgid "new user accounts" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:5 +msgid "no" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/JobManager/delete_form.html.ep:7 msgid "no jobs" msgstr "" @@ -12120,11 +12507,11 @@ msgstr "" msgid "no location" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2133 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2112 msgid "no sets" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2119 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:2098 msgid "no students" msgstr "" @@ -12136,10 +12523,14 @@ msgstr "" msgid "nobody" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:192 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:193 msgid "non-student users" msgstr "" +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:77 /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.txt.ep:48 +msgid "none" +msgstr "" + #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/SendMail/main_form.html.ep:109 msgid "nth column of merge file" msgstr "" @@ -12149,11 +12540,11 @@ msgid "of" msgstr "" # Context is Assign this set to which users? "only ____" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:65 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep:69 msgid "only" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:46 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:47 msgid "only best scores" msgstr "" @@ -12170,15 +12561,15 @@ msgid "overwrite" msgstr "" #. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:513 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:536 msgid "permissions for %1 not defined" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:265 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:557 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:267 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:563 msgid "point" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:265 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:557 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/ShowMeAnother.pm:267 /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:563 msgid "points" msgstr "" @@ -12186,11 +12577,11 @@ msgstr "" msgid "preserve" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:622 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:638 msgid "preview answers" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:70 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:71 msgid "problems" msgstr "" @@ -12210,37 +12601,37 @@ msgstr "" msgid "progress for one user" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:134 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:135 msgid "recitation" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:82 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:83 msgid "recitation #" msgstr "" #. ($userID) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:511 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserList.pm:534 msgid "record for visible user %1 not found" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1374 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserDetail.pm:178 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetDetail.pm:1357 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/UserDetail.pm:178 msgid "required" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:132 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:133 msgid "score" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:133 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:134 msgid "section" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:76 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:77 msgid "section #" msgstr "" #. ('templates', 'html') -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:174 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:175 msgid "select all" msgstr "" @@ -12284,7 +12675,7 @@ msgstr "" msgid "shown" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:186 +#: /opt/webwork/webwork2/templates/ContentGenerator/CourseAdmin/add_course_form.html.ep:187 msgid "simple configuration file" msgstr "" @@ -12292,7 +12683,7 @@ msgstr "" msgid "statistics for one set" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:158 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:157 msgid "still open" msgstr "" @@ -12300,12 +12691,12 @@ msgstr "" msgid "student" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:147 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:128 msgid "submission" msgstr "" #. ($setVersionID) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:150 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:131 msgid "submission (version %1)" msgstr "" @@ -12325,15 +12716,15 @@ msgstr "" msgid "templates/macros directory" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:147 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:128 msgid "test" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:52 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:53 msgid "test date" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:58 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:59 msgid "test time" msgstr "" @@ -12341,11 +12732,11 @@ msgstr "" msgid "then delete them" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:161 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/Instructor/StudentProgress.pm:160 msgid "time limit exceeded" msgstr "" -#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:64 +#: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep:65 msgid "time remaining" msgstr "" @@ -12355,11 +12746,11 @@ msgid "to" msgstr "" #. ($ce->{institutionName}) -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:419 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:420 msgid "to %1 main web site" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:403 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator.pm:404 msgid "to courses page" msgstr "" @@ -12392,14 +12783,18 @@ msgid "version %1" msgstr "" #. ($setVersionID) -#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:151 +#: /opt/webwork/webwork2/templates/ContentGenerator/GatewayQuiz.html.ep:132 msgid "version (%1)" msgstr "" -#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2173 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:796 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:915 +#: /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:2174 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:797 /opt/webwork/webwork2/lib/WeBWorK/ContentGenerator/CourseAdmin.pm:916 msgid "visible" msgstr "" #: /opt/webwork/webwork2/templates/ContentGenerator/Instructor/UserList/import_form.html.ep:16 msgid "visible users" msgstr "" + +#: /opt/webwork/webwork2/templates/ContentGenerator/Feedback/feedback_email.html.ep:4 +msgid "yes" +msgstr "" diff --git a/lib/WeBWorK/Utils.pm b/lib/WeBWorK/Utils.pm index 86a2e91a90..2048c66b56 100644 --- a/lib/WeBWorK/Utils.pm +++ b/lib/WeBWorK/Utils.pm @@ -30,7 +30,10 @@ our @EXPORT_OK = qw( processEmailMessage createEmailSenderTransportSMTP generateURLs + formatEmailSubject getAssetURL + points_stepsize + round_nearest_stepsize x ); @@ -356,7 +359,6 @@ sub generateURLs ($c, %params) { for my $name ('displayMode', 'showCorrectAnswers', 'showHints', 'showOldAnswers', 'showSolutions') { $args{$name} = [ $c->param($name) ] if defined $c->param($name) && $c->param($name) ne ''; } - $args{showProblemGrader} = 1; } else { $routePath = $c->url_for('problem_list', setID => $params{set_id}); } @@ -382,6 +384,33 @@ sub generateURLs ($c, %params) { } } +sub formatEmailSubject ($formatString, $courseID, $userID, $setID, $problemID, $section, $recitation) { + my %subject_map = ( + c => $courseID, + u => $userID, + s => $setID, + p => $problemID, + x => $section, + r => $recitation, + '%' => '%', + ); + my $chars = join('', keys %subject_map); + my $subject = $formatString; + # extract the brace pairs + my @braces = $formatString =~ /(\{(?:[^{}]*|(?0))*\})/xg; + if (@braces) { + # for each brace pair, do substitutions, but leave %c etc when variable is empty + my %braces = map { $_ => $_ =~ s/%([$chars])/$subject_map{$1} ne '' ? $subject_map{$1} : "%$1"/egr } @braces; + # If there is an instance of %c, etc, nullify the whole thing. Remove outer braces. + %braces = map { $_ => $braces{$_} =~ /%[$chars]/ ? '' : substr($braces{$_}, 1, -1) } keys %braces; + my $regex = join('|', map {"\Q$_\E"} keys %braces); + $regex = qr/$regex/; + $subject =~ s/($regex)/$braces{$1}/g; + } + $subject =~ s/%([$chars])/$subject_map{$1} ne '' ? $subject_map{$1} : ''/eg; + return $subject; +} + my $staticWWAssets; my $staticPGAssets; my $thirdPartyWWDependencies; @@ -506,6 +535,28 @@ sub getAssetURL ($ce, $file, $isThemeFile = 0) { return "$ce->{webworkURLs}{htdocs}/$file"; } +sub points_stepsize ($points) { + my $stepsize; + if ($points == 1) { + $stepsize = 0.01; + } elsif ($points <= 5) { + $stepsize = 0.05; + } elsif ($points <= 10) { + $stepsize = 0.1; + } elsif ($points <= 25) { + $stepsize = 0.25; + } elsif ($points <= 50) { + $stepsize = 0.5; + } else { + $stepsize = int(($points - 1) / 100) + 1; + } + return $stepsize; +} + +sub round_nearest_stepsize ($score, $stepsize) { + return wwRound(2, wwRound(0, $score / $stepsize) * $stepsize); +} + sub x (@args) { return @args } 1; @@ -736,6 +787,22 @@ Returns the URL for the asset specified in C<$file>. If C<$isThemeFile> is true, then the asset will be assumed to be located in a theme directory. The parameter C<$ce> must be a valid C object. +=head2 points_stepsize + +Usage: C + +Returns a reasonable stepsize that best converts between a whole percent and +a point value. The stepsize is the point value that is close to but greater +than or equal to 1% per step. This is done by first using preset values of +0.01, 0.05, 0.1, 0.25, or 0.5, then using only whole point values, such that +the stepsize is greater than or equal to 1% of total points. + +=head2 round_nearest_stepsize + +Usage: C + +Returns the value of the score rounded to the nearest stepsize. + =head2 x Usage: C diff --git a/lib/WeBWorK/Utils/CourseManagement.pm b/lib/WeBWorK/Utils/CourseManagement.pm index cafe7f5d9a..6ba1bdc203 100644 --- a/lib/WeBWorK/Utils/CourseManagement.pm +++ b/lib/WeBWorK/Utils/CourseManagement.pm @@ -498,9 +498,9 @@ sub addCourse { %options may also contain: skipDBRename => $skipDBRename, - courseTitle => $courseTitle - courseInstitution => $courseInstitution - + courseTitle => $courseTitle, + courseInstitution => $courseInstitution, + updateLTICourseMap => $updateLTICourseMap Rename the course named $courseID to $newCourseID. @@ -509,16 +509,16 @@ environment. The name of the course's directory is changed to $newCourseID. -If the course's database layout is C or C, new tables -are created in the current database, course data is copied from the old tables -to the new tables, and the old tables are deleted. - -If the course's database layout is something else, no database changes are made. +New tables are created in the current database, course data is copied from the +old tables to the new tables, and the old tables are deleted. If $skipDBRename is true, no database changes are made. This is useful if a course is being unarchived and no database was found, or for renaming the modelCourse. +If $updateLTICourseMap is true, then the LTI course map is updated to associate +the LMS context id to the new course name. + Any errors encountered while renaming the course are returned. =cut @@ -635,6 +635,16 @@ sub renameCourse { } }; warn "Problems from resetting course title and institution = $@" if $@; + + # Remap the LTI course mapping for the renamed course to the new course if that is requested. + if ($options{updateLTICourseMap}) { + my @ltiCourseMaps = $newDB->getLTICourseMapsWhere({ course_id => $oldCE->{courseName} }); + $newDB->deleteLTICourseMapWhere({ course_id => $oldCE->{courseName} }); + for (@ltiCourseMaps) { + $newDB->setLTICourseMap($newCE->{courseName}, $_->lms_context_id); + last; + } + } } } diff --git a/lib/WeBWorK/Utils/FilterRecords.pm b/lib/WeBWorK/Utils/FilterRecords.pm index 5c65bfc314..ea796a04db 100644 --- a/lib/WeBWorK/Utils/FilterRecords.pm +++ b/lib/WeBWorK/Utils/FilterRecords.pm @@ -182,7 +182,7 @@ sub filterRecords { my @filteredRecords = $intersect ? @records : (); if ($intersect) { for my $filter (@filtersToUse) { - my ($name, $value) = split(/:/, $filter); + my ($name, $value) = split(/:/, $filter, 2); # permission level is handled differently if ($name eq 'permission') { @filteredRecords = @@ -194,7 +194,7 @@ sub filterRecords { } else { for my $record (@records) { for my $filter (@filtersToUse) { - my ($name, $value) = split(/:/, $filter); + my ($name, $value) = split(/:/, $filter, 2); # permission level is handled differently if ($name eq 'permission' && $permissionName{ $permissionLevels{ $record->user_id } } eq $value) { push @filteredRecords, $record; diff --git a/lib/WeBWorK/Utils/Instructor.pm b/lib/WeBWorK/Utils/Instructor.pm index 62aa3eb942..8e4716673e 100644 --- a/lib/WeBWorK/Utils/Instructor.pm +++ b/lib/WeBWorK/Utils/Instructor.pm @@ -554,10 +554,7 @@ sub getDefList { find( { wanted => sub { - if ($File::Find::dir =~ /^$topdir\/Library/ - || $File::Find::dir =~ /^$topdir\/Contrib/ - || $File::Find::dir =~ /^$topdir\/capaLibrary/) - { + if ($File::Find::dir =~ /^$topdir\/Library/ || $File::Find::dir =~ /^$topdir\/Contrib/) { $File::Find::prune = 1; return; } diff --git a/lib/WeBWorK/Utils/ListingDB.pm b/lib/WeBWorK/Utils/ListingDB.pm index 589da814c8..528ac038a6 100644 --- a/lib/WeBWorK/Utils/ListingDB.pm +++ b/lib/WeBWorK/Utils/ListingDB.pm @@ -286,7 +286,7 @@ sub getDBListings ($c, $amcounter = 0) { if ($amcounter) { $selectwhat = "COUNT(DISTINCT $selectwhat)"; } else { - $selectwhat .= 'as filepath, pgf.morelt_id, pgf.pgfile_id, pgf.static, pgf.MO'; + $selectwhat .= 'as filepath, MAX(pgf.morelt_id), MAX(pgf.pgfile_id), MAX(pgf.static), MAX(pgf.MO)'; $group_by = 'GROUP BY filepath'; } @@ -308,7 +308,7 @@ sub getDBListings ($c, $amcounter = 0) { ts.chapter_id = tc.chapter_id AND prob.section_id = ts.section_id AND p.path_id = pgf.path_id - $extrawhere $textextrawhere $kw_where $group_by"; + $extrawhere $textextrawhere $kw_where $group_by ORDER BY FIELD('pgf.libraryroot', 'Library')"; $pg_file_ref = $dbh->selectall_arrayref($query, {}, @select_parameters, @textInfo_parameters, @keyword_parameters); @@ -319,7 +319,7 @@ sub getDBListings ($c, $amcounter = 0) { dbc.DBchapter_id = dbsc.DBchapter_id AND dbsc.DBsection_id = pgf.DBsection_id AND p.path_id = pgf.path_id - $extrawhere $kw_where $group_by"; + $extrawhere $kw_where $group_by ORDER BY FIELD('pgf.libraryroot', 'Library')"; $pg_file_ref = $dbh->selectall_arrayref($query, {}, @select_parameters, @keyword_parameters); } diff --git a/lib/WeBWorK/Utils/PODParser.pm b/lib/WeBWorK/Utils/PODParser.pm deleted file mode 100644 index e11b5899a3..0000000000 --- a/lib/WeBWorK/Utils/PODParser.pm +++ /dev/null @@ -1,66 +0,0 @@ -package WeBWorK::Utils::PODParser; -use parent qw(Pod::Simple::XHTML); - -use strict; -use warnings; - -use Pod::Simple::XHTML; -use File::Basename qw(basename); - -# $podFiles must be provided in order for pod links to local files to work. It should be the -# first return value of the POD::Simple::Search survey method. -sub new { - my ($invocant, $podFiles) = @_; - my $class = ref $invocant || $invocant; - my $self = $class->SUPER::new(@_); - $self->perldoc_url_prefix("https://metacpan.org/pod/"); - $self->index(1); - $self->backlink(1); - $self->html_charset('UTF-8'); - $self->{podFiles} = $podFiles // {}; - return bless $self, $class; -} - -# Attempt to resolve links to local files. If a local file is not found, then -# let Pod::Simple::XHTML resolve to a cpan link. -sub resolve_pod_page_link { - my ($self, $target, $section) = @_; - - unless (defined $target) { - print "Using internal page link.\n" if $self->{verbose} > 2; - return $self->SUPER::resolve_pod_page_link($target, $section); - } - - my $podFound; - for (keys %{ $self->{podFiles} }) { - if ($target eq $_ =~ s/lib:://r || $target eq basename($self->{podFiles}{$_}) =~ s/\.pod$//r) { - $podFound = - $self->{assert_html_ext} ? ($self->{podFiles}{$_} =~ s/\.(pm|pl|pod)$/.html/r) : $self->{podFiles}{$_}; - last; - } - } - - if ($podFound) { - my $pod_url = $self->encode_entities($podFound =~ s/^$self->{source_root}/$self->{base_url}/r) - . ($section ? '#' . $self->idify($self->encode_entities($section), 1) : ''); - print "Resolved local pod link for $target" . ($section ? "/$section" : '') . " to $pod_url\n" - if $self->{verbose} > 2; - return $pod_url; - } - - print "Using cpan pod link for $target" . ($section ? "/$section" : '') . "\n" if $self->{verbose} > 2; - return $self->SUPER::resolve_pod_page_link($target, $section); -} - -# Trim spaces from the beginning of each line in code blocks. This attempts to -# trim spaces from all lines in the code block in the same amount as there are -# spaces at the beginning of the first line. Note that Pod::Simple::XHTML has -# already converted tab characters into 8 spaces. -sub handle_code { - my ($self, $code) = @_; - my $start_spaces = length(($code =~ /^( *)/)[0]) || ''; - $self->SUPER::handle_code($code =~ s/^( {1,$start_spaces})//gmr); - return; -} - -1; diff --git a/lib/WeBWorK/Utils/ProblemProcessing.pm b/lib/WeBWorK/Utils/ProblemProcessing.pm index 02d8ba18a8..cfe9ba8903 100644 --- a/lib/WeBWorK/Utils/ProblemProcessing.pm +++ b/lib/WeBWorK/Utils/ProblemProcessing.pm @@ -13,7 +13,7 @@ use Try::Tiny; use Mojo::JSON qw(encode_json decode_json); use WeBWorK::Debug; -use WeBWorK::Utils qw(encodeAnswers createEmailSenderTransportSMTP); +use WeBWorK::Utils qw(encodeAnswers createEmailSenderTransportSMTP formatEmailSubject); use WeBWorK::Utils::DateTime qw(before after); use WeBWorK::Utils::JITAR qw(jitar_id_to_seq jitar_problem_adjusted_status); use WeBWorK::Utils::Logs qw(writeLog writeCourseLog); @@ -298,7 +298,7 @@ sub create_ans_str_from_responses ($formFields, $pg, $needed_grading = 0) { my @past_answers_order; my @last_answer_order; - my %pg_answers_hash = %{ $pg->{PG_ANSWERS_HASH} }; + my %pg_answers_hash = %{ $pg->{PG_ANSWERS_HASH} // {} }; for my $ans_id (@{ $pg->{flags}{ANSWER_ENTRY_ORDER} // [] }) { $scores_string .= ($pg_answers_hash{$ans_id}{rh_ans}{score} // 0) >= 1 ? '1' : '0'; push @answerTypes, $pg_answers_hash{$ans_id}{rh_ans}{type} // ''; @@ -326,7 +326,7 @@ sub create_ans_str_from_responses ($formFields, $pg, $needed_grading = 0) { # KEPT_EXTRA_ANSWERS needs to be stored in last_answer in order to preserve persistence items. # The persistence items do not need to be stored in past_answers_string. # Don't add _ext_data items. Those are stored elsewhere. - for my $entry_id (@{ $pg->{flags}{KEPT_EXTRA_ANSWERS} }) { + for my $entry_id (@{ $pg->{flags}{KEPT_EXTRA_ANSWERS} // [] }) { next if exists($answers_to_store{$entry_id}) || $entry_id =~ /^_ext_data/; $answers_to_store{$entry_id} = $formFields->{$entry_id}; push @last_answer_order, $entry_id; @@ -383,19 +383,12 @@ sub jitar_send_warning_email ($c, $userProblem) { $problemID = join('.', jitar_id_to_seq($problemID)); - my %subject_map = ( - 'c' => $courseID, - 'u' => $userID, - 's' => $setID, - 'p' => $problemID, - 'x' => $user->section, - 'r' => $user->recitation, - '%' => '%', + my $subject = formatEmailSubject( + $ce->{mail}{feedbackSubjectFormat}, + $courseID, $userID, $setID, $problemID, + $user ? $user->section : '', + $user ? $user->recitation : '' ); - my $chars = join('', keys %subject_map); - my $subject = $ce->{mail}{feedbackSubjectFormat} - || 'WeBWorK question from %c: %u set %s/prob %p'; # default if not entered - $subject =~ s/%([$chars])/defined $subject_map{$1} ? $subject_map{$1} : ""/eg; my $full_name = $user->full_name; my $email_address = $user->email_address; diff --git a/lib/WeBWorK/Utils/Rendering.pm b/lib/WeBWorK/Utils/Rendering.pm index c87be8a842..91d30406e2 100644 --- a/lib/WeBWorK/Utils/Rendering.pm +++ b/lib/WeBWorK/Utils/Rendering.pm @@ -172,7 +172,6 @@ sub constructPGOptions ($ce, $user, $set, $problem, $psvn, $formFields, $transla $options{templateDirectory} = "$ce->{courseDirs}{templates}/"; $options{tempDirectory} = "$ce->{courseDirs}{html_temp}/"; $options{tempURL} = "$ce->{courseURLs}{html_temp}/"; - $options{webworkDocsURL} = "$ce->{webworkURLs}{docs}/"; $options{localHelpURL} = "$ce->{pg}{URLs}{localHelpURL}/"; $options{MathJaxURL} = $ce->{webworkURLs}{MathJax}; $options{server_root_url} = $ce->{server_root_url} || ''; @@ -192,7 +191,6 @@ sub constructPGOptions ($ce, $user, $set, $problem, $psvn, $formFields, $transla tmpl => $ce->{courseDirs}{templates}, # ditto }; - # Variables for interpreting capa problems and other things to be seen in a pg file. $options{specialPGEnvironmentVars} = $ce->{pg}{specialPGEnvironmentVars}; return %options; @@ -254,10 +252,9 @@ sub renderPG ($c, $effectiveUser, $set, $problem, $psvn, $formFields, $translati }; if (ref($pg->{pgcore}) eq 'PGcore') { - $ret->{internal_debug_messages} = $pg->{pgcore}->get_internal_debug_messages; - $ret->{warning_messages} = $pg->{pgcore}->get_warning_messages(); - $ret->{debug_messages} = $pg->{pgcore}->get_debug_messages(); - $ret->{PG_ANSWERS_HASH} = { + $ret->{warning_messages} = $pg->{pgcore}->get_warning_messages(); + $ret->{debug_messages} = $pg->{pgcore}->get_debug_messages(); + $ret->{PG_ANSWERS_HASH} = { map { $_ => { response_obj => unbless($pg->{pgcore}{PG_ANSWERS_HASH}{$_}->response_obj), @@ -271,6 +268,8 @@ sub renderPG ($c, $effectiveUser, $set, $problem, $psvn, $formFields, $translati keys %{ $pg->{pgcore}{PG_alias}{resource_list} } }; $ret->{PERSISTENCE_HASH} = $pg->{pgcore}{PERSISTENCE_HASH}; + } else { + $ret->{render_fail} = 1; } # Save the problem source. This is used by Caliper::Entity. Why? @@ -279,7 +278,7 @@ sub renderPG ($c, $effectiveUser, $set, $problem, $psvn, $formFields, $translati $pg->free; return $ret; })->catch(sub ($err) { - return { body_text => '', answers => {}, flags => { error_flag => 1 }, errors => $err }; + return { body_text => '', answers => {}, render_fail => 1, flags => { error_flag => 1 }, errors => $err }; }); } diff --git a/lib/WeBWorK/Utils/Routes.pm b/lib/WeBWorK/Utils/Routes.pm index bb5101069c..e24f33ce12 100644 --- a/lib/WeBWorK/Utils/Routes.pm +++ b/lib/WeBWorK/Utils/Routes.pm @@ -23,6 +23,7 @@ PLEASE FOR THE LOVE OF GOD UPDATE THIS IF YOU CHANGE THE ROUTES BELOW!!! ltiadvantage_launch /ltiadvantage/launch ltiadvantage_keys /ltiadvantage/keys ltiadvantage_content_selection /ltiadvantage/content_selection + ltiadvantage_registration /ltiadvantage/registration saml2_acs /saml2/acs saml2_metadata /saml2/metadata @@ -86,7 +87,6 @@ PLEASE FOR THE LOVE OF GOD UPDATE THIS IF YOU CHANGE THE ROUTES BELOW!!! instructor_statistics /$courseID/instructor/stats instructor_set_statistics /$courseID/instructor/stats/set/$setID instructor_problem_statistics /$courseID/instructor/stats/set/$setID/$problemID - instructor_user_statistics /$courseID/instructor/stats/student/$userID instructor_progress /$courseID/instructor/progress instructor_set_progress /$courseID/instructor/progress/set/$setID @@ -147,6 +147,7 @@ my %routeParameters = ( ltiadvantage_launch ltiadvantage_keys ltiadvantage_content_selection + ltiadvantage_registration saml2_acs saml2_metadata saml2_error @@ -217,6 +218,12 @@ my %routeParameters = ( path => '/ltiadvantage/content_selection', action => 'content_selection' }, + ltiadvantage_registration => { + title => x('LTI 1.3 Registration'), + module => 'LTIAdvantage', + path => '/ltiadvantage/registration', + action => 'registration' + }, # This route also ends up at the login screen on failure, and the title is not used anywhere else. saml2_acs => { @@ -483,7 +490,7 @@ my %routeParameters = ( }, instructor_statistics => { title => x('Statistics'), - children => [qw(instructor_set_statistics instructor_user_statistics)], + children => [qw(instructor_set_statistics)], module => 'Instructor::Stats', path => '/stats' }, @@ -498,11 +505,6 @@ my %routeParameters = ( module => 'Instructor::Stats', path => '/' }, - instructor_user_statistics => { - title => '[_1]', - module => 'Instructor::Stats', - path => '/student/#userID' - }, instructor_progress => { title => x('Student Progress'), children => [qw(instructor_set_progress instructor_user_progress)], diff --git a/lib/WeBWorK/Utils/Sets.pm b/lib/WeBWorK/Utils/Sets.pm index e522adc711..aa54003337 100644 --- a/lib/WeBWorK/Utils/Sets.pm +++ b/lib/WeBWorK/Utils/Sets.pm @@ -17,6 +17,7 @@ our @EXPORT_OK = qw( is_restricted get_test_problem_position list_set_versions + restricted_set_message ); sub format_set_name_internal ($set_name) { @@ -107,7 +108,7 @@ sub grade_set ($db, $set, $studentName, $setIsVersioned = 0, $wantProblemDetails } sub grade_gateway ($db, $setName, $studentName) { - my $bestSetData = [ 0, 0 ]; + my $bestSetData = [ 0, 0, [] ]; my @setVersions = $db->getSetVersionsWhere({ user_id => $studentName, set_id => { like => "$setName,v\%" } }); for (@setVersions) { @@ -255,6 +256,53 @@ sub list_set_versions ($db, $studentName, $setName, $setIsVersioned = 0) { return (\@allSetNames, $notAssignedSet); } +sub restricted_set_message($c, $set, $status) { + my $ce = $c->ce; + my $db = $c->db; + my $authz = $c->authz; + + if ($status eq 'conditional') { + my $user = $c->param('effectiveUser') || $c->param('user'); + my @restricted = $ce->{options}{enableConditionalRelease} ? is_restricted($db, $set, $user) : (); + return '' unless @restricted; + + if (@restricted == 1) { + return $c->maketext( + 'To access this set you must score at least [_1]% on set [_2].', + sprintf('%.0f', $set->restricted_status * 100), + $c->tag('span', dir => 'ltr', format_set_name_display($restricted[0])) + ); + } else { + return $c->maketext( + 'To access this set you must score at least [_1]% on the following sets: [_2].', + sprintf('%.0f', $set->restricted_status * 100), + join(', ', map { $c->tag('span', dir => 'ltr', format_set_name_display($_)) } @restricted) + ); + } + } + + if ($status eq 'lti') { + # Only show this message if unable to view unopened sets or acting as another user. + return '' + if $authz->hasPermissions($c->param('user'), 'view_unopened_sets') + && (!$c->param('effectiveUser') || $c->param('effectiveUser') eq $c->param('user')); + + if ($ce->{LTIVersion} + && ($ce->{LTIVersion} ne 'v1p3' || !$ce->{LTI}{v1p3}{ignoreMissingSourcedID}) + && $ce->{LTIGradeMode} eq 'homework' + && !$set->lis_source_did) + { + return $c->maketext( + 'You must access this assignment from [_1] before you can start.', + $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} + ? $c->link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) + : $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} + ); + } + return ''; + } +} + 1; =head1 NAME @@ -354,4 +402,12 @@ assigned to the set. The list of names will be a list of set versions if the set is versioned (i.e., if C is true), and a list containing only the original set id otherwise. +=head2 restricted_set_message + +Usage: C + +Checks for and returns any restricted messages for the given set and status. +C<$status> can be either 'conditional' for conditional release, or 'lti' to +check for lis_source_did when using homework grade passback. + =cut diff --git a/lib/WebworkWebservice.pm b/lib/WebworkWebservice.pm index d8f9a28a5e..ef4f03f29d 100644 --- a/lib/WebworkWebservice.pm +++ b/lib/WebworkWebservice.pm @@ -4,7 +4,7 @@ package WebworkWebservice; WebworkWebservice -=head1 SYNPOSIS +=head1 SYNOPSIS my $rpc_service = WebworkWebservice->new($c); await $rpc_service->rpc_execute('command_to_execute'); @@ -248,16 +248,17 @@ sub command_permission { # WebworkWebservice::ProblemActions getUserProblem => 'access_instructor_tools', - # Note: The modify_student_data permission is checked in the following three methods and only the status and - # comment_string can actually be modified by users with the problem_grader permission only. + # Note: The modify_student_data permission is checked in the following three methods and only the status, + # sub_status, and comment_string can actually be modified by users with the problem_grader permission only. putUserProblem => 'problem_grader', putProblemVersion => 'problem_grader', putPastAnswer => 'problem_grader', tidyPGCode => 'access_instructor_tools', convertCodeToPGML => 'access_instructor_tools', + runPGCritic => 'access_instructor_tools', # WebworkWebservice::RenderProblem - renderProblem => 'proctor_quiz_login', + renderProblem => 'webservice_render_problem', # WebworkWebservice::SetActions listGlobalSets => 'access_instructor_tools', diff --git a/lib/WebworkWebservice/ProblemActions.pm b/lib/WebworkWebservice/ProblemActions.pm index 3252bcdaa8..a93babdf56 100644 --- a/lib/WebworkWebservice/ProblemActions.pm +++ b/lib/WebworkWebservice/ProblemActions.pm @@ -8,6 +8,7 @@ use Data::Structure::Util qw(unbless); use WeBWorK::PG::Tidy qw(pgtidy); use WeBWorK::PG::ConvertToPGML qw(convertToPGML); +use WeBWorK::PG::Critic qw(critiquePGCode); sub getUserProblem { my ($invocant, $self, $params) = @_; @@ -37,16 +38,17 @@ sub putUserProblem { 'source_file', 'value', 'max_attempts', 'showMeAnother', 'showMeAnotherCount', 'prPeriod', 'prCount', 'problem_seed', 'attempted', 'last_answer', 'num_correct', 'num_incorrect', - 'att_to_open_children', 'counts_parent_grade', 'sub_status', 'flags' + 'att_to_open_children', 'counts_parent_grade', 'flags' ) { $userProblem->{$_} = $params->{$_} if defined $params->{$_}; } } - # The status is the only thing that users with the problem_grader permission can change. + # The status and sub_status are the only things that users with the problem_grader permission can change. # This method cannot be called without the problem_grader permission. - $userProblem->{status} = $params->{status} if defined $params->{status}; + $userProblem->{status} = $params->{status} if defined $params->{status}; + $userProblem->{sub_status} = $params->{sub_status} if defined $params->{sub_status}; # Remove the needs_grading flag if the mark_graded parameter is set. $userProblem->{flags} =~ s/:needs_grading$// if $params->{mark_graded}; @@ -76,16 +78,17 @@ sub putProblemVersion { 'source_file', 'value', 'max_attempts', 'showMeAnother', 'showMeAnotherCount', 'prPeriod', 'prCount', 'problem_seed', 'attempted', 'last_answer', 'num_correct', 'num_incorrect', - 'att_to_open_children', 'counts_parent_grade', 'sub_status', 'flags' + 'att_to_open_children', 'counts_parent_grade', 'flags' ) { $problemVersion->{$_} = $params->{$_} if defined($params->{$_}); } } - # The status is the only thing that users with the problem_grader permission can change. + # The status and sub_status are the only things that users with the problem_grader permission can change. # This method cannot be called without the problem_grader permission. - $problemVersion->{status} = $params->{status} if defined $params->{status}; + $problemVersion->{status} = $params->{status} if defined $params->{status}; + $problemVersion->{sub_status} = $params->{sub_status} if defined $params->{sub_status}; # Remove the needs_grading flag if the mark_graded parameter is set. $problemVersion->{flags} =~ s/:needs_grading$// if $params->{mark_graded}; @@ -165,4 +168,18 @@ sub convertCodeToPGML { } +sub runPGCritic { + my ($invocant, $self, $params) = @_; + + return { + ra_out => { + html => $self->c->render_to_string( + template => 'ContentGenerator/Instructor/PGProblemEditor/pg_critic', + violations => [ critiquePGCode($params->{pgCode}) ] + ) + }, + text => 'The script pg-critic has been run successfully.' + }; +} + 1; diff --git a/lib/WebworkWebservice/RenderProblem.pm b/lib/WebworkWebservice/RenderProblem.pm index 00217577f3..08d8ec4c91 100644 --- a/lib/WebworkWebservice/RenderProblem.pm +++ b/lib/WebworkWebservice/RenderProblem.pm @@ -26,6 +26,14 @@ async sub renderProblem { # is enabled. That is an expensive method to always call here. debug(pretty_print_rh($rh)) if $WeBWorK::Debug::Enabled; + # If the problem source is provided, check user is allow to render problem source. + if (!$ws->authz->hasPermissions($rh->{user}, 'webservice_render_source') + && ($rh->{problemSource} || $rh->{rawProblemSource} || $rh->{uriEncodedProblemSource})) + { + $ws->error_string(__PACKAGE__ . ": User $rh->{user} does not have permission to render problem source."); + return {}; + } + my $problemSeed = $rh->{problemSeed} // '1234'; my $beginTime = Benchmark->new; @@ -250,26 +258,23 @@ async sub renderProblem { # New version of output: return { - text => $pg->{body_text}, - header_text => $pg->{head_text}, - post_header_text => $pg->{post_header_text}, - answers => $pg->{answers}, - errors => $pg->{errors}, - pg_warnings => $pg->{warnings}, - PG_ANSWERS_HASH => $pg->{PG_ANSWERS_HASH}, - PERSISTENCE_HASH => $pg->{PERSISTENCE_HASH}, - problem_result => $pg->{result}, - problem_state => $pg->{state}, - flags => $pg->{flags}, - psvn => $psvn, - problem_seed => $problemSeed, - resource_list => $pg->{resource_list}, - warning_messages => ref $pg->{warning_messages} eq 'ARRAY' ? $pg->{warning_messages} : [], - debug_messages => ref $pg->{debug_messages} eq 'ARRAY' ? $pg->{debug_messages} : [], - internal_debug_messages => ref $pg->{internal_debug_messages} eq 'ARRAY' - ? $pg->{internal_debug_messages} - : [], - compute_time => logTimingInfo($beginTime, Benchmark->new), + text => $pg->{body_text}, + header_text => $pg->{head_text}, + post_header_text => $pg->{post_header_text}, + answers => $pg->{answers}, + errors => $pg->{errors}, + pg_warnings => $pg->{warnings}, + PG_ANSWERS_HASH => $pg->{PG_ANSWERS_HASH}, + PERSISTENCE_HASH => $pg->{PERSISTENCE_HASH}, + problem_result => $pg->{result}, + problem_state => $pg->{state}, + flags => $pg->{flags}, + psvn => $psvn, + problem_seed => $problemSeed, + resource_list => $pg->{resource_list}, + warning_messages => ref $pg->{warning_messages} eq 'ARRAY' ? $pg->{warning_messages} : [], + debug_messages => ref $pg->{debug_messages} eq 'ARRAY' ? $pg->{debug_messages} : [], + compute_time => logTimingInfo($beginTime, Benchmark->new), }; } diff --git a/templates/ContentGenerator/Base/error_output.html.ep b/templates/ContentGenerator/Base/error_output.html.ep index b6960ba065..5533a7f94d 100644 --- a/templates/ContentGenerator/Base/error_output.html.ep +++ b/templates/ContentGenerator/Base/error_output.html.ep @@ -1,11 +1,12 @@ % use Date::Format; % -

    <%= maketext('WeBWorK Error') %>

    +% unless (stash->{briefErrorOutput}) { +

    <%= maketext('WeBWorK Error') %>

    +% }

    <%= maketext( - 'WeBWorK has encountered a software error while attempting to process this problem. It is likely that ' - . 'there is an error in the problem itself. If you are a student, report this error message to your ' - . 'professor to have it corrected. If you are a professor, please consult the error output below for ' + 'WeBWorK has encountered a software error. If you are a student, report this error message to your ' + . 'instructor to have it corrected. If you are a instructor, please consult the error output below for ' . 'more information.' ) %>

    @@ -15,6 +16,7 @@
    <%== ref $details =~ /SCALAR/i ? $$details : ref $details =~ /ARRAY/i ? join('', @$details) : $details %>
    +% last if stash->{briefErrorOutput};

    <%= maketext('Request information') %>

    diff --git a/templates/ContentGenerator/Base/feedback_macro_email.html.ep b/templates/ContentGenerator/Base/feedback_macro_email.html.ep index 2c9d5a8b7a..3d5f6f2a62 100644 --- a/templates/ContentGenerator/Base/feedback_macro_email.html.ep +++ b/templates/ContentGenerator/Base/feedback_macro_email.html.ep @@ -6,6 +6,8 @@ % next if $key eq 'pg_object'; # Not used in internal feedback mechanism <%= hidden_field $key => $value =%> % } - <%= submit_button maketext($ce->{feedback_button_name}) || maketext('Email instructor'), - name => 'feedbackForm', class => 'btn btn-primary' =%> +
    + <%= submit_button maketext($ce->{feedback_button_name}) || maketext('Email instructor'), + name => 'feedbackForm', class => 'btn btn-primary' =%> +
    % end diff --git a/templates/ContentGenerator/Base/links.html.ep b/templates/ContentGenerator/Base/links.html.ep index f45f2f9b2e..171206b58b 100644 --- a/templates/ContentGenerator/Base/links.html.ep +++ b/templates/ContentGenerator/Base/links.html.ep @@ -221,31 +221,8 @@ % # Statistics % # Student Progress diff --git a/templates/ContentGenerator/Base/login_status.html.ep b/templates/ContentGenerator/Base/login_status.html.ep index 1e835b84ff..aca49ad3ca 100644 --- a/templates/ContentGenerator/Base/login_status.html.ep +++ b/templates/ContentGenerator/Base/login_status.html.ep @@ -6,10 +6,12 @@ % my $effectiveUserID = param('effectiveUser'); % my $userName = $user->full_name || $user->user_id; % - <%= maketext('Logged in as [_1].', $userName) %> - <%= link_to $c->systemLink(url_for 'logout'), class => 'btn btn-light btn-sm ms-2', begin %> - <%= maketext('Log Out') %> - <% end %> +
    + <%= maketext('Logged in as [_1].', $userName) %> + <%= link_to $c->systemLink(url_for 'logout'), class => 'btn btn-light btn-sm ms-2', begin %> + <%= maketext('Log Out') %> + <% end %> +
    % % if ($effectiveUserID ne $userID) { % my $effectiveUser = $db->getUser($effectiveUserID); @@ -22,13 +24,14 @@ % ? join(' ', $effectiveUser->full_name, '(' . $effectiveUser->user_id . ')') % : $effectiveUser->user_id; % -
    - <%= maketext('Acting as [_1].', $effectiveUserName) %> - <%= link_to $c->systemLink(url_for, params => { effectiveUser => $userID }), - class => 'btn btn-light btn-sm ms-2', begin %> - <%= maketext('Stop Acting') %> - <% end %> +
    + <%= maketext('Acting as [_1].', $effectiveUserName) %> + <%= link_to $c->systemLink(url_for, params => { effectiveUser => $userID }), + class => 'btn btn-light btn-sm ms-2', begin %> + <%= maketext('Stop Acting') %> + <% end %> +
    % } % } else { - <%= maketext('Not logged in.') =%> +
    <%= maketext('Not logged in.') %>
    % } diff --git a/templates/ContentGenerator/Base/problem_warning_and_debug_output.html.ep b/templates/ContentGenerator/Base/problem_warning_and_debug_output.html.ep new file mode 100644 index 0000000000..9faf5184c0 --- /dev/null +++ b/templates/ContentGenerator/Base/problem_warning_and_debug_output.html.ep @@ -0,0 +1,34 @@ +% if ($warnings) { +
    +
    +

    <%= maketext('PG warning messages') %>

    +
      + % for (split m/\n+/, $warnings) { +
    • <%== $_ %>
    • + % } +
    +
    +
    +% } +% if (@$warning_messages) { +
    +
    +

    <%= maketext('PG processing warning messages') %>

    +
      + % for (@$warning_messages) { +
    • <%== $_ %>
    • + % } +
    +
    +
    +% } +% if (@$debug_messages) { +
    +
    +

    <%= maketext('PG debug messages') %>

    + % for (@$debug_messages) { +
    <%== $_ %>
    + % } +
    +
    +% } diff --git a/templates/ContentGenerator/Base/warning_output.html.ep b/templates/ContentGenerator/Base/warning_output.html.ep index ace4b696a5..f51c5935da 100644 --- a/templates/ContentGenerator/Base/warning_output.html.ep +++ b/templates/ContentGenerator/Base/warning_output.html.ep @@ -3,17 +3,15 @@

    <%= maketext('WeBWorK Warnings') %>

    <%= maketext( - 'WeBWorK has encountered warnings while processing your request. If this occurred when viewing ' - . 'a problem, it was likely caused by an error or ambiguity in that problem. Otherwise, it may indicate ' - . 'a problem with the WeBWorK system itself. If you are a student, report these warnings to your ' - . 'professor to have them corrected. If you are a professor, please consult the warning output below ' - . 'for more information.' + 'WeBWorK has encountered warnings while processing your request. This indicates a problem with the WeBWorK ' + . 'system. If you are a student, report these warnings to your instructor to have them corrected. If you ' + . 'are a instructor, please consult the warning output below for more information.' ) %>

    <%= maketext('Warning messages') %>

      % for (@$warnings) { -
    • <%= $_ %>
    • +
    • <%= $_ %>
    • % }

    <%= maketext('Request information') %>

    diff --git a/templates/ContentGenerator/Feedback/feedback_email.html.ep b/templates/ContentGenerator/Feedback/feedback_email.html.ep index 901e899a28..667e2fb5df 100644 --- a/templates/ContentGenerator/Feedback/feedback_email.html.ep +++ b/templates/ContentGenerator/Feedback/feedback_email.html.ep @@ -1,22 +1,22 @@ % use WeBWorK::Utils qw(decodeAnswers); % use WeBWorK::Utils::Sets qw(format_set_name_display); % +% my $yes = maketext('yes'); +% my $no = maketext('no'); +%

    - % if ($problem) { - Message from <%= $user->full_name %> (<%= $user->user_id %>) via WeBWorK at - <%= $ce->{institutionName} %> (sent from - <%= link_to format_set_name_display($set->set_id) . ', #' . $problem->problem_id => $emailableURL %>). - % } elsif ($set) { - Message from <%= $user->full_name %> (<%= $user->user_id %>) via WeBWorK at - <%= $ce->{institutionName} %> - (sent from <%= link_to format_set_name_display($set->set_id) => $emailableURL %>) - % } else { - Message from <%= $user->full_name %> (<%= $user->user_id %>) via WeBWorK at - <%= $ce->{institutionName} %> (sent from <%= link_to 'this page' => $emailableURL %>). - % } + <%== maketext('Message from [_1] ([_2]) via WeBWorK at [_3] (sent from [_4]).', + $user->full_name, $user->user_id, $ce->{institutionName}, + $problem ? link_to(format_set_name_display($set->set_id) . ', #' . $problem->problem_id, $emailableURL) + : $set ? link_to(format_set_name_display($set->set_id), $emailableURL) + : link_to('this page', $emailableURL) + ) =%>

    + % if ($numRecipients > 1) { +

    <%= maketext('Message delivered to multiple recipients. Consider using reply-all.') =%>

    + % } % if ($feedback) {
    % for (split /\n\r?/, $feedback) { @@ -32,19 +32,20 @@
    + background-color: lightgray" colspan="2"><%= maketext('Data about the problem') %> % my @rows = ( - % [ 'Problem ID', $problem->problem_id ], - % [ 'Source file', $problem->source_file ], - % [ 'Value', $problem->value ], - % [ 'Max attempts', $problem->max_attempts == -1 ? 'unlimited' : $problem->max_attempts ], - % [ 'Random seed', $problem->problem_seed ], - % [ 'Status', $problem->status ], - % [ 'Attempted', $problem->attempted ? 'yes' : 'no' ], - % [ 'Correct attempts', $problem->num_correct ], - % [ 'Incorrect attempts', $problem->num_incorrect ] + % [ maketext('Problem ID'), $problem->problem_id ], + % [ maketext('Source file'), $problem->source_file ], + % [ maketext('Value'), $problem->value ], + % [ maketext('Max attempts'), + % $problem->max_attempts == -1 ? 'unlimited' : $problem->max_attempts ], + % [ maketext('Random seed'), $problem->problem_seed ], + % [ maketext('Status'), $problem->status ], + % [ maketext('Attempted'), $problem->attempted ? $yes : $no ], + % [ maketext('Correct attempts'), $problem->num_correct ], + % [ maketext('Incorrect attempts'), $problem->num_incorrect ] % ); % for (@rows) { @@ -54,20 +55,26 @@ % } % my %last_answer = decodeAnswers($problem->last_answer); - + % if (%last_answer) { - + % } else { - + % } @@ -77,28 +84,28 @@
    Data about the problem
    Last submission: + <%= maketext('Last submission:') =%> + - % for my $key (sort keys %last_answer) { - % if ($last_answer{$key}) { - - - - - % } - % } -
    <%= $key %>:<%= $last_answer{$key} %>
    + + % for my $key (sort keys %last_answer) { + % if ($last_answer{$key}) { + + + + + % } + % } +
    <%= $key %>: + <%= $last_answer{$key} %> +
    +
    none<%= maketext('none') %>
    + background-color: lightgray" colspan="2"><%= maketext('Data about the assignment') %> % my @rows = ( - % [ 'Set ID', $set->set_id ], - % [ 'Set header file', $set->set_header ], - % [ 'Hardcopy header file', $set->hardcopy_header ], - % [ 'Open date', $c->formatDateTime($set->open_date) ], - % [ 'Close date', $c->formatDateTime($set->due_date) ], - % [ 'Answer date', $c->formatDateTime($set->answer_date) ], - % [ 'Visible', $set->visible ? 'yes' : 'no' ], - % [ 'Assignment type', $set->assignment_type ] + % [ maketext('Set ID'), $set->set_id ], + % [ maketext('Set header file'), $set->set_header ], + % [ maketext('Hardcopy header file'), $set->hardcopy_header ], + % [ maketext('Open date'), $c->formatDateTime($set->open_date) ], + % [ maketext('Close date'), $c->formatDateTime($set->due_date) ], + % [ maketext('Answer date'), $c->formatDateTime($set->answer_date) ], + % [ maketext('Visible'), $set->visible ? $yes : $no ], + % [ maketext('Assignment type'), $set->assignment_type ] % ); % if ($set->assignment_type =~ /gateway/) { % push @rows, ( - % [ 'Attempts per version', $set->attempts_per_version ], - % [ 'Time interval', $set->time_interval ], - % [ 'Versions per interval', $set->versions_per_interval ], - % [ 'Version time limit', $set->version_time_limit ], - % [ 'Version creation time', $c->formatDateTime($set->version_creation_time) ], - % [ 'Problem randorder', $set->problem_randorder ], - % [ 'Version last attempt time', $set->version_last_attempt_time ] + % [ maketext('Attempts per version'), $set->attempts_per_version ], + % [ maketext('Time interval'), $set->time_interval ], + % [ maketext('Versions per interval'), $set->versions_per_interval ], + % [ maketext('Version time limit'), $set->version_time_limit ], + % [ maketext('Version creation time'), $c->formatDateTime($set->version_creation_time) ], + % [ maketext('Problem randorder'), $set->problem_randorder ], + % [ maketext('Version last attempt time'), $set->version_last_attempt_time ] % ); % } % for (@rows) { @@ -113,16 +120,20 @@ % if ($problem && $verbosity >= 1) {
    Data about the assignment
    - + + + % my @rows = ( - % [ 'Display Mode', param('displayMode') ], - % [ 'Show Old Answers', param('showOldAnswers') ? 'yes' : 'no' ], - % [ 'Show Correct Answers', param('showCorrectAnswers') ? 'yes' : 'no' ], - % [ 'Show Hints', param('showHints') ? 'yes' : 'no' ], - % [ 'Show Solutions', param('showSolutions') ? 'yes' : 'no' ] + % [ maketext('Display Mode'), param('displayMode') ], + % [ maketext('Show Old Answers'), param('showOldAnswers') ? $yes : $no ], + % [ maketext('Show Correct Answers'), param('showCorrectAnswers') ? $yes : $no ], + % [ maketext('Show Hints'), param('showHints') ? $yes : $no ], + % [ maketext('Show Solutions'), param('showSolutions') ? $yes : $no ] % ); % for (@rows) { @@ -138,26 +149,26 @@
    Data about the problem processor
    + <%= maketext('Data about the problem processor') =%> +
    + background-color: lightgray" colspan="2"><%= maketext('Data about the user') %> % my @rows = ( - % [ 'User ID', $user->user_id ], - % [ 'Name', $user->full_name ], - % [ 'Email', $user->email_address ] + % [ maketext('User ID'), $user->user_id ], + % [ maketext('Name'), $user->full_name ], + % [ maketext('Email'), $user->email_address ] % ); % unless ($ce->{blockStudentIDinFeedback}) { push @rows, ['Student ID', $user->student_id]; } % my $status_name = $ce->status_abbrev_to_name($user->status); % my $status_string = % defined $status_name % ? "$status_name ('" . $user->status . q{')} - % : $user->status . ' (unknown status abbreviation)'; + % : maketext('[_1] (unknown status abbreviation)', $user->status); % push @rows, ( - % [ 'Status', $status_string ], - % [ 'Section', $user->section ], - % [ 'Recitation', $user->recitation ], - % [ 'Comment', $user->comment ], - % [ 'IP Address', $remote_host ] + % [ maketext('Status'), $status_string ], + % [ maketext('Section'), $user->section ], + % [ maketext('Recitation'), $user->recitation ], + % [ maketext('Comment'), $user->comment ], + % [ maketext('IP Address'), $remote_host ] %); % for (@rows) { @@ -172,7 +183,7 @@
    Data about the user
    + background-color: lightgray" colspan="2"><%= maketext('Data about the environment') %> diff --git a/templates/ContentGenerator/Feedback/feedback_email.txt.ep b/templates/ContentGenerator/Feedback/feedback_email.txt.ep index 3771d933b1..5de552e159 100644 --- a/templates/ContentGenerator/Feedback/feedback_email.txt.ep +++ b/templates/ContentGenerator/Feedback/feedback_email.txt.ep @@ -1,104 +1,109 @@ % use WeBWorK::Utils qw(decodeAnswers); % use WeBWorK::Utils::Sets qw(format_set_name_display); % -Message from <%= $user->full_name %> (<%= $user->user_id %>) via WeBWorK at <%= $ce->{institutionName} %>. +<%= maketext('Message from [_1] ([_2]) via WeBWorK at [_3].', + $user->full_name, $user->user_id, $ce->{institutionName}) %> % if ($problem) { -Feedback sent from <%= format_set_name_display($set->set_id) . ', #' . $problem->problem_id %>: +<%= maketext('Feedback sent from [_1]:', format_set_name_display($set->set_id) . ', #' . $problem->problem_id) %> % } elsif ($set) { -Feedback sent from <%= format_set_name_display($set->set_id) %>: +<%= maketext('Feedback sent from [_1]:', format_set_name_display($set->set_id)) %> % } else { -Feedback sent from: +<%= maketext('Feedback sent from:') %> % } <%== $emailableURL %> +% if ($numRecipients > 1) { + +<%= maketext('Message delivered to multiple recipients. Consider using reply-all.') %> +% } % if ($feedback) { -<%== $user->full_name %> (<%== $user->user_id %>) wrote: +<%= maketext('[_1] ([_2]) wrote:', $user->full_name, $user->user_id) %> <%== $feedback %> % } % if ($problem && $verbosity >= 1) { -***** Data about the problem: ***** +***** <%= maketext('Data about the problem:') %> ***** -Problem ID: <%== $problem->problem_id %> -Source file: <%== $problem->source_file %> -Value: <%== $problem->value %> -Max attempts <%== $problem->max_attempts == -1 ? 'unlimited' : $problem->max_attempts %> -Random seed: <%== $problem->problem_seed %> -Status: <%== $problem->status %> -Attempted: <%== $problem->attempted ? 'yes' : 'no' %> -Number of correct attempts: <%== $problem->num_correct %> -Number of incorrect attempts: <%== $problem->num_incorrect %> +<%= maketext('Problem ID:') %> <%== $problem->problem_id %> +<%= maketext('Source file:') %> <%== $problem->source_file %> +<%= maketext('Value:') %> <%== $problem->value %> +<%= maketext('Max attempts') %> <%== $problem->max_attempts == -1 ? 'unlimited' : $problem->max_attempts %> +<%= maketext('Random seed:') %> <%== $problem->problem_seed %> +<%= maketext('Status:') %> <%== $problem->status %> +<%= maketext('Attempted:') %> <%== $problem->attempted ? 'yes' : 'no' %> +<%= maketext('Number of correct attempts:') %> <%== $problem->num_correct %> +<%= maketext('Number of incorrect attempts:') %> <%== $problem->num_incorrect %> % my %last_answer = decodeAnswers($problem->last_answer); % if (%last_answer) { -Last submission: - % for my $key (sort keys %last_answer) { - % if ($last_answer{$key}) { +<%= maketext('Last submission:') %> + % for my $key (sort keys %last_answer) { + % if ($last_answer{$key}) { <%== $key %>: <%== $last_answer{$key} %> + % } % } - % } % } else { -Last submission: none +<%= maketext('Last submission:') =%> <%= maketext('none') %> % } % } % if ($set && $verbosity >= 1) { -***** Data about the assignment: ***** +***** <%= maketext('Data about the assignment:') %> ***** -Set ID: <%== $set->set_id %> -Set header file: <%== $set->set_header %> -Hardcopy header file: <%== $set->hardcopy_header %> -Open date: <%== $c->formatDateTime($set->open_date) %> -Due date: <%== $c->formatDateTime($set->due_date) %> -Answer date: <%== $c->formatDateTime($set->answer_date) %> -Visible: <%== $set->visible ? 'yes' : 'no' %> -Assignment type: <%== $set->assignment_type %> +<%= maketext('Set ID:') %> <%== $set->set_id %> +<%= maketext('Set header file:') %> <%== $set->set_header %> +<%= maketext('Hardcopy header file:') %> <%== $set->hardcopy_header %> +<%= maketext('Open date:') %> <%== $c->formatDateTime($set->open_date) %> +<%= maketext('Due date:') %> <%== $c->formatDateTime($set->due_date) %> +<%= maketext('Answer date:') %> <%== $c->formatDateTime($set->answer_date) %> +<%= maketext('Visible:') %> <%== $set->visible ? 'yes' : 'no' %> +<%= maketext('Assignment type:') %> <%== $set->assignment_type %> % if ($set->assignment_type =~ /gateway/) { -Attempts per version: <%== $set->attempts_per_version %> -Time interval: <%== $set->time_interval %> -Versions per interval: <%== $set->versions_per_interval %> -Version time limit: <%== $set->version_time_limit %> -Version creation time: <%== $c->formatDateTime($set->version_creation_time) %> -Problem randorder: <%== $set->problem_randorder %> -Version last attempt time: <%== $set->version_last_attempt_time %> +<%= maketext('Attempts per version:') %> <%== $set->attempts_per_version %> +<%= maketext('Time interval:') %> <%== $set->time_interval %> +<%= maketext('Versions per interval:') %> <%== $set->versions_per_interval %> +<%= maketext('Version time limit:') %> <%== $set->version_time_limit %> +<%= maketext('Version creation time:') %> <%== $c->formatDateTime($set->version_creation_time) %> +<%= maketext('Problem randorder:') %> <%== $set->problem_randorder %> +<%= maketext('Version last attempt time:') %> <%== $set->version_last_attempt_time %> % } % } % if ($problem && $verbosity >= 1) { -***** Data about the problem processor: ***** +***** <%= maketext('Data about the problem processor:') %> ***** -Display Mode: <%== param('displayMode') %> -Show Old Answers: <%== param('showOldAnswers') ? 'yes' : 'no' %> -Show Correct Answers: <%== param('showCorrectAnswers') ? 'yes' : 'no' %> -Show Hints: <%== param('showHints') ? 'yes' : 'no' %> -Show Solutions: <%== param('showSolutions') ? 'yes' : 'no' %> +<%= maketext('Display Mode:') %> <%== param('displayMode') %> +<%= maketext('Show Old Answers:') %> <%== param('showOldAnswers') ? 'yes' : 'no' %> +<%= maketext('Show Correct Answers:') %> <%== param('showCorrectAnswers') ? 'yes' : 'no' %> +<%= maketext('Show Hints:') %> <%== param('showHints') ? 'yes' : 'no' %> +<%= maketext('Show Solutions:') %> <%== param('showSolutions') ? 'yes' : 'no' %> % } % if ($user && $verbosity >= 1) { -***** Data about the user: ***** +***** <%= maketext('Data about the user:') %> ***** -User ID: <%== $user->user_id %> -Name: <%== $user->full_name %> -Email: <%== $user->email_address %> +<%= maketext('User ID:') %> <%== $user->user_id %> +<%= maketext('Name:') %> <%== $user->full_name %> +<%= maketext('Email:') %> <%== $user->email_address %> % unless ($ce->{blockStudentIDinFeedback}) { -Student ID: <%== $user->student_id %> +<%= maketext('Student ID:') %> <%== $user->student_id %> % } % my $status_name = $ce->status_abbrev_to_name($user->status); %my $status_string = % defined $status_name % ? "$status_name ('" . $user->status . q{')} - % : $user->status . ' (unknown status abbreviation)'; -Status: <%== $status_string %> -Section: <%== $user->section %> -Recitation: <%== $user->recitation %> -Comment: <%== $user->comment %> -IP Address: <%== $remote_host %>:<%== $c->tx->remote_port || 'UNKNOWN' %> + % : maketext('[_1] (unknown status abbreviation)', $user->status); +<%= maketext('Status:') %> <%== $status_string %> +<%= maketext('Section:') %> <%== $user->section %> +<%= maketext('Recitation:') %> <%== $user->recitation %> +<%= maketext('Comment:') %> <%== $user->comment %> +<%= maketext('IP Address:') %> <%== $remote_host %>:<%== $c->tx->remote_port || 'UNKNOWN' %> % } % if ($verbosity >= 2) { -Data about the environment +<%= maketext('Data about the environment') %> <%== dumper($ce) %> % } diff --git a/templates/ContentGenerator/GatewayQuiz.html.ep b/templates/ContentGenerator/GatewayQuiz.html.ep index 49f951a04a..244bdbcd38 100644 --- a/templates/ContentGenerator/GatewayQuiz.html.ep +++ b/templates/ContentGenerator/GatewayQuiz.html.ep @@ -108,25 +108,6 @@ % last; % } % -% # If there were translation errors, then show those and exit. -% if (@{ $c->{errors} }) { - % my $errorNum = 1; - % my ($message, $context) = (c, c); - % for (@{ $c->{errors} }) { - % push(@$message, "$errorNum. ") if (@{ $c->{errors} } > 1); - % push(@$message, $_->{message}, tag('br')); - % - % my $line = begin -

    <%= (@{ $c->{errors} } > 1 ? "$errorNum." : '') %><%== $_->{context} %>

    -
    - % end - % push @$context, $line->(); - % } - <%= include 'ContentGenerator/Base/error_output', error => $message->join(''), details => $context->join('') =%> - % - % last; -% } -% % my $setID = $c->{set}->set_id; % my $setVersionID = $c->{set}->version_id; % my $numProbPerPage = $c->{set}->problems_per_page; @@ -188,7 +169,7 @@ % && $c->{can}{showScore} % ) % { -
    +
    <%== maketext( 'Your recorded score for this version is [_1]/[_2] ([_3]%).', '' . wwRound(2, $c->{recordedScore}) . '', @@ -201,7 +182,7 @@ % } % } elsif ($c->{will}{checkAnswers}) { % if ($c->{can}{showScore}) { -
    +
    <%= maketext('Your score on this (checked, not recorded) submission is [_1]/[_2].', $c->{attemptScore}, $c->{totalPossible}) =%> @@ -226,7 +207,7 @@ % && before($c->{set}->due_date, $submitTime) % && ($c->{can}{recordAnswersNextTime} || $c->{submitAnswers})) % { -
    +
    % my $text = maketext('You are in the Reduced Scoring Period. All work counts for [_1]% of the original.', % $ce->{pg}{ansEvalDefaults}{reducedScoringValue} * 100); @@ -328,7 +309,7 @@ % } % } else { % if (!$c->{checkAnswers} && !$c->{submitAnswers} && $c->{can}{showScore}) { -
    +
    <%== maketext( 'Your recorded score on this test (version [_1]) is [_2]/[_3] ([_4]%).', @@ -350,12 +331,14 @@ % } % % if ($c->{set}->version_last_attempt_time) { -
    +
    <%= maketext('Time taken on test: [_1] min ([_2] min allowed).', $c->{elapsedTime}, sprintf('%.0f', 10 * ($c->{set}->due_date - $c->{set}->open_date) / 6) / 100) %> +
    + <%= maketext('Test completed on [_1].', $c->{completedTime}) %>
    % } elsif ($c->{exceededAllowedTime} && $c->{recordedScore} != 0) { -
    +
    <%= maketext('(This test is overtime because it was not submitted in the allowed time.)') %>
    % } @@ -405,8 +388,18 @@ % # Problems can be shown, so output the main form and the problems. % my $startTime = param('startTime') || time; % - <%= form_for $action, name => 'gwquiz', method => 'POST', class => 'problem-main-form', begin =%> + % if ($haveProblemWarnings) { +
    +
    + <%== maketext('Warning: There may be something wrong with a problem in this test. ' + . 'Please inform your instructor including the warning messages below the problem.') =%> +
    +
    + % } + % + <%= form_for $action, name => 'gwquiz', method => 'POST', class => 'problem-main-form mt-0', begin =%> <%= $c->hidden_authen_fields =%> + <%= hidden_field courseID => $ce->{courseName} =%> % % # Hacks to use a javascript link to trigger previews and jump to subsequent pages of a multipage test. <%= hidden_field pageChangeHack => '' =%> @@ -448,9 +441,10 @@ % end % if ($numProbPerPage && $numPages > 1) { % content_for 'gw-navigation-cols' => begin - % for (1 .. $numPages) { + % for my $pageNum (1 .. $numPages) {
    % for (1 .. $numProbPerPage) { + % last if $_ * $pageNum > @$problem_numbers; % } @@ -458,7 +452,9 @@ % end % for my $i (1 .. $numPages) { % content_for 'gw-navigation-pages' => begin - % } % end + % content_for 'gw-previous-next-buttons' => begin +
    + % my $prevText = $numProbPerPage == 1 ? maketext('Previous Problem') : maketext('Previous Page'); + % if ($pageNumber > 1) { + <%= link_to $prevText => '#', + class => 'btn btn-primary page-change-link', data => { page_number => $pageNumber - 1 } =%> + % } else { + <%= $prevText =%> + % } + % my $nextText = $numProbPerPage == 1 ? maketext('Next Problem') : maketext('Next Page'); + % if ($pageNumber < $numPages) { + <%= link_to $nextText => '#', + class => 'btn btn-primary page-change-link', data => { page_number => $pageNumber + 1 } =%> + % } else { + <%= $nextText =%> + % } +
    + % end % } else { % content_for 'gw-navigation-cols' => begin
    <% for (0 .. $#$pg_results) { =%><% } =%> @@ -508,6 +522,7 @@ <%= content 'gw-navigation-table-rows' =%>
    Data about the environment
    <%= dumper($ce) %>
    % if ($i == $pageNumber) { <%= $i =%> @@ -485,6 +481,24 @@
    + <%= content 'gw-previous-next-buttons' =%> % end <%= $jumpLinks->() =%> % @@ -530,7 +545,7 @@ % $recordMessage = tag('div', class => 'alert alert-danger d-inline-block mb-2 p-1', % maketext('CORRECT ANSWERS SHOWN ONLY -- ANSWERS NOT RECORDED') % ); - % } elsif ($c->{will}{checkAnswers} || $c->{will}{showProblemGrader}) { + % } elsif ($c->{will}{checkAnswers}) { % $recordMessage = tag('div', class => 'alert alert-danger d-inline-block mb-2 p-1', % maketext('ANSWERS ONLY CHECKED -- ANSWERS NOT RECORDED') % ); @@ -546,7 +561,7 @@ % # Show the jump to anchor.
    " tabindex="-1"><%= $recordMessage %>
    % # Output the problem header. -

    <%= maketext('Problem [_1].', $i + 1) %>

    +

    <%= maketext('Problem [_1].', $i + 1) %>

    % if ($c->{can}{showTemplateIds}) { <%= '(' @@ -581,11 +596,21 @@ % } % -
    {flags}, $ce->{perProblemLangAndDirSettingMode}, $ce->{language} - ) %>> - <%== $pg->{body_text} =%> -
    + % # If there were translation errors, then show those instead of the problem. + % if ($pg->{flags}{error_flag}) { + % stash->{briefErrorOutput} = 1; + <%= include 'ContentGenerator/Base/error_output', + error => $pg->{errors}, + details => $pg->{body_text} =%> + % + % delete stash->{briefErrorOutput}; + % } else { +
    {flags}, $ce->{perProblemLangAndDirSettingMode}, $ce->{language} + ) %> data-bs-theme="light"> + <%== $pg->{body_text} =%> +
    + % } % if ($pg->{result}{msg}) {
    <%== maketext('Note: [_1]', tag('i', $pg->{result}{msg})) %>
    % } @@ -621,7 +646,7 @@
    <%= link_to maketext('preview answers') => '#', class => 'gateway-preview-btn btn btn-secondary', - ($numProbPerPage && $numPages > 1) ? (data_page_number => $pageNumber) : () =%> + ($numProbPerPage && $numPages > 1) ? (data => { page_number => $pageNumber }) : () =%>
    % % if ($resultsTable) { @@ -629,10 +654,15 @@ % } % % # Initialize the problem graders for the problem. - % if ($c->{will}{showProblemGrader}) { - <%= WeBWorK::HTML::SingleProblemGrader->new($c, $pg, $problems->[ $probOrder->[$i] ]) + % if ($c->{will}{showProblemGrader} && !$pg->{flags}{error_flag}) { + <%= WeBWorK::HTML::SingleProblemGrader->new($c, $pg, $problems->[ $probOrder->[$i] ], $c->{set}) ->insertGrader =%> % } + % # Show warnings for the problem if there are any. + <%= include 'ContentGenerator/Base/problem_warning_and_debug_output', + warnings => $pg->{warnings}, + warning_messages => ref $pg->{warning_messages} eq 'ARRAY' ? $pg->{warning_messages} : [], + debug_messages => ref $pg->{debug_messages} eq 'ARRAY' ? $pg->{debug_messages} : [] =%> % # Store the problem status for continued attempts recording. <%= hidden_field 'probstatus' . $problems->[ $probOrder->[$i] ]{problem_id} @@ -705,6 +735,15 @@ : maketext( 'This is your only submission. If you say yes, then your answers will be final, ' . 'and you will not be able to continue to work this test version.' + ), + # This is always a plural form. JavaScript replaces %d with the + # number of unanswered questions which will be greater than one. + unanswered_questions_message => + maketext('There are [_1] problems with unanswered questions.', '%d'), + unanswered_question_message => maketext('There is a problem with unanswered questions.'), + return_to_test_message => maketext( + 'Are you sure you want to grade the test? ' + . 'Select "No" if you would like to return to the test to enter more answers.' ) } ) @@ -716,20 +755,10 @@

    <%= maketext('Note: grading the test grades all problems, not just those on this page.') %>

    % } % - % if ($c->{can}{showProblemGrader}) { + % if ($c->{can}{showCorrectAnswers}) {
    - % if ($c->{can}{showCorrectAnswers}) { - <%= submit_button maketext('Show Correct Answers'), name => 'showCorrectAnswers', - class => 'btn btn-primary mb-1' =%> - % } - % if ($c->{will}{showProblemGrader}) { - <%= submit_button maketext('Hide Problem Graders'), name => 'hideProblemGrader', - class => 'btn btn-primary mb-1' =%> - <%= hidden_field showProblemGrader => 1 =%> - % } else { - <%= submit_button maketext('Show Problem Graders'), name => 'showProblemGrader', - class => 'btn btn-primary mb-1' =%> - % } + <%= submit_button maketext('Show Correct Answers'), name => 'showCorrectAnswers', + class => 'btn btn-primary mb-1' =%>
    % } % @@ -763,5 +792,5 @@ % # If achievements enabled, check to see if there are new ones and output them. Use the first % # problem to seed the data. However, all of the problems will be provided to the achievement evaluator. % if ($ce->{achievementsEnabled} && $c->{will}{recordAnswers} && $c->{submitAnswers} && $setID ne 'Undefined_Set') { - <%= checkForAchievements($problems->[0], $pg_results->[0], $c, setVersion => $setVersionID) =%> + <%= checkForAchievements($problems->[0], $c, setVersion => $setVersionID) =%> % } diff --git a/templates/ContentGenerator/GatewayQuiz/nav.html.ep b/templates/ContentGenerator/GatewayQuiz/nav.html.ep index f4b83b096c..3a3f7aca81 100644 --- a/templates/ContentGenerator/GatewayQuiz/nav.html.ep +++ b/templates/ContentGenerator/GatewayQuiz/nav.html.ep @@ -9,28 +9,36 @@
  • <%= link_to maketext('Show all tests') => $c->systemLink( url_for('gateway_quiz', setID => "$setID,v$setVersion"), - params => { - effectiveUser => param('effectiveUser'), - currentPage => $pageNumber, - showProblemGrader => $c->{will}{showProblemGrader} - } + params => { effectiveUser => param('effectiveUser'), currentPage => $pageNumber } ), class => 'dropdown-item' =%>
  • @@ -104,10 +109,9 @@ <%= link_to $filters->{$_}[0] => $c->systemLink( url_for('gateway_quiz', setID => "$setID,v$filters->{$_}[2]"), params => { - effectiveUser => $filters->{$_}[1], - currentPage => $pageNumber, - showProblemGrader => $c->{will}{showProblemGrader}, - studentNavFilter => $_ + effectiveUser => $filters->{$_}[1], + currentPage => $pageNumber, + studentNavFilter => $_ } ), class => 'dropdown-item', diff --git a/templates/ContentGenerator/Instructor/LTIUpdate.html.ep b/templates/ContentGenerator/Instructor/LTIUpdate.html.ep index 40fd1f3da5..ed37539383 100644 --- a/templates/ContentGenerator/Instructor/LTIUpdate.html.ep +++ b/templates/ContentGenerator/Instructor/LTIUpdate.html.ep @@ -47,6 +47,7 @@ %

    <%= maketext('Start LTI Grade Update') %>

    <%= form_for current_route, method => 'POST', id => 'updateLTIForm', name => 'updateLTIForm', begin =%> + <%= $c->hidden_authen_fields =%>
    <%= label_for updateUserID => maketext('Update user:'), class => 'col-auto col-form-label fw-bold' =%>
    diff --git a/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep b/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep index e666e53937..b813220b8a 100644 --- a/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep +++ b/templates/ContentGenerator/Instructor/PGProblemEditor.html.ep @@ -103,20 +103,19 @@
    <%= link_to maketext('Sample Problems') => url_for('sample_problem_index'), target => 'techniques_window', - title => maketext('POD for macros and sample problem code and snippets'), - class => 'reference-link btn btn-sm btn-info', + title => maketext('Sample problem code with documentation.'), + class => 'btn btn-sm btn-info', data => { bs_toggle => 'tooltip', bs_placement => 'top' } =%> - % # http://webwork.maa.org/wiki/Category:MathObjects <%= link_to maketext('Math Objects') => $ce->{webworkURLs}{MathObjectsHelpURL}, target => 'math_objects', title => maketext('Wiki summary page for MathObjects'), - class => 'reference-link btn btn-sm btn-info', + class => 'btn btn-sm btn-info', data => { bs_toggle => 'tooltip', bs_placement => 'top' } =%> % # PG POD served locally <%= link_to maketext('POD') => url_for('pod_index'), target => 'pod_docs', title => maketext('Documentation from source code for PG modules and macro files.'), - class => 'reference-link btn btn-sm btn-info', + class => 'btn btn-sm btn-info', data => { bs_toggle => 'tooltip', bs_placement => 'top' } =%> % # PGML lab problem rendered as an unattached problem in a new window. % my $pgml_lab_source = readFile("$ce->{webworkDirs}{assets}/pg/PGMLLab/PGML-lab.pg"); @@ -125,15 +124,13 @@ 'PG markdown syntax used to format WeBWorK questions. ' . 'This interactive lab can help you to learn the techniques.' ), - id => 'pgml-lab', - class => 'reference-link btn btn-sm btn-info', - data => { source => url_escape($pgml_lab_source), bs_toggle => 'tooltip', bs_placement => 'top' }, + class => 'pgml-lab btn btn-sm btn-info', + data => { source => url_escape($pgml_lab_source), bs_toggle => 'tooltip', bs_placement => 'top' }, 'PGML' =%> - % # http://webwork.maa.org/wiki/Category:Authors <%= link_to maketext('Author Info') => $ce->{webworkURLs}{AuthorHelpURL}, target => 'author_info', title => maketext('Top level of author information on the wiki.'), - class => 'reference-link btn btn-sm btn-info', + class => 'btn btn-sm btn-info', data => { bs_toggle => 'tooltip', bs_placement => 'top' } =%> % # Only show the report bugs in problem button if editing an OPL or Contrib problem. % if ($ce->{webworkURLs}{OPLBugReporter} @@ -152,7 +149,7 @@ . 'The very first time you do this you will need to register with an email address so that ' . 'information on the bug fix can be reported back to you.' ), - class => 'reference-link btn btn-sm btn-info', + class => 'btn btn-sm btn-info', data => { bs_toggle => 'tooltip', bs_placement => 'top' } =%> % }
    diff --git a/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep b/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep new file mode 100644 index 0000000000..f05df5d277 --- /dev/null +++ b/templates/ContentGenerator/Instructor/PGProblemEditor/code_maintenance_form.html.ep @@ -0,0 +1,47 @@ +% last unless $c->{is_pg}; +
    +
    + <%= radio_button 'action.code_maintenance' => 'tidyPGCode', + id => 'action_code_maintenance_perltidy', class => 'form-check-input', checked => undef =%> + <%= label_for 'action_code_maintenance_perltidy', class => 'form-check-label', begin =%> + <%== maketext('Reformat the code using perltidy.') =%> + <% end =%> + + + <%= maketext('Perltidy Help') %> + +
    +
    + <%= radio_button 'action.code_maintenance' => 'convertCodeToPGML', + id => 'action_code_maintenance_convert_PGML', class => 'form-check-input'=%> + <%= label_for 'action_code_maintenance_convert_PGML', class => 'form-check-label', begin =%> + <%== maketext('Convert the code to PGML') =%> + <% end =%> + + + <%= maketext('PGML Conversion Help') %> + +
    +
    + <%= radio_button 'action.code_maintenance' => 'runPGCritic', + id => 'action_code_maintenance_run_pgcritic', class => 'form-check-input'=%> + <%= label_for 'action_code_maintenance_run_pgcritic', class => 'form-check-label', begin =%> + <%== maketext('Analyze code with PG Critic') =%> + <% end =%> + + + <%= maketext('PG Critic Help') %> + +
    +
    diff --git a/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep b/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep index 10e361a65f..1ba942eb24 100644 --- a/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep +++ b/templates/ContentGenerator/Instructor/PGProblemEditor/file_chooser.html.ep @@ -2,6 +2,7 @@ % <%= form_for current_route, method => 'POST', name => 'pg-editor-file-chooser', class => 'needs-validation', novalidate => undef, begin =%> + <%= hidden_field courseID => $c->{courseID} =%>
    diff --git a/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep b/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep deleted file mode 100644 index 69da3d5a95..0000000000 --- a/templates/ContentGenerator/Instructor/PGProblemEditor/format_code_form.html.ep +++ /dev/null @@ -1,33 +0,0 @@ -% last unless $c->{is_pg}; -
    -
    - <%= radio_button 'action.format_code' => 'tidyPGCode', - id => 'action_format_code_perltidy', class => 'form-check-input', checked => undef =%> - <%= label_for 'action_format_code_perltidy', class => 'form-check-label', begin =%> - <%== maketext('Reformat the code using perltidy.') =%> - <% end =%> - - - <%= maketext('Perltidy Help') %> - -
    -
    - <%= radio_button 'action.format_code' => 'convertCodeToPGML', - id => 'action_format_code_convert_PGML', class => 'form-check-input'=%> - <%= label_for 'action_format_code_convert_PGML', class => 'form-check-label', begin =%> - <%== maketext('Convert the code to PGML') =%> - <% end =%> - - - <%= maketext('PGML Conversion Help') %> - -
    -
    diff --git a/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep b/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep new file mode 100644 index 0000000000..33de2acdcf --- /dev/null +++ b/templates/ContentGenerator/Instructor/PGProblemEditor/pg_critic.html.ep @@ -0,0 +1,59 @@ +% Perl::Critic::Violation::set_format('%m at line %l, column %c.'); +% +
    +

    <%= maketext('PG Critic Violations') %>

    + % my @pgCriticViolations = grep { $_->policy =~ /^Perl::Critic::Policy::PG::/ } @$violations; + % my @perlCriticViolations = grep { $_->policy !~ /^Perl::Critic::Policy::PG::/ } @$violations; + % unless (@pgCriticViolations || @perlCriticViolations) { +

    <%= maketext('Congratulations! No PG critic violations found.') %>

    + % } + % if (@pgCriticViolations) { +

    <%= maketext('The following PG issues should be fixed:') %>

    +
      + % for (@pgCriticViolations) { +
    • +
      <%= $_->to_string %>
      +
      + <%= $_->explanation->{explanation} %> + <%== maketext( + 'See [_1].', + link_to( + ($_->policy =~ s/^Perl::Critic::Policy:://r) + => pod_viewer => { filePath => 'lib/' . ($_->policy =~ s/::/\//gr) . '.pm' }, + target => '_blank' + ) + ) =%> +
      + % if (ref($_->explanation->{sampleProblems}) eq 'ARRAY' && @{ $_->explanation->{sampleProblems} }) { +
      + <%== maketext('Related sample [plural,_1,problem]:', + scalar(@{ $_->explanation->{sampleProblems} })) %> + <%= c(map { + link_to( + $_->[0] => sample_problem_viewer => { filePath => $_->[1] }, + target => '_blank' + ) + } @{ $_->explanation->{sampleProblems} })->join(', ') =%> +
      + % } +
    • + % } +
    + % } + % if (@perlCriticViolations) { +

    <%= maketext('The following general Perl issues should be fixed:') %>

    +
      + % for (@perlCriticViolations) { +
    • +
      <%= $_->to_string %>
      +
      + See <%= link_to( + ($_->policy =~ s/^Perl::Critic::Policy:://r) => 'https://metacpan.org/pod/' . $_->policy, + target => '_blank' + ) %>. +
      +
    • + % } +
    + % } +
    diff --git a/templates/ContentGenerator/Instructor/ProblemGrader.html.ep b/templates/ContentGenerator/Instructor/ProblemGrader.html.ep index 60a6d260bf..30b857c915 100644 --- a/templates/ContentGenerator/Instructor/ProblemGrader.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemGrader.html.ep @@ -1,4 +1,4 @@ -% use WeBWorK::Utils qw(wwRound getAssetURL); +% use WeBWorK::Utils qw(wwRound getAssetURL points_stepsize round_nearest_stepsize); % require WeBWorK::PG; % % content_for js => begin @@ -8,7 +8,7 @@ <%= javascript getAssetURL($ce, 'node_modules/iframe-resizer/js/iframeResizer.min.js') =%> <%= javascript getAssetURL($ce, 'js/Essay/essay.js'), defer => undef =%> % if ($ce->{pg}{specialPGEnvironmentVars}{entryAssist} eq 'MathQuill') { - <%= javascript getAssetURL($ce, 'node_modules/mathquill/dist/mathquill.js'), defer => undef =%> + <%= javascript getAssetURL($ce, 'node_modules/@openwebwork/mathquill/dist/mathquill.js'), defer => undef =%> <%= javascript getAssetURL($ce, 'js/MathQuill/mqeditor.js'), defer => undef =%> % } elsif ($ce->{pg}{specialPGEnvironmentVars}{entryAssist} eq 'MathView') { <%= javascript getAssetURL($ce, "js/MathView/$ce->{pg}{options}{mathViewLocale}"), defer => undef =%> @@ -19,7 +19,7 @@ % content_for css => begin <%= stylesheet getAssetURL($ce, 'js/Problem/problem.css') =%> % if ($ce->{pg}{specialPGEnvironmentVars}{entryAssist} eq 'MathQuill') { - <%= stylesheet getAssetURL($ce, 'node_modules/mathquill/dist/mathquill.css') =%> + <%= stylesheet getAssetURL($ce, 'node_modules/@openwebwork/mathquill/dist/mathquill.css') =%> <%= stylesheet getAssetURL($ce, 'js/MathQuill/mqeditor.css') =%> % } elsif ($ce->{pg}{specialPGEnvironmentVars}{entryAssist} eq 'MathView') { <%= stylesheet getAssetURL($ce, 'js/MathView/mathview.css') =%> @@ -77,7 +77,7 @@ ref($_->{problem}) =~ /::ProblemVersion/ ? ( version_id => $_->{problem}->version_id, - answer_prefix => sprintf('Q%04d_', $_->{problemNumber} + 1) + answer_prefix => sprintf('Q%04d_', $_->{problem}->problem_id) ) : (), } @@ -122,11 +122,17 @@ <%= check_box 'select-all' => 'on', id => 'select-all', class => 'select-all form-check-input', data => { select_group => 'mark_correct' } =%> - <%= maketext('Score (%)') %> + % unless ($ce->{problemGraderScore} eq 'Point') { + <%= maketext('Score (%)') %> + % } + % unless ($ce->{problemGraderScore} eq 'Percent') { + <%= maketext('Points (0 - [_1])', $problem->value) %> + % } <%= maketext('Comment') %> + % my $stepSize = points_stepsize($problem->value); % for my $user (@$users) { % my $userID = $user->user_id; % @@ -138,16 +144,12 @@ % if ($versionID) { % $problemLink = $c->systemLink( % url_for('gateway_quiz', setID => "$setID,v$versionID"), - % params => { - % effectiveUser => $userID, - % currentPage => $_->{pageNumber}, - % showProblemGrader => 1 - % } + % params => { effectiveUser => $userID, currentPage => $_->{pageNumber} } % )->fragment("prob$_->{problemNumber}"); % } else { % $problemLink = $c->systemLink( % url_for('problem_detail'), - % params => { effectiveUser => $userID, showProblemGrader => 1 } + % params => { effectiveUser => $userID } % )->fragment('problem_body'); % } @@ -172,23 +174,31 @@ % my @answers = split(/\t/, $_->{past_answer}->answer_string); % % for (my $i = 0; $i <= $#answers; $i++) { - % # Color the answer if it is not an essay answer. -
    +
    % if ($answerTypes[$i] && $answerTypes[$i] eq 'essay') { % # If the answer is an essay answer then display it line by line. -
    - <%= c(split /\n/, $answers[$i])->join('
    ') =%> -
    + % my @lines = split /\n/, $answers[$i]; + % for (0 .. $#lines - 1) { + <%= $lines[$_] =%>
    + % } + <%= $lines[-1] =%> % } elsif ($answerTypes[$i] && $answerTypes[$i] eq 'Value (Formula)') { % # If its a formula then mark it as tex for MathJax. `<%= $answers[$i] %>` -
    % } else { % # If it isn't an essay or a formula then show it as text. - <%= $answers[$i] %> + % my @parts = split("⍮", $answers[$i]); + % for (0 .. $#parts - 1) { + <%= $parts[$_] =%>⍮\ + % } + <%= $parts[-1] =%> % }
    % } @@ -202,14 +212,46 @@ class => 'mark_correct form-check-input', 'aria-labelledby' => 'mark-all-correct-header' =%> - - % param("$userID.$versionID.score", undef); - <%= number_field "$userID.$versionID.score" => - wwRound(0, $_->{problem}->status * 100), - class => 'score-selector form-control form-control-sm restricted-width-col', - style => 'width:6.5rem;', min => 0, max => 100, autocomplete => 'off', - 'aria-labelledby' => 'score-header' =%> - + % unless ($ce->{problemGraderScore} eq 'Point') { + + % param("$userID.$versionID.score", undef); + <%= number_field "$userID.$versionID.score" => wwRound(0, $_->{problem}->status * 100), + id => "$userID.$versionID.score", + class => 'problem-score form-control form-control-sm restricted-width-col', + style => 'width:6.5rem;', min => 0, max => 100, step => 1, + autocomplete => 'off', 'aria-labelledby' => 'score-header' =%> + + % } + % unless ($ce->{problemGraderScore} eq 'Percent') { + % my $problemValue = ($_->{problem}->value ne '' ? $_->{problem} : $problem)->value; + % my $useUserValue = $problemValue != $problem->value; + % my $thisStepSize = $useUserValue ? points_stepsize($problemValue) : $stepSize; + + % if ($ce->{problemGraderScore} eq 'Point') { + % param("$userID.$versionID.score", wwRound(0, $_->{problem}->status * 100)); + <%= hidden_field "$userID.$versionID.score" => 0, + id => "$userID.$versionID.score" %> + % } + % param("$userID.$versionID.points", undef); + <%= number_field "$userID.$versionID.points" => round_nearest_stepsize( + $_->{problem}->status * $problemValue, $thisStepSize), + id => "$userID.$versionID.points", + class => 'problem-points form-control form-control-sm restricted-width-col', + style => 'width:6.5rem;', + min => 0, + max => $problemValue, + step => $thisStepSize, + autocomplete => 'off', + 'aria-labelledby' => $useUserValue + ? "point-label-$userID.$versionID" + : 'point-header' =%> + % if ($useUserValue) { +
    " class="fw-bold"> + <%= maketext('Points (0 - [_1])', $problemValue) =%> +
    + % } + + % } % if (defined $_->{past_answer}) { <%= text_area "$userID.$versionID.comment" => $_->{past_answer}->comment_string, @@ -227,13 +269,13 @@ % if ($problemNeedsGrading) { -
    +
    <%= maketext('Name') %> \( = \) <%= maketext('Problem has an essay answer that needs to be graded.') =%>
    % } -
    +
    <%= maketext('Latest Answers') %> \( = \) <%= maketext('Problem has a different source file than the currently rendered problem.') =%> diff --git a/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep b/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep index ae7c2c39c2..5c1991d475 100644 --- a/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemSetDetail.html.ep @@ -5,6 +5,7 @@ % % content_for css => begin <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/flatpickr.min.css') =%> + <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/themes/dark.css'), id => 'flatpickr-dark-theme' =%> <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/plugins/confirmDate/confirmDate.css') =%> % end % @@ -116,7 +117,7 @@ % } % @$userLinks = sort @$userLinks; % -
    +
    <%== maketext( @@ -151,7 +152,7 @@
    % } else { -
    +
    <%== maketext( @@ -198,7 +199,7 @@
    % % # General set information -
    +
    <%= maketext('Set Parameters') %>
    @@ -226,7 +227,7 @@ % % # Display header information % if (!@editForUser) { -
    +
    <%= maketext("Headers") %>
    % for my $headerType (@$headers) { @@ -621,7 +622,7 @@ % }
    -
    +
    <%= $c->fieldTable( $userToShow, $setID, $problemID, $globalProblems->{$problemID}, @@ -629,7 +630,7 @@ $setRecord->assignment_type ) =%>
    -
    +
    % if ($repeatFile) {
    <%= $repeatFile %>
    % } diff --git a/templates/ContentGenerator/Instructor/ProblemSetList.html.ep b/templates/ContentGenerator/Instructor/ProblemSetList.html.ep index 8f0a71aee9..46a55b57af 100644 --- a/templates/ContentGenerator/Instructor/ProblemSetList.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemSetList.html.ep @@ -2,6 +2,7 @@ % % content_for css => begin <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/flatpickr.min.css') =%> + <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/themes/dark.css'), id => 'flatpickr-dark-theme' =%> <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/plugins/confirmDate/confirmDate.css') =%> % end % diff --git a/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep b/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep index bd7ea75f91..60bff0fd19 100644 --- a/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemSetList/import_form.html.ep @@ -15,11 +15,15 @@ class => 'col-form-label col-form-label-sm col-md-auto' =%>
    <%= select_field 'action.import.source' => [ - [ maketext('Select filenames below') => '', selected => undef, disabled => undef ], + [ maketext('Select filename below') => '', selected => undef, disabled => undef ], @$setDefList ], id => 'import_source_select', class => 'form-select form-select-sm', dir => 'ltr', size => param('action.import.number') || 1, + data => { + select_multiple_text => maketext('Select filenames below'), + select_single_text => maketext('Select filename below') + }, defined param('action.import.number') && param('action.import.number') ne '1' ? (multiple => undef) : () =%> @@ -30,7 +34,7 @@ class => 'col-form-label col-form-label-sm col-md-auto' =%>
    <%= text_field 'action.import.name' => '', id => 'import_text', class => 'form-control form-control-sm', - dir => 'ltr' =%> + dir => 'ltr', data => { multiple_files_text => maketext('(taken from filenames)') } =%>
    diff --git a/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep b/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep index 1054859cb3..30bedc5b6e 100644 --- a/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemSetList/set_list_row.html.ep @@ -16,6 +16,7 @@ % % if ($c->{editMode}) { + <%= check_box apply_date_sets => $set_id, class => 'form-check-input' =%> % if ($iconClass) { @@ -71,9 +72,9 @@ % for my $field (@$fieldNames) { % next unless defined $fieldTypes->{$field}; - +
    <%= include 'ContentGenerator/Instructor/ProblemSetList/set_list_field', name => "set.$set_id.$field", value => $set->$field, type => $fieldTypes->{$field} =%> - +
    % } diff --git a/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep b/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep index 6717411106..bb220e0a2c 100644 --- a/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep +++ b/templates/ContentGenerator/Instructor/ProblemSetList/set_list_table.html.ep @@ -10,6 +10,50 @@ % answer_date => maketext('Answer Date') % ); % +% if ($c->{editMode}) { +
    + +
    + +
    + +
    + <%= text_field 'common-date' => '', + id => 'common-date', class => 'form-control', + data => { + input => undef, + done_text => maketext('Done'), + today_text => maketext('Today'), + now_text => maketext('Now'), + locale => $ce->{language}, + timezone => $ce->{siteDefaults}{timezone} + } =%> + + + +
    +
    + +
    +
    +
    + <%= maketext('Please choose a set date type.') %> +
    +
    + <%= maketext('Please select a date.') %> +
    +% }
    <%= maketext('Please select at least one set.') %>
    @@ -21,22 +65,20 @@ % - % if (!$c->{editMode}) { - - <%= label_for 'select-all', begin =%> - <%= check_box 'select-all' => '', id => 'select-all', - class => 'select-all form-check-input set-id-tooltip', - 'aria-label' => maketext('Select all sets'), - data => { - select_group => 'selected_sets', - bs_toggle => 'tooltip', - bs_placement => 'right', - bs_title => maketext('Select all sets') - } =%> - - <% end =%> - - % } + + <%= label_for 'select-all', begin =%> + <%= check_box 'select-all' => '', id => 'select-all', + class => 'select-all form-check-input set-id-tooltip', + 'aria-label' => maketext('Select all sets'), + data => { + select_group => $c->{editMode} ? 'apply_date_sets' : 'selected_sets', + bs_toggle => 'tooltip', + bs_placement => 'right', + bs_title => maketext('Select all sets') + } =%> + + <% end =%> + % for (@$fieldNames) { % if (!$c->{editMode} && $sortableFields->{$_}) { diff --git a/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep b/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep index 87cfaf1353..c1af9c734e 100644 --- a/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep +++ b/templates/ContentGenerator/Instructor/SetMaker/problem_row.html.ep @@ -46,7 +46,7 @@ % if ($stats->{students_attempted}) { % content_for "global-problem-stats-$cnt" => begin
    - begin
    - > + $ce->{sessionTimeout} ? 'class="table-rule"' : '' %>> % # Show the problem seed for instructors. % if ($isInstructor) { @@ -47,9 +46,13 @@ % % # Color the answer if the user is an instructor, there is an answer, % # there is a score, and it is not an essay question. - class="px-3 <%== $answerType eq 'essay' ? 'essay' : '' %>"> + % if ($answer eq '') { <%= maketext('empty') %> % } else { diff --git a/templates/ContentGenerator/Instructor/Stats.html.ep b/templates/ContentGenerator/Instructor/Stats.html.ep index 19c234d292..f1ee404562 100644 --- a/templates/ContentGenerator/Instructor/Stats.html.ep +++ b/templates/ContentGenerator/Instructor/Stats.html.ep @@ -1,20 +1,22 @@ % use WeBWorK::Utils qw(getAssetURL); +% use WeBWorK::Utils::Sets qw(format_set_name_display); % % unless ($authz->hasPermissions(param('user'), 'access_instructor_tools')) {
    <%= maketext('You are not authorized to access instructor tools') %>
    % last; % } % -% if (current_route eq 'instructor_user_statistics') { - % # Stats and StudentProgress share this template. - <%= include 'ContentGenerator/Instructor/Stats/student_stats' =%> -% } elsif (current_route eq 'instructor_set_statistics') { +% if (current_route eq 'instructor_set_statistics') { <%= $c->set_stats =%> % } elsif (current_route eq 'instructor_problem_statistics') { <%= $c->problem_stats =%> % } else { - % # Stats and StudentProgress share this template also. - <%= include 'ContentGenerator/Instructor/Stats/index', - set_header => maketext('View statistics by set'), - student_header => maketext('View statistics by student') =%> +
      + % for ($db->listGlobalSetsWhere({}, 'set_id')) { +
    • + <%= link_to format_set_name_display($_->[0]) => + $c->systemLink(url_for("instructor_set_statistics", setID => $_->[0])) =%> +
    • + % } +
    % } diff --git a/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep b/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep index a0aea45c9f..4b8c7c792c 100644 --- a/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep +++ b/templates/ContentGenerator/Instructor/Stats/problem_menu.html.ep @@ -10,7 +10,7 @@ url_for('instructor_set_statistics'), params => param('filter') ? { filter => param('filter') } : {} ), - class => 'dropdown-item', $c->{prettyID} ? () : (style => 'background-color: #8F8') =%> + class => join(' ', 'dropdown-item', $c->{prettyID} ? () : 'active') =%> % for (@$problems) { % my $probID = @@ -22,8 +22,7 @@ url_for('instructor_problem_statistics', problemID => $_->problem_id), params => param('filter') ? { filter => param('filter') } : {} ), - class => 'dropdown-item', - $probID eq ($c->{prettyID} // '') ? (style => 'background-color: #8F8') : () =%> + class => join(' ', 'dropdown-item', $probID eq ($c->{prettyID} // '') ? 'active' : ()) =%> % }
diff --git a/templates/ContentGenerator/Instructor/Stats/siblings.html.ep b/templates/ContentGenerator/Instructor/Stats/siblings.html.ep index 68827f455e..41bd165a6a 100644 --- a/templates/ContentGenerator/Instructor/Stats/siblings.html.ep +++ b/templates/ContentGenerator/Instructor/Stats/siblings.html.ep @@ -1,6 +1,3 @@ -% # Note that this template is used by both WeBWorK::ContentGenerator::Instructor::Stats and -% # WeBWorK::ContentGenerator::Instructor::StudentProgress. -% % use WeBWorK::Utils::JITAR qw(jitar_id_to_seq); % use WeBWorK::Utils::Sets qw(format_set_name_display); % @@ -9,24 +6,8 @@ % } %
-

<%= $header %>

- % if (current_route =~ /^instructor_user_/) { - - % } elsif (current_route eq 'instructor_problem_statistics') { +

<%= maketext('Statistics') %>

+ % if (current_route eq 'instructor_problem_statistics') { % } else { - + % # Shared with StudentProgress siblings. + <%= include 'ContentGenerator/Instructor/Stats/siblings_set_list', + set_link_route => 'instructor_set_statistics' =%> % }
diff --git a/templates/ContentGenerator/Instructor/Stats/siblings_set_list.html.ep b/templates/ContentGenerator/Instructor/Stats/siblings_set_list.html.ep new file mode 100644 index 0000000000..e69605b056 --- /dev/null +++ b/templates/ContentGenerator/Instructor/Stats/siblings_set_list.html.ep @@ -0,0 +1,18 @@ +% # This is shared between Stats and StudentProgress siblings page to list all sets. +% + diff --git a/templates/ContentGenerator/Instructor/Stats/student_filter_menu.html.ep b/templates/ContentGenerator/Instructor/Stats/student_filter_menu.html.ep index 98ba7f083e..12308273d6 100644 --- a/templates/ContentGenerator/Instructor/Stats/student_filter_menu.html.ep +++ b/templates/ContentGenerator/Instructor/Stats/student_filter_menu.html.ep @@ -13,7 +13,7 @@ % for (@$filters) {
  • <%= link_to $_->[0] => $c->systemLink(url_for, params => { %$params, filter => $_->[1] }), - $_->[1] eq $filter ? (style => 'background-color: #8F8') : (), class => 'dropdown-item' =%> + class => join(' ', 'dropdown-item', $_->[1] eq $filter ? 'active' : ()) =%>
  • % } diff --git a/templates/ContentGenerator/Instructor/StudentProgress.html.ep b/templates/ContentGenerator/Instructor/StudentProgress.html.ep index d135d8e5c5..4b02941e92 100644 --- a/templates/ContentGenerator/Instructor/StudentProgress.html.ep +++ b/templates/ContentGenerator/Instructor/StudentProgress.html.ep @@ -4,13 +4,9 @@ % } % % if (current_route eq 'instructor_user_progress') { - % # Stats and StudentProgress share this template. - <%= include 'ContentGenerator/Instructor/Stats/student_stats' =%> + <%= include 'ContentGenerator/Instructor/StudentProgress/student_progress' =%> % } elsif (current_route eq 'instructor_set_progress') { <%= $c->displaySets =%> % } else { - % # Stats and StudentProgress share this template also. - <%= include 'ContentGenerator/Instructor/Stats/index', - set_header => maketext('View student progress by set'), - student_header => maketext('View student progress by student') =%> + <%= include 'ContentGenerator/Instructor/StudentProgress/index' =%> % } diff --git a/templates/ContentGenerator/Instructor/Stats/index.html.ep b/templates/ContentGenerator/Instructor/StudentProgress/index.html.ep similarity index 59% rename from templates/ContentGenerator/Instructor/Stats/index.html.ep rename to templates/ContentGenerator/Instructor/StudentProgress/index.html.ep index 96016b1bfa..142abaa394 100644 --- a/templates/ContentGenerator/Instructor/Stats/index.html.ep +++ b/templates/ContentGenerator/Instructor/StudentProgress/index.html.ep @@ -1,22 +1,17 @@ -% # Note that this template is used by both WeBWorK::ContentGenerator::Instructor::Stats and -% # WeBWorK::ContentGenerator::Instructor::StudentProgress. -% % use WeBWorK::Utils::Sets qw(format_set_name_display); % -% my $type = current_route =~ s/instructor_//r; -% % stash->{footerWidthClass} = 'col-lg-10 col-sm-12'; %
    -

    <%= $set_header %>

    +

    <%= maketext('View student progress by set') %>

      % for ($db->listGlobalSetsWhere({}, 'set_id')) {
    • <%= link_to format_set_name_display($_->[0]) => - $c->systemLink(url_for("instructor_set_$type", setID => $_->[0])) =%> + $c->systemLink(url_for("instructor_set_progress", setID => $_->[0])) =%>
    • % }
    @@ -26,12 +21,12 @@
    -

    <%= $student_header %>

    +

    <%= maketext('View student progress by student') %>

      % for (@{ $c->{student_records} }) {
    • <%= link_to $_->last_name . ', ' . $_->first_name . ' (' . $_->user_id . ')' => - $c->systemLink(url_for("instructor_user_$type", userID => $_->user_id)) =%> + $c->systemLink(url_for("instructor_user_progress", userID => $_->user_id)) =%>
    • % }
    diff --git a/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep b/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep index e1eb38b734..e155421871 100644 --- a/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep +++ b/templates/ContentGenerator/Instructor/StudentProgress/set_progress.html.ep @@ -16,6 +16,7 @@ % show_section => $showColumns->{section}, % show_recitation => $showColumns->{recit}, % show_login => $showColumns->{login}, + % returning => 1 % ) % : () % ); diff --git a/templates/ContentGenerator/Instructor/StudentProgress/siblings.html.ep b/templates/ContentGenerator/Instructor/StudentProgress/siblings.html.ep new file mode 100644 index 0000000000..8d77a079f9 --- /dev/null +++ b/templates/ContentGenerator/Instructor/StudentProgress/siblings.html.ep @@ -0,0 +1,30 @@ +% use WeBWorK::Utils::Sets qw(format_set_name_display); +% +% unless ($authz->hasPermissions(param('user'), 'access_instructor_tools')) { + % last; +% } +% +
    +

    <%= maketext('Student Progress') %>

    + % if (current_route eq 'instructor_user_progress') { + + % } else { + % # Shared with Stats siblings. + <%= include 'ContentGenerator/Instructor/Stats/siblings_set_list', + set_link_route => 'instructor_set_progress' =%> + % } +
    diff --git a/templates/ContentGenerator/Instructor/Stats/student_stats.html.ep b/templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep similarity index 85% rename from templates/ContentGenerator/Instructor/Stats/student_stats.html.ep rename to templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep index 6f50080c39..913d3e410f 100644 --- a/templates/ContentGenerator/Instructor/Stats/student_stats.html.ep +++ b/templates/ContentGenerator/Instructor/StudentProgress/student_progress.html.ep @@ -1,6 +1,3 @@ -% # Note that this template is used by both WeBWorK::ContentGenerator::Instructor::Stats and -% # WeBWorK::ContentGenerator::Instructor::StudentProgress. -% % use WeBWorK::ContentGenerator::Grades; % % my $studentRecord = $db->getUser($c->{studentID}); diff --git a/templates/ContentGenerator/Instructor/UserDetail.html.ep b/templates/ContentGenerator/Instructor/UserDetail.html.ep index 1ef3720df6..4e4c0447fd 100644 --- a/templates/ContentGenerator/Instructor/UserDetail.html.ep +++ b/templates/ContentGenerator/Instructor/UserDetail.html.ep @@ -2,6 +2,7 @@ % % content_for css => begin <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/flatpickr.min.css') =%> + <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/themes/dark.css'), id => 'flatpickr-dark-theme' =%> <%= stylesheet getAssetURL($ce, 'node_modules/flatpickr/dist/plugins/confirmDate/confirmDate.css') =%> % end % diff --git a/templates/ContentGenerator/Instructor/UserList.html.ep b/templates/ContentGenerator/Instructor/UserList.html.ep index 1f441230e2..424b0c2d9b 100644 --- a/templates/ContentGenerator/Instructor/UserList.html.ep +++ b/templates/ContentGenerator/Instructor/UserList.html.ep @@ -59,10 +59,15 @@ <%= link_to maketext($formTitles->{$actionID}) => "#$actionID", class => "nav-link action-link$active$disabled", id => "$actionID-tab", - data => { action => $actionID, bs_toggle => 'tab', bs_target => "#$actionID" }, + data => { + action => $actionID, + bs_toggle => 'tab', + bs_target => "#$actionID", + $actionID eq 'cancel_edit' ? (no_validate => 1) : () + }, role => 'tab', 'aria-controls' => $actionID, - 'aria-selected' => $active ? 'true' : 'false' =%> + 'aria-selected' => $active ? 'true' : 'false', =%> % end % content_for 'tab-content' => begin diff --git a/templates/ContentGenerator/Instructor/UserList/user_list.html.ep b/templates/ContentGenerator/Instructor/UserList/user_list.html.ep index 3abe3e2bc6..4e99bb6e7a 100644 --- a/templates/ContentGenerator/Instructor/UserList/user_list.html.ep +++ b/templates/ContentGenerator/Instructor/UserList/user_list.html.ep @@ -52,6 +52,7 @@ <%= include 'ContentGenerator/Instructor/UserList/sort_button', field => 'status' =%>
    + <%= maketext('Accommodation Time Factor') %>
    <%= link_to maketext('Section') => '#', class => 'sort-header', diff --git a/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep b/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep index c0a842ee0a..e7e3831480 100644 --- a/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep +++ b/templates/ContentGenerator/Instructor/UserList/user_list_field.html.ep @@ -1,12 +1,13 @@ % my $fieldName = 'user.' . $user->user_id . '.' . $field; % my $properties = $fieldProperties->{$field}; % -% if ($properties->{type} eq 'text') { +% if ($properties->{type} eq 'text' || $properties->{type} eq 'number') { % my $value = $user->$field; % if ($c->{editMode}) { - <%= text_field $fieldName => $value, id => $fieldName . '_id', size => $properties->{size}, + % my $field_method = "$properties->{type}_field"; + <%= $c->$field_method($fieldName => $value, id => $fieldName . '_id', %{$properties->{attributes} // {}}, class => 'form-control form-control-sm d-inline w-auto', - 'aria-labelledby' => ($fieldName =~ s/^.*\.([^.]*)$/$1/r) . '_header' =%> + 'aria-labelledby' => ($fieldName =~ s/^.*\.([^.]*)$/$1/r) . '_header') =%> % } else { % if ($field eq 'email_address') { % if ($value =~ /\S/) { diff --git a/templates/ContentGenerator/Problem.html.ep b/templates/ContentGenerator/Problem.html.ep index 83b7773faa..d79cbb165d 100644 --- a/templates/ContentGenerator/Problem.html.ep +++ b/templates/ContentGenerator/Problem.html.ep @@ -65,29 +65,47 @@ % stash->{footerWidthClass} = 'col-lg-10'; % <%== $c->post_header_text =%> +% if ($c->{pg}{warnings} || @{ $c->{pgwarning} // [] }) { +
    +
    + <%== maketext('Warning: There may be something wrong with this question. ' + . 'Please inform your instructor including the warning messages below.') =%> +
    +
    +% } +% if (ref $c->{pg}{debug_messages} eq 'ARRAY' && @{ $c->{pg}{debug_messages} }) { +
    +
    <%== maketext('Debugging information is shown below.') %>
    +
    +% }
    <%= $c->output_custom_edit_message %>
    <%= $c->output_summary %>
    <%= $c->output_achievement_message %>
    <%= $c->output_comments %>
    -
    <%= $c->output_grader %>
    +% if ($c->{pg}{render_fail}) { +
    +
    +

    <%= maketext('PG question failed to render') %>

    +

    <%= maketext('Processing of this PG problem was not completed. Probably because of a ' + . 'syntax error. The translator died prematurely and no PG warning messages were transmitted.') %>

    +
    +
    +% }
    <%= form_for current_route, method => 'POST', name => 'problemMainForm', id => 'problemMainForm', class => 'problem-main-form', begin =%> <%= $c->hidden_authen_fields =%> <%= hidden_field(startTime => param('startTime') || time) =%> - <% if ($c->can('output_hidden_info')) { - <%= $c->output_hidden_info =%> - % } -
    -
    output_problem_lang_and_dir %>> - <%= $c->output_problem_body =%> -
    - <%= $c->output_message =%> + <%= hidden_field(courseID => $c->ce->{courseName}) =%> +
    output_problem_lang_and_dir %>> + <%= $c->output_problem_body =%>
    + <%= $c->output_message =%> + <%= $c->output_grader %> <%= $c->output_checkboxes %>
    <%= $c->output_submit_buttons %>
    <%= include 'ContentGenerator/Problem/instructor_buttons' %> @@ -100,3 +118,7 @@ <%= $c->output_past_answer_button =%> <%= $c->output_email_instructor =%>
    +<%= include 'ContentGenerator/Base/problem_warning_and_debug_output', + warnings => $c->{pg}{warnings}, + warning_messages => ref $c->{pg}{warning_messages} eq 'ARRAY' ? $c->{pg}{warning_messages} : [], + debug_messages => ref $c->{pg}{debug_messages} eq 'ARRAY' ? $c->{pg}{debug_messages} : [] =%> diff --git a/templates/ContentGenerator/Problem/instructor_buttons.html.ep b/templates/ContentGenerator/Problem/instructor_buttons.html.ep index 1462957186..c336324f87 100644 --- a/templates/ContentGenerator/Problem/instructor_buttons.html.ep +++ b/templates/ContentGenerator/Problem/instructor_buttons.html.ep @@ -1,18 +1,8 @@ % last unless $authz->hasPermissions(param('user'), 'access_instructor_tools'); % -
    - % if ($c->{can}{showCorrectAnswers}) { +% if ($c->{can}{showCorrectAnswers}) { +
    <%= submit_button maketext('Show Correct Answers'), name => 'showCorrectAnswers', class => 'btn btn-primary mb-1' =%> - % } - % if ($c->{can}{showProblemGrader} && !$c->{will}{showMeAnother}) { - % if ($c->{will}{showProblemGrader}) { - <%= submit_button maketext('Hide Problem Grader'), name => 'hideProblemGrader', - class => 'btn btn-primary mb-1' =%> - <%= hidden_field showProblemGrader => 1 =%> - % } else { - <%= submit_button maketext('Show Problem Grader'), name => 'showProblemGrader', - class => 'btn btn-primary mb-1' =%> - % } - % } -
    +
    +% } diff --git a/templates/ContentGenerator/Problem/student_nav.html.ep b/templates/ContentGenerator/Problem/student_nav.html.ep deleted file mode 100644 index 5d4c09c79c..0000000000 --- a/templates/ContentGenerator/Problem/student_nav.html.ep +++ /dev/null @@ -1,103 +0,0 @@ -% # Cap the number of students shown to at most 200. -% my $numAfter = $#$userRecords - $currentUserIndex; -% my $numBefore = 200 - ($numAfter < 100 ? $numAfter : 100); -% my $minStudentIndex = $currentUserIndex < $numBefore ? 0 : $currentUserIndex - $numBefore; -% my $maxStudentIndex = $minStudentIndex + 200 < $#$userRecords ? $minStudentIndex + 200 : $#$userRecords; -% -
    -
    - % if ($prevUser) { - <%= link_to $c->systemLink( - $problemPage, - params => { - effectiveUser => $prevUser->user_id, - showProblemGrader => $c->{will}{showProblemGrader}, - $filter ? (studentNavFilter => $filter) : () - } - ), - data => { bs_toggle => 'tooltip', bs_placement => 'top' }, - title => $prevUser->{displayName}, - class => 'btn btn-primary student-nav-button', - begin =%> - - <% end =%> - % } else { - - % } -
    - <%= link_to $userRecords->[$currentUserIndex]{displayName} => '#', - id => 'studentSelector', class => 'btn btn-primary dropdown-toggle', role => 'button', - data => { bs_toggle => 'dropdown' }, 'aria-expanded' => 'false' =%> - -
    - % if ($nextUser) { - <%= link_to $c->systemLink( - $problemPage, - params => { - effectiveUser => $nextUser->user_id, - showProblemGrader => $c->{will}{showProblemGrader}, - $filter ? (studentNavFilter => $filter) : () - } - ), - data => { bs_toggle => 'tooltip', bs_placement => 'top' }, - title => $nextUser->{displayName}, - class => 'btn btn-primary student-nav-button', - begin =%> - - <%= end %> - % } else { - - % } -
    - % # Create a section/recitation "filter by" dropdown if there are sections or recitations. - % if (keys %$filters) { -
    - <%= link_to $filter ? $filters->{$filter}[0] : maketext('Showing all students') => '#', - id => 'studentSelectorFilter', class => 'btn btn-primary dropdown-toggle', role => 'button', - data => { bs_toggle => 'dropdown' }, 'aria-expanded' => 'false' =%> - -
    - % } -
    diff --git a/templates/ContentGenerator/ProblemSet.html.ep b/templates/ContentGenerator/ProblemSet.html.ep index 62eb24f808..c6935a2c9e 100644 --- a/templates/ContentGenerator/ProblemSet.html.ep +++ b/templates/ContentGenerator/ProblemSet.html.ep @@ -1,28 +1,56 @@ % use WeBWorK::Utils::DateTime qw(before between); % -% if ( - % $c->{invalidSet} - % && ($c->{invalidSet} !~ /^Client ip address .* is not in the list of addresses/ - % || $authz->{merged_set}->assignment_type !~ /gateway/) - % ) -% { -
    -

    - <%= maketext( - 'The selected problem set ([_1]) is not a valid set for [_2].', - stash('setID'), param('effectiveUser') - ) =%> -

    -

    <%= $c->{invalidSet} %>

    -
    - % last; +% if ($c->{invalidSet}) { + % # If $c->{viewSetCheck} is set, show some set information. + % if ($c->{viewSetCheck}) { + % # Do nothing unless the set is hidden, then show a warning message instead of an error. + % if ($c->{viewSetCheck} eq 'hidden') { +
    +

    <%= $c->{invalidSet} %>

    +
    + % last; + % } + % } else { +
    +

    + <%= maketext( + 'The selected problem set ([_1]) is not a valid set for [_2].', + stash('setID'), param('effectiveUser') + ) =%> +

    +

    <%= $c->{invalidSet} %>

    +
    + % last; + % } % } % % my $set = $c->{set}; % +% # Show the set description if it is not empty. +% if ($set->description =~ /\S/) { +
    <%= $set->description %>
    +% } +% % # Stats message displays the current status of the set and states the next important date. <%= include 'ContentGenerator/Base/set_status', set => $set =%> % +% # Show any restricted messages. +% if ($c->{viewSetCheck} && $c->{viewSetCheck} eq 'restricted') { +
    <%== $c->{invalidSet} %>
    +% } elsif ($c->{restrictedSetMessages}) { +
    + % for (0 .. $#{ $c->{restrictedSetMessages} }) { + % my $class = $_ == $#{ $c->{restrictedSetMessages} } ? ' class="mb-0"' : ''; + ><%== $c->{restrictedSetMessages}->[$_] %>

    + % } +
    +% } +% <%= include 'ContentGenerator/ProblemSet/auxiliary_tools' =%> % -<%= $set->assignment_type =~ /gateway/ ? $c->gateway_body : $c->problem_list =%> +% # Always show test versions, but only show problem list if the set has no restrictions. +% if ($set->assignment_type =~ /gateway/) { + <%= $c->gateway_body =%> +% } elsif (!$c->{viewSetCheck}) { + <%= $c->problem_list =%> +% } diff --git a/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep b/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep index 3fdbfcf5d6..34a70e4385 100644 --- a/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep +++ b/templates/ContentGenerator/ProblemSet/auxiliary_tools.html.ep @@ -1,3 +1,22 @@ +% # If viewing a restricted set, only show the email instructor button. +% if ($c->{viewSetCheck}) { +
    +
    + <%= $c->feedbackMacro( + route => current_route, + set => $c->{set}->set_id, + problem => '', + displayMode => $c->{displayMode}, + showOldAnswers => '', + showCorrectAnswers => '', + showHints => '', + showSolutions => '', + ) =%> +
    +
    + % last; +% } +%
    <%= $c->feedbackMacro( @@ -34,6 +53,7 @@ % my ($item, $form) = @$_;
    <%= $item->name %>
    + % if (param('user') eq param('effectiveUser')) { <%= form_for current_route, method => 'POST', name => 'use_reward', begin =%> <%= hidden_field 'use_achievement_item_id' => $item->id %> <%= $form %> @@ -43,6 +63,17 @@ value="<%= maketext('Use [_1]', $item->remaining_title($c)) %>"> % } <%= end =%> + % } else { + <%= $form %> + + + + % }
    % } @@ -53,13 +84,6 @@
    - % } elsif (param('user') ne param('effectiveUser')) { - - - % } else { diff --git a/templates/ContentGenerator/ProblemSet/version_list.html.ep b/templates/ContentGenerator/ProblemSet/version_list.html.ep index 0d332c749e..fb521457dd 100644 --- a/templates/ContentGenerator/ProblemSet/version_list.html.ep +++ b/templates/ContentGenerator/ProblemSet/version_list.html.ep @@ -8,14 +8,11 @@ % % my $routeName = $set->assignment_type =~ /proctored/ ? 'proctored_gateway_quiz' : 'gateway_quiz'; % -% if ($c->{invalidSet}) { - % # If this is an invalidSet it is because the IP address is not allowed to access the set. - % # Display that message here. Note that the set is valid so the set versions can still be displayed, - % # but the "Start New Test" or "Continue Test" buttons should not be. -
    <%= $c->{invalidSet} %>
    +% if ($c->{viewSetCheck}) { + % # If we are viewing a restricted set, then only show existing set versions and no other information. % } elsif ($continueVersion) { % # Display information about the current test and a continue open test button. - % if ($timeLimit > 0) { + % if ($continueVersion->version_time_limit > 0) { % if ($timeNow >= $continueVersion->due_date) { % # If the currently open test is in the grace period, display a mesage stating this.
    @@ -249,6 +246,6 @@ % } else { <%= $version_list->() =%> % } -% } else { +% } elsif (!$c->{viewSetCheck}) {

    <%= maketext('No versions of this test have been taken.') %>

    % } diff --git a/templates/ContentGenerator/ProblemSets.html.ep b/templates/ContentGenerator/ProblemSets.html.ep index e01a4dee45..d8e49ce887 100644 --- a/templates/ContentGenerator/ProblemSets.html.ep +++ b/templates/ContentGenerator/ProblemSets.html.ep @@ -5,10 +5,14 @@ % unless ($authz->hasPermissions(param('user'), 'navigation_allowed')) {
    - <%== maketext('You must access assignments from your Course Management System ([_1]).', - $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} - ? link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) - : $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name}) =%> + % if ($ce->{LTI}) { + <%== maketext('You must access assignments from your Course Management System ([_1]).', + $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url} + ? link_to($ce->{LTI}{ $ce->{LTIVersion} }{LMS_name} => $ce->{LTI}{ $ce->{LTIVersion} }{LMS_url}) + : $ce->{LTI}{ $ce->{LTIVersion} }{LMS_name}) =%> + % } else { + <%= maketext('You do not have permission to list assignments in this course.') %> + % }
    % last; diff --git a/templates/ContentGenerator/ProblemSets/set_list_row.html.ep b/templates/ContentGenerator/ProblemSets/set_list_row.html.ep index 24cbc8cc3e..9e9852a58f 100644 --- a/templates/ContentGenerator/ProblemSets/set_list_row.html.ep +++ b/templates/ContentGenerator/ProblemSets/set_list_row.html.ep @@ -16,17 +16,16 @@
    - % if ($link_is_active) { - <%= link_to $display_name => $c->systemLink(url_for('problem_list', setID => $set->set_id)), - class => 'fw-bold set-id-tooltip', - data => { bs_toggle => 'tooltip', bs_placement => 'right', bs_title => $set->description } - =%> - % } else { - - <%= $display_name =%> - - <%= $set->description %> + <%= link_to $display_name => $c->systemLink(url_for('problem_list', setID => $set->set_id)), + class => 'fw-bold' + =%> + % if ($set->description =~ /\S/) { + + + <%= maketext('Assignment Description') =%> + % }
    <%= $status_msg %>
    diff --git a/templates/ContentGenerator/SampleProblemViewer.html.ep b/templates/ContentGenerator/SampleProblemViewer.html.ep index e8d24daf4f..1729c3fbc8 100644 --- a/templates/ContentGenerator/SampleProblemViewer.html.ep +++ b/templates/ContentGenerator/SampleProblemViewer.html.ep @@ -14,7 +14,14 @@ <%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'node_modules/minisearch/dist/umd/index.js' }), defer => undef =%> - + <%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'js/SampleProblemViewer/documentation-search.js' }), defer => undef =%> @@ -83,7 +90,9 @@ <%= link_to 'sample_problem_viewer', { filePath => 'macros' }, class => 'list-group-item list-group-item-action', begin =%> <%= maketext('Sample Problems by Macro') %> -
    <%= maketext('For many macros, this lists all sample problems used by the macro.') %>
    +
    + <%= maketext('For many macros, this lists all sample problems that use the macro.') %> +
    % end
    diff --git a/templates/HTML/SingleProblemGrader/grader.html.ep b/templates/HTML/SingleProblemGrader/grader.html.ep index b5caad01ba..8405eab134 100644 --- a/templates/HTML/SingleProblemGrader/grader.html.ep +++ b/templates/HTML/SingleProblemGrader/grader.html.ep @@ -1,4 +1,4 @@ -% use WeBWorK::Utils 'wwRound'; +% use WeBWorK::Utils qw(wwRound points_stepsize round_nearest_stepsize); % % if (!stash->{jsInserted}) { % stash->{jsInserted} = 1; @@ -7,8 +7,8 @@ % end % } % -
    -
    +
    % my $currentScore = 0; % my $rawCurrentScore = 0; @@ -82,28 +82,11 @@ % % # Total point value. Show only if configured to. % unless ($ce->{problemGraderScore} eq 'Percent') { - % # Compute a reasonable step size based on point value. - % # First use some preset nice values, then only use whole - % # point values, such that the step size >= 1% of total. - % my $stepSize; - % if ($grader->{problem_value} == 1) { - % $stepSize = 0.01; - % } elsif ($grader->{problem_value} <= 5) { - % $stepSize = 0.05; - % } elsif ($grader->{problem_value} <= 10) { - % $stepSize = 0.1; - % } elsif ($grader->{problem_value} <= 25) { - % $stepSize = 0.25; - % } elsif ($grader->{problem_value} <= 50) { - % $stepSize = 0.5; - % } else { - % $stepSize = int(($grader->{problem_value} - 1) / 100) + 1; - % } - % # Round point score to the nearest $stepSize. + % my $stepSize = points_stepsize($grader->{problem_value}); % my $recordedPoints = - % wwRound(2, wwRound(0, $grader->{recorded_score} * $grader->{problem_value} / $stepSize) * $stepSize); + % round_nearest_stepsize($grader->{recorded_score} * $grader->{problem_value}, $stepSize); % my $currentPoints = - % wwRound(2, wwRound(0, $rawCurrentScore / 100 * $grader->{problem_value} / $stepSize) * $stepSize); + % round_nearest_stepsize($rawCurrentScore / 100 * $grader->{problem_value}, $stepSize); % param('grader-problem-points', $recordedPoints);
    <%= label_for "score_problem$grader->{problem_id}_points", @@ -271,7 +254,8 @@ data-set-id="<%= $grader->{set_id} %>" data-version-id="<%= $grader->{version_id} %>" data-problem-id="<%= $grader->{problem_id} %>" - data-past-answer-id="<%= $grader->{past_answer_id} %>"> + data-past-answer-id="<%= $grader->{past_answer_id} %>" + data-save-sub-status="<%= $grader->{save_sub_status} %>"> <%= maketext('Save') =%>
    @@ -280,5 +264,4 @@
    -
    diff --git a/templates/HTML/StudentNav/student_nav.html.ep b/templates/HTML/StudentNav/student_nav.html.ep new file mode 100644 index 0000000000..10070e7512 --- /dev/null +++ b/templates/HTML/StudentNav/student_nav.html.ep @@ -0,0 +1,96 @@ +% # Cap the number of students shown to at most 200. +% my $numAfter = $#$userRecords - $currentUserIndex; +% my $numBefore = 200 - ($numAfter < 100 ? $numAfter : 100); +% my $minStudentIndex = $currentUserIndex < $numBefore ? 0 : $currentUserIndex - $numBefore; +% my $maxStudentIndex = $minStudentIndex + 200 < $#$userRecords ? $minStudentIndex + 200 : $#$userRecords; +% +
    +
    + % if ($eUserID ne $userID) { + % if ($prevUser) { + <%= link_to $c->systemLink( + url_for, + params => { effectiveUser => $prevUser->user_id, $filter ? (studentNavFilter => $filter) : () } + ), + data => { bs_toggle => 'tooltip', bs_placement => 'top' }, + title => $prevUser->{displayName}, + class => 'btn btn-primary student-nav-button', + begin =%> + + <% end =%> + % } else { + + % } + % } +
    + % my $buttonName = + % $eUserID ne $userID + % ? $userRecords->[$currentUserIndex]{displayName} + % : maketext('Select Student to Act As'); + <%= link_to $buttonName => '#', id => 'studentSelector', class => 'btn btn-primary dropdown-toggle', + role => 'button', data => { bs_toggle => 'dropdown' }, 'aria-expanded' => 'false' =%> + +
    + % if ($eUserID ne $userID) { + % if ($nextUser) { + <%= link_to $c->systemLink( + url_for, + params => { + effectiveUser => $nextUser->user_id, + $filter ? (studentNavFilter => $filter) : () + } + ), + data => { bs_toggle => 'tooltip', bs_placement => 'top' }, + title => $nextUser->{displayName}, + class => 'btn btn-primary student-nav-button', + begin =%> + + <%= end %> + % } else { + + % } + % } +
    + % # Create a section/recitation "filter by" dropdown if there are sections or recitations. + % if (keys %$filters) { +
    + <%= link_to $filter ? $filters->{$filter}[0] : maketext('Showing all students') => '#', + id => 'studentSelectorFilter', class => 'btn btn-primary dropdown-toggle', role => 'button', + data => { bs_toggle => 'dropdown' }, 'aria-expanded' => 'false' =%> + +
    + % } +
    diff --git a/templates/HelpFiles/InstructorFileManager.html.ep b/templates/HelpFiles/InstructorFileManager.html.ep index d6f0ddfe0b..95daeebb66 100644 --- a/templates/HelpFiles/InstructorFileManager.html.ep +++ b/templates/HelpFiles/InstructorFileManager.html.ep @@ -34,7 +34,7 @@ . 'and are created when exporting a problem set from the "Sets Manager". Each set definition file ' . 'contains a list of problems used and the dates and times. These definitions can be imported into the ' . 'current course.', - 'href="https://webwork.maa.org/wiki/Set_Definition_Files" target="Webworkdocs"') =%> + 'href="https://wiki.openwebwork.org/wiki/Set_Definition_Files" target="Webworkdocs"') =%>
    <%= maketext('Class list (".lst") files') %>
    @@ -44,7 +44,7 @@ . 'ClassList files can be prepared using a spreadsheet and then saved as [_3] (comma separated values) ' . 'text files. However, to access as a classlist file, the file suffix needs to be changed to [_4], ' . 'which can be done with the "Rename" button.', - 'href="http://webwork.maa.org/wiki/Classlist_Files#Format_of_classlist_files" target="Webworkdocs"', + 'href="https://wiki.openwebwork.org/wiki/Classlist_Files#Format_of_classlist_files" target="Webworkdocs"', 'demoCourse.lst', '.csv', '.lst') =%>
    <%= maketext('Scoring (".csv") files') %>
    diff --git a/templates/HelpFiles/InstructorPGProblemEditor.html.ep b/templates/HelpFiles/InstructorPGProblemEditor.html.ep index 8715387509..87f966708e 100644 --- a/templates/HelpFiles/InstructorPGProblemEditor.html.ep +++ b/templates/HelpFiles/InstructorPGProblemEditor.html.ep @@ -11,13 +11,12 @@
    - - <%= maketext('Problem Techniques') =%> - + <%= link_to maketext('Sample Problems') => url_for('sample_problem_index'), + target => 'techniques_window' =%>
    -
    <%= maketext('This links to a list of problem authoring techniques.') %>
    +
    <%= maketext('Sample problem code with documentation.') %>
    - + <%= maketext('Math Objects') %>
    @@ -28,29 +27,16 @@ . 'macro files themselves.') =%>
    - % if (-e "$ce->{courseDirs}{templates}/PGMLLab/PGML-lab.pg") { - <%= link_to maketext('PGML') => $c->systemLink( - url_for('problem_detail', setID => 'Undefined_Set', problemID => 1), - params => { - displayMode => $ce->{pg}{options}{displayMode}, - problemSeed => 1234, - editMode => 'temporaryFile', - sourceFilePath => 'PGMLLab/PGML-lab.pg' - } - ), - target => 'PGML' =%> - % } else { - <%= maketext('PGML') %> - % } + <%= link_to PGML => '#', class => 'pgml-lab', target => 'PGML', + data => { source => url_escape(readFile("$ce->{webworkDirs}{assets}/pg/PGMLLab/PGML-lab.pg")) } =%>
    - <%= maketext('This links to a WeBWorK "problem" which allows you to try out fragments of PGML code. ' - . 'This link will not be available if the file [_1] is not located in the templates directory of ' - . 'the course.', - 'PGMLLab/PGML-lab.pg') =%> + <%= maketext( + 'This links to a WeBWorK "problem" which allows you to try out fragments of PGML code.' + ) =%>
    - + <%= maketext('Author Info') %>
    @@ -156,19 +142,22 @@ . 'generating the PDF file using LaTeX.') =%>

    - <%= maketext('You can also click "Edit Selected Theme" to edit a hardcopy theme. The new theme will be saved to ' - . 'the templates/hardcopyThemes folder.') =%> + <%= maketext('You can also click "Edit Selected Theme" to edit a hardcopy theme. The new theme will be saved ' + . 'to the templates/hardcopyThemes folder.') =%>

    -
    <%= maketext('Format Code') %>
    +
    <%= maketext('Code Maintenance') %>
    - <%= maketext('Reformat the code using perltidy or a conversion to PGML. Using perltidy will change the code ' - . 'in the editor window, and save changes to the temporary file. In some cases (if the code contains ' - . 'backslashes or double tildes) this can result in odd spacing in the code. The convert to PGML ' - . 'feature changes the code in text blocks in the code to use PGML features. Generally the conversion of ' - . 'many of the formatting and LaTeX is performed correctly, however answer blanks need attention. In ' - . 'either case, make sure to inspect the formatted code, and edit further or revert if needed.') =%> + <%= maketext('Three code maintenance tools can be utilized. First, the code can be reformatted using perltidy. ' + . 'Using perltidy will change the code in the editor window, and save changes to the temporary file. In some ' + . 'cases (if the code contains backslashes or double tildes) this can result in odd spacing in the code. ' + . 'Second the code can be converted to PGML. This changes the code in text blocks to use PGML features. ' + . 'Generally the conversion of much of the formatting and LaTeX is performed correctly. However, answer ' + . 'blanks need attention. In any case, make sure to inspect the formatted code, and edit further or revert ' + . 'if needed. Third, the code can be analyzed by the "PG Critic." This checks that the code does not use ' + . 'old or deprecated features of PG and conforms to current best-practices in problem authoring, and offers ' + . 'suggestions on how to fix issues that are found.') =%>
    <%= maketext('Save') %>
    diff --git a/templates/HelpFiles/InstructorStats.html.ep b/templates/HelpFiles/InstructorStats.html.ep index c3434a1ccd..49a3f62517 100644 --- a/templates/HelpFiles/InstructorStats.html.ep +++ b/templates/HelpFiles/InstructorStats.html.ep @@ -1,14 +1,9 @@ % layout 'help_macro'; % title maketext('Statistics Help'); % -

    - <%= maketext('The main page allows access to set and student statistics. When selecting a student, their grades ' - . 'page is shown, which lists set totals and per problem grades for each set assigned to the student. When ' - . 'selecting a set, various statistics and histograms are shown for the overall grades of students who are ' - . 'currently enrolled or auditing the course.') =%> -

    - <%= maketext('When viewing set statistics, the drop down menus can be used to show stats for individual sections, ' - . 'recitations, or problems. The overall results include all students who are assigned to the set, while the ' - . 'individual problem results only include active (have attempted the problem) students.') =%> + <%= maketext('Display full set or problem statistics. The main page lists all sets to view. When viewing ' + . 'set statistics, the drop down menus can be used to show stats for individual sections, recitations, or ' + . 'problems. The overall results include all students who are assigned to the set, while the individual ' + . 'problem results only include active (have attempted the problem) students.') =%>

    diff --git a/templates/HelpFiles/InstructorUserList.html.ep b/templates/HelpFiles/InstructorUserList.html.ep index 57ed8676a7..b1b071cc6f 100644 --- a/templates/HelpFiles/InstructorUserList.html.ep +++ b/templates/HelpFiles/InstructorUserList.html.ep @@ -3,9 +3,9 @@ %

    <%== maketext('From this page you can add new students, edit user data ' - . '(name, email address, recitation, section, permission level, enrollment status, and password), ' - . 'and export (save) class lists for back-up or use in another course. ' - . 'You can also delete students from the class roster, but this cannot be undone.') =%> + . '(name, email address, student ID, enrollment status, accommodation time factor, section, recitation, ' + . 'comment, permission level, and password), and export (save) class lists for back-up or use ' + . 'in another course. You can also delete students from the class roster, but this cannot be undone.') =%>

    <%= maketext('This page gives access to information about the student, independent of the assignments ' @@ -62,7 +62,7 @@

    <%== maketext('This is most easily done by importing a class list. The class list can be uploaded from your ' . 'workstation to the server using the File Manager page. The class list must be a file ending in .lst and ' - . 'must have a specific ' + . 'must have a specific ' . 'format. Once the file has been uploaded to the server the file will appear in the import action ' . 'pop-up list (5th action). demoCourse.lst is available for most courses and adds the "practice users" ' . 'which activate guest logins to the class list.') =%> @@ -142,6 +142,16 @@ . 'grade for each problem is listed as "status" on this third page).') =%>
    +
    <%= maketext('Give one student or several students additional time for all timed tests.') %>
    +
    + <%= maketext('Click on the "Select" checkbox next to the names of the students that additional time is to be ' + . 'assigned, click on the radio button for editing selected users, and then click the "Edit" button. ' + . 'Set the "Accommodation Time Factor" to the desired multiplier for each student selected (this must be a ' + . 'decimal number that is greater than or equal to 1). The time that a student will have to complete a ' + . 'timed test will be the product of the "Test Time Limit" for the test set in the "Sets Manager" and ' + . 'the "Accommodation Time Factor" set here.') =%> +
    +
    <%= maketext('Extend the number of attempts allowed a student on a given problem.') %>
    <%= maketext(q{Click first in the "Assigned Sets" column in the student's row. This will take you to a new } diff --git a/templates/HelpFiles/instructor_links.html.ep b/templates/HelpFiles/instructor_links.html.ep index 1a4595cc49..f1fe87bd94 100644 --- a/templates/HelpFiles/instructor_links.html.ep +++ b/templates/HelpFiles/instructor_links.html.ep @@ -6,8 +6,8 @@
    <%== maketext('The main page for WeBWorK documentation is the webwork wiki while specific help for ' . q{instructors setting up a course are in the instructors' section.}, - 'href="http://webwork.maa.org/wiki" target="ww_wiki"', - 'href="http://webwork.maa.org/wiki/Instructors" target="ww_wiki"') =%> + 'href="https://wiki.openwebwork.org/wiki" target="ww_wiki"', + 'href="https://wiki.openwebwork.org/wiki/Instructors" target="ww_wiki"') =%>
    @@ -24,14 +24,14 @@ <%= maketext('Edit class roster data. Add students, edit student data, drop students from class, import ' . 'students from a classlist, and give user professor privileges. Access to individual assignments.') =%>
    -
    <%= maketext('Assigner Tool') %>
    -
    <%= maketext('Assign and unassign selected exercise sets to selected users.') %>
    <%= maketext('Sets Manager') %>
    <%= maketext('Edit sets for the entire class. Change set due dates, create new sets from a set ' . 'definition file, create new sets, make sets visible/invisible, score assignments. Assign ' . 'sets to the class.') =%>
    +
    <%= maketext('Assigner Tool') %>
    +
    <%= maketext('Assign and unassign selected exercise sets to selected users.') %>
    <%= maketext('Problem Editor') %>
    <%= maketext('Write a new PG problem file or edit an existing one.') %>
    <%= maketext('Library Browser') %>
    @@ -45,6 +45,11 @@ <%= maketext('Score one or more sets. This can also be done from the "Sets Manager" or from the ' . '"Instructor Tools", but the "Scoring Tools" page allows control over parameters.') =%> +
    <%= maketext('LTI Grade Update') %>
    +
    + <%= maketext('Manually initiate an LTI grade passback for selected sets or users. This link is only visible ' + . 'if LTI grade passback is enabled for the course.') =%> +
    <%= maketext('Achievements Manager') %>
    <%= maketext('Edit achivements for the course. This link is only present if achievements ' @@ -52,16 +57,13 @@
    <%= maketext('Email') %>
    <%= maketext('Send email to students.') %>
    +
    <%= maketext('Job Manager') %>
    +
    <%= maketext('View and manage jobs in the job queue.') %>
    <%= maketext('File Manager') %>
    <%= maketext('Upload, download and delete text files, including scoring spread sheets, set definition files, ' . 'class list spread sheets, and "PG" problems.') =%>
    -
    <%= maketext('LTI Grade Update') %>
    -
    - <%= maketext('Manually initiate an LTI grade passback for selected sets or users. This link is only visible ' - . 'if LTI grade passback is enabled for the course.') =%> -
    <%= maketext('Course Configuration') %>
    <%= maketext('Allows configuration of certain parameters, such as permission levels, default display mode for ' diff --git a/templates/RPCRenderFormats/default.html.ep b/templates/RPCRenderFormats/default.html.ep index 0ae0a2c6ec..a18a17cd40 100644 --- a/templates/RPCRenderFormats/default.html.ep +++ b/templates/RPCRenderFormats/default.html.ep @@ -19,6 +19,7 @@ % for (@$extra_css_files) { %= stylesheet $_->{file} % } + % for (@$third_party_js) { %= javascript $_->[0], %{ $_->[1] // {} } % } @@ -101,6 +102,9 @@ %= hidden_field showFooter => $showFooter %= hidden_field extra_header_text => $extra_header_text %= hidden_field problem_data => $problem_data + % if ($ws->{inputs_ref}{answerPrefix}) { + %= hidden_field answerPrefix => $ws->{inputs_ref}{answerPrefix} + % } % if ($formatName eq 'debug' && $ws->{inputs_ref}{clientDebug}) { %= hidden_field clientDebug => $ws->{inputs_ref}{clientDebug} % } @@ -132,64 +136,28 @@ % end
    - % # PG warning messages (this includes translator warnings but not translator errors). - % if ($rh_result->{pg_warnings}) { -
    -

    <%= $lh->maketext('Warning messages') %>

    -
      - % for (split("\n", $rh_result->{pg_warnings})) { -
    • <%== $_ %>
    • - % } -
    -
    - % } - % # PG warning messages generated with WARN_message. - % if (ref $rh_result->{warning_messages} eq 'ARRAY' && @{ $rh_result->{warning_messages} }) { -
    -

    <%= $lh->maketext('PG warning messages') %>

    -
      - % for (@{ $rh_result->{warning_messages} }) { -
    • <%== $_ %>
    • - % } -
    -
    - % } - % # Translator errors. - % if ($rh_result->{flags}{error_flag}) { -
    -

    Translator errors

    - <%== $rh_result->{errors} %> -
    - % } + <%= include 'ContentGenerator/Base/problem_warning_and_debug_output', + warnings => $rh_result->{pg_warnings}, + warning_messages => ref $rh_result->{warning_messages} eq 'ARRAY' ? $rh_result->{warning_messages} : [], + debug_messages => + $formatName eq 'debug' && ref $rh_result->{debug_messages} eq 'ARRAY' + ? $rh_result->{debug_messages} + : [] + =%> % # Additional information output only for the debug format. % if ($formatName eq 'debug') { - % # PG debug messages generated with DEBUG_message. - % if (@{ $rh_result->{debug_messages} }) { -
    -

    PG debug messages

    -
      - % for (@{ $rh_result->{debug_messages} }) { -
    • <%== $_ %>
    • - % } -
    -
    - % } - % # Internal debug messages generated within PGcore. - % if (ref $rh_result->{internal_debug_messages} eq 'ARRAY' && @{ $rh_result->{internal_debug_messages} }) { -
    -

    Internal errors

    -
      - % for (@{ $rh_result->{internal_debug_messages} }) { -
    • <%== $_ %>
    • - % } -
    -
    - % } % if ($ws->{inputs_ref}{clientDebug}) {

    Webwork client data

    %== $pretty_print->($ws) % } % } + % # Translator errors. + % if ($rh_result->{flags}{error_flag}) { +
    +

    Translator errors

    +
    <%== $rh_result->{errors} %>
    +
    + % }
    % # Show the footer unless it is explicity disabled. % if ($showFooter ne '0') { diff --git a/templates/layouts/system.html.ep b/templates/layouts/system.html.ep index d9af1c26e7..ff39da58ab 100644 --- a/templates/layouts/system.html.ep +++ b/templates/layouts/system.html.ep @@ -20,13 +20,15 @@ % } % % # Webwork configuration for javascript - + % % # JS Loads +% # The color scheme JavaScript must be loaded early and not deferred to prevent flickering as the color scheme is set. +<%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'js/System/color-scheme.js' }) =%> <%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'js/MathJaxConfig/mathjax-config.js' }), defer => undef =%> -<%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'node_modules/mathjax/es5/tex-svg.js' }), - id => 'MathJax-script', defer => undef =%> +<%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'node_modules/mathjax/tex-svg.js' }), + defer => undef =%> <%= javascript $c->url({ type => 'webwork', name => 'htdocs', file => 'node_modules/jquery/dist/jquery.min.js' }) %> <%= javascript $c->url({ type => 'webwork', name => 'htdocs', @@ -47,24 +49,66 @@ % <%= link_to 'Skip to main content' => '#page-title', - class => 'visually-hidden-focusable bg-white p-2 m-3 position-absolute' =%> + class => 'visually-hidden-focusable bg-light p-2 m-3 position-absolute' =%> % % # Header % # Navigation % if ($c->can('links') || $c->can('siblings') || $c->can('options')) { @@ -145,7 +189,7 @@
    % % if ($c->have_warnings) { -
    <%= $c->warnings %>
    +
    <%= $c->warnings %>
    % } % if ($c->can('message')) {
    <%= $c->message %>