├── MANIFEST.in ├── examples ├── mycategory.pdf ├── simple_random_question │ ├── pdf.png │ ├── moodle.png │ ├── python.png │ ├── moodle_cat.png │ ├── Number-of-roots-for-a-polynomial.pdf │ ├── latextomoodle.sty │ ├── template.ipynb │ └── Number-of-roots-for-a-polynomial.tex ├── simplest_essay_question_from_python │ ├── pdf.png │ ├── moodle.png │ ├── python.png │ ├── Simple-derivative.pdf │ ├── Simple-derivative.tex │ ├── template.ipynb │ ├── latextomoodle.sty │ └── Simple-derivative.xml ├── simplest_multichoice_question_from_python │ ├── pdf.png │ ├── moodle.png │ ├── python.png │ ├── python - Copie.png │ ├── Simple-arithmetic.pdf │ ├── Simple-arithmetic.tex │ ├── template.ipynb │ ├── latextomoodle.sty │ └── Simple-arithmetic.xml ├── simplest_multichoice_question_from_latex │ ├── latex.png │ ├── python.png │ ├── question-typed-from-latex.tex │ ├── template.ipynb │ ├── latextomoodle.sty │ └── Simple-arithmetic.xml ├── myquestion.tex ├── mycategory.tex ├── latextomoodle.sty ├── my first question.xml ├── simple_example.ipynb ├── many_questions_at_once.ipynb ├── My little catgory from latex.xml └── My little catgory from python.xml ├── doc ├── images │ └── schema │ │ ├── pdf.png │ │ ├── tex.png │ │ ├── xml.png │ │ ├── moodle.png │ │ ├── python.png │ │ ├── schema.pdn │ │ └── schema.png ├── changelog.md └── documentation.md ├── moodlexport ├── __init__.py ├── templates │ └── latextomoodle.sty ├── python_to_latex.py ├── tex_to_python.py ├── python_to_moodle.py └── string_manager.py ├── setup.py ├── LICENSE.txt ├── .gitignore └── README.md /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include moodlexport *.sty -------------------------------------------------------------------------------- /examples/mycategory.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/mycategory.pdf -------------------------------------------------------------------------------- /doc/images/schema/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/pdf.png -------------------------------------------------------------------------------- /doc/images/schema/tex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/tex.png -------------------------------------------------------------------------------- /doc/images/schema/xml.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/xml.png -------------------------------------------------------------------------------- /doc/images/schema/moodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/moodle.png -------------------------------------------------------------------------------- /doc/images/schema/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/python.png -------------------------------------------------------------------------------- /doc/images/schema/schema.pdn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/schema.pdn -------------------------------------------------------------------------------- /doc/images/schema/schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/doc/images/schema/schema.png -------------------------------------------------------------------------------- /examples/simple_random_question/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simple_random_question/pdf.png -------------------------------------------------------------------------------- /examples/simple_random_question/moodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simple_random_question/moodle.png -------------------------------------------------------------------------------- /examples/simple_random_question/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simple_random_question/python.png -------------------------------------------------------------------------------- /examples/simple_random_question/moodle_cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simple_random_question/moodle_cat.png -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_essay_question_from_python/pdf.png -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/moodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_essay_question_from_python/moodle.png -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_essay_question_from_python/python.png -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_python/pdf.png -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_latex/latex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_latex/latex.png -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_latex/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_latex/python.png -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/moodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_python/moodle.png -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_python/python.png -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/Simple-derivative.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_essay_question_from_python/Simple-derivative.pdf -------------------------------------------------------------------------------- /examples/simple_random_question/Number-of-roots-for-a-polynomial.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simple_random_question/Number-of-roots-for-a-polynomial.pdf -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/python - Copie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_python/python - Copie.png -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/Simple-arithmetic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/HEAD/examples/simplest_multichoice_question_from_python/Simple-arithmetic.pdf -------------------------------------------------------------------------------- /examples/myquestion.tex: -------------------------------------------------------------------------------- 1 | \documentclass{amsart} 2 | \usepackage{latextomoodle} 3 | \begin{document} 4 | \begin{question}[essay] 5 | What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$? 6 | \grade{1.5} 7 | \end{question} 8 | \end{document} -------------------------------------------------------------------------------- /moodlexport/__init__.py: -------------------------------------------------------------------------------- 1 | #from moodlexport.python_to_moodle import * 2 | #from moodlexport.tex_to_python import * 3 | #from moodlexport.python_to_latex import * 4 | 5 | from .python_to_moodle import Category, Question, savexml, savetex, savepdf 6 | from .tex_to_python import latextopython, latextomoodle 7 | from .string_manager import printmk, includegraphics 8 | 9 | 10 | 11 | #__all__ = [ Category] -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_latex/question-typed-from-latex.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{latextomoodle} 3 | \begin{document} 4 | \begin{category}[Simple arithmetic] 5 | \begin{question}[multichoice] 6 | The product 6x8 is equal to ... : 7 | 8 | \answer[0.0]{47} 9 | \answer[100.0]{48} 10 | \answer[0.0]{49} 11 | 12 | \end{question} 13 | \end{category} 14 | \end{document} 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/Simple-derivative.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{amsmath} 3 | \usepackage{amssymb} 4 | \usepackage{graphicx} 5 | \usepackage{latextomoodle} 6 | \begin{document} 7 | \begin{category}[Simple derivative] 8 | \begin{question}[essay] 9 | \title{Simple derivative} 10 | What is the derivative of $f(x)=x^2?$ 11 | 12 | 13 | \end{question} 14 | 15 | \end{category} 16 | 17 | \end{document} 18 | -------------------------------------------------------------------------------- /examples/mycategory.tex: -------------------------------------------------------------------------------- 1 | \documentclass{amsart} 2 | \usepackage{latextomoodle} 3 | \begin{document} 4 | \begin{category}[My little catgory from latex] 5 | \begin{question}[essay] 6 | What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$? 7 | \grade{1.5} 8 | \end{question} 9 | 10 | \begin{question}[multichoice] 11 | Is every symmetric matrix invertible? 12 | \answer[0]{Yes} 13 | \answer[100]{No} 14 | \grade{2.0} 15 | \end{question} 16 | \end{category} 17 | \end{document} -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/Simple-arithmetic.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{amsmath} 3 | \usepackage{amssymb} 4 | \usepackage{graphicx} 5 | \usepackage{latextomoodle} 6 | \begin{document} 7 | \begin{category}[Simple arithmetic] 8 | \begin{question}[multichoice] 9 | \title{Simple arithmetic} 10 | The product 6x8 is equal to ... : 11 | 12 | \answer[0.0]{47} 13 | \answer[100.0]{48} 14 | \answer[0.0]{49} 15 | 16 | \single{True} 17 | 18 | \end{question} 19 | 20 | \end{category} 21 | 22 | \end{document} 23 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name="moodlexport", 8 | version="0.0.32", 9 | author="Guillaume Garrigos", 10 | author_email="guillaume.garrigos@lpsm.paris", 11 | license="MIT", 12 | description="A package to export test questions into Moodle from python or latex", 13 | long_description=long_description, 14 | long_description_content_type="text/markdown", 15 | url="https://github.com/Guillaume-Garrigos/moodlexport", 16 | packages=['moodlexport', ], 17 | classifiers=[ 18 | "Programming Language :: Python :: 3", 19 | "License :: OSI Approved :: MIT License", 20 | "Operating System :: OS Independent", 21 | ], 22 | python_requires='>=3.7', 23 | install_requires=[ 24 | 'texsoup == 0.2.1', 25 | 'xmltodict >= 0.12.0', 26 | 'numpy >= 1.18.1', 27 | 'beautifulsoup4 >= 4.8.2', 28 | 'latexifier >= 1.0.5', 29 | ], 30 | include_package_data=True, 31 | ) -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Guillaume Garrigos 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_latex/template.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "The code below reads a question from a .tex file, and returns a .xml file ready to export to Moodle." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "from moodlexport import latextomoodle\n", 17 | "latextomoodle('question-typed-from-latex.tex')" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [] 26 | } 27 | ], 28 | "metadata": { 29 | "kernelspec": { 30 | "display_name": "Python 3", 31 | "language": "python", 32 | "name": "python3" 33 | }, 34 | "language_info": { 35 | "codemirror_mode": { 36 | "name": "ipython", 37 | "version": 3 38 | }, 39 | "file_extension": ".py", 40 | "mimetype": "text/x-python", 41 | "name": "python", 42 | "nbconvert_exporter": "python", 43 | "pygments_lexer": "ipython3", 44 | "version": "3.7.6" 45 | } 46 | }, 47 | "nbformat": 4, 48 | "nbformat_minor": 4 49 | } 50 | -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/template.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "The code below writes a question in Python, and exports it in both .xml and .pdf (along with .tex) formats." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 5, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "from moodlexport import Question # imports moodlexport\n", 17 | "question = Question(\"essay\") # we want a essay question\n", 18 | "question.text(\"What is the derivative of $f(x)=x^2?$\") # the question\n", 19 | "question.savexml(\"Simple derivative\") # that is for Moodle\n", 20 | "question.savepdf(\"Simple derivative\") # for convenient storing" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [] 29 | } 30 | ], 31 | "metadata": { 32 | "kernelspec": { 33 | "display_name": "Python 3", 34 | "language": "python", 35 | "name": "python3" 36 | }, 37 | "language_info": { 38 | "codemirror_mode": { 39 | "name": "ipython", 40 | "version": 3 41 | }, 42 | "file_extension": ".py", 43 | "mimetype": "text/x-python", 44 | "name": "python", 45 | "nbconvert_exporter": "python", 46 | "pygments_lexer": "ipython3", 47 | "version": "3.7.6" 48 | } 49 | }, 50 | "nbformat": 4, 51 | "nbformat_minor": 4 52 | } 53 | -------------------------------------------------------------------------------- /examples/latextomoodle.sty: -------------------------------------------------------------------------------- 1 | %%%% Define a family of environments and comments that we can use to define Moodle answers/questions/categories 2 | 3 | %%%%% ANSWER 4 | \usepackage{ifthen} 5 | \usepackage{wasysym} 6 | \newcommand{\goodanswer}{$\XBox$~} 7 | \newcommand{\badanswer}{$\Box$~} 8 | 9 | \newcommand{\answer}[2][]{ 10 | \ifthenelse{#1 > 0} 11 | {~\newline \noindent \goodanswer #2} 12 | {~\newline \noindent \badanswer #2} 13 | } 14 | 15 | %%%%% CATEGORY 16 | \newenvironment{category}[1][]{ \newpage \section{Catégorie: #1} }{\bigskip} 17 | 18 | \newcommand{\name}[1]{} 19 | \renewcommand{\description}[1]{} 20 | 21 | %%%%% QUESTION 22 | \newenvironment{question}[1][]{\noindent \textbf{Question:}}{\bigskip} 23 | 24 | \renewcommand{\title}[1]{\textbf{(#1)}} 25 | \newcommand{\infocorrecteur}[1]{~\\ \noindent \textbf{Solution:} #1} 26 | 27 | % Dummy commands 28 | \newcommand{\type}[1]{} 29 | \newcommand{\generalfeedback}[1]{} 30 | \newcommand{\grade}[1]{} 31 | %\renewcommand{\penalty}[1]{} 32 | \newcommand{\hidden}[1]{} 33 | \newcommand{\idnumber}[1]{} 34 | \newcommand{\responseformat}[1]{} 35 | \newcommand{\responserequired}[1]{} 36 | \newcommand{\responsefieldlines}[1]{} 37 | \newcommand{\attachments}[1]{} 38 | \newcommand{\attachmentsrequired}[1]{} 39 | \newcommand{\responsetemplate}[1]{} 40 | \newcommand{\single}[1]{} 41 | \newcommand{\shuffleanswers}[1]{} 42 | \newcommand{\answernumbering}[1]{} 43 | \newcommand{\correctfeedback}[1]{} 44 | \newcommand{\partiallycorrectfeedback}[1]{} 45 | \newcommand{\incorrectfeedback}[1]{} 46 | \newcommand{\shownumcorrect}[1]{} 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/template.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "The code below writes a question in Python, and exports it in both .xml and .pdf (along with .tex) formats." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "from moodlexport import Question # imports moodlexport\n", 17 | "question = Question(\"multichoice\") # we want a multichoice question\n", 18 | "question.text(\"The product 6x8 is equal to ... :\") # the question\n", 19 | "question.answer(\"47\", False) # the possible answers\n", 20 | "question.answer(\"48\", True)\n", 21 | "question.answer(\"49\", False)\n", 22 | "question.savexml(\"Simple arithmetic\") # that is for Moodle\n", 23 | "question.savepdf(\"Simple arithmetic\") # for convenient storing" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [] 32 | } 33 | ], 34 | "metadata": { 35 | "kernelspec": { 36 | "display_name": "Python 3", 37 | "language": "python", 38 | "name": "python3" 39 | }, 40 | "language_info": { 41 | "codemirror_mode": { 42 | "name": "ipython", 43 | "version": 3 44 | }, 45 | "file_extension": ".py", 46 | "mimetype": "text/x-python", 47 | "name": "python", 48 | "nbconvert_exporter": "python", 49 | "pygments_lexer": "ipython3", 50 | "version": "3.7.6" 51 | } 52 | }, 53 | "nbformat": 4, 54 | "nbformat_minor": 4 55 | } 56 | -------------------------------------------------------------------------------- /examples/simple_random_question/latextomoodle.sty: -------------------------------------------------------------------------------- 1 | %%%% Define a family of environments and comments that we can use to define Moodle answers/questions/categories 2 | 3 | %%%%% ANSWER 4 | \usepackage{ifthen} 5 | \usepackage{wasysym} 6 | \newcommand{\goodanswer}{$\XBox$~} 7 | \newcommand{\badanswer}{$\Box$~} 8 | 9 | \newcommand{\answer}[2][]{% 10 | \ifthenelse{\lengthtest{#1 pt > 0.0pt}} 11 | {\leavevmode\newline \noindent \goodanswer #2 \hfill (${#1} \%$)} 12 | {\leavevmode\newline \noindent \badanswer #2 \hfill (${#1} \%$)} 13 | } 14 | 15 | %%%%% CATEGORY 16 | \newenvironment{category}[1][]{ \newpage \section{Catégorie: #1} }{\bigskip} 17 | 18 | \newcommand{\name}[1]{} 19 | \renewcommand{\description}[1]{} 20 | 21 | %%%%% QUESTION 22 | \newenvironment{question}[1][]{\noindent \textbf{Question:}}{\bigskip} 23 | 24 | \renewcommand{\title}[1]{\textbf{(#1)}} 25 | \newcommand{\infocorrecteur}[1]{~\\ \noindent \textbf{Solution:} #1} 26 | 27 | % Dummy commands 28 | \newcommand{\type}[1]{} 29 | \newcommand{\generalfeedback}[1]{} 30 | \newcommand{\grade}[1]{} 31 | %\renewcommand{\penalty}[1]{} 32 | \newcommand{\hidden}[1]{} 33 | \newcommand{\idnumber}[1]{} 34 | \newcommand{\responseformat}[1]{} 35 | \newcommand{\responserequired}[1]{} 36 | \newcommand{\responsefieldlines}[1]{} 37 | \newcommand{\attachments}[1]{} 38 | \newcommand{\attachmentsrequired}[1]{} 39 | \newcommand{\responsetemplate}[1]{} 40 | \newcommand{\single}[1]{} 41 | \newcommand{\shuffleanswers}[1]{} 42 | \newcommand{\answernumbering}[1]{} 43 | \newcommand{\correctfeedback}[1]{} 44 | \newcommand{\partiallycorrectfeedback}[1]{} 45 | \newcommand{\incorrectfeedback}[1]{} 46 | \newcommand{\shownumcorrect}[1]{} 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/latextomoodle.sty: -------------------------------------------------------------------------------- 1 | %%%% Define a family of environments and comments that we can use to define Moodle answers/questions/categories 2 | 3 | %%%%% ANSWER 4 | \usepackage{ifthen} 5 | \usepackage{wasysym} 6 | \newcommand{\goodanswer}{$\XBox$~} 7 | \newcommand{\badanswer}{$\Box$~} 8 | 9 | \newcommand{\answer}[2][]{% 10 | \ifthenelse{\lengthtest{#1 pt > 0.0pt}} 11 | {\leavevmode\newline \noindent \goodanswer #2 \hfill (${#1} \%$)} 12 | {\leavevmode\newline \noindent \badanswer #2 \hfill (${#1} \%$)} 13 | } 14 | 15 | %%%%% CATEGORY 16 | \newenvironment{category}[1][]{ \newpage \section{Catégorie: #1} }{\bigskip} 17 | 18 | \newcommand{\name}[1]{} 19 | \renewcommand{\description}[1]{} 20 | 21 | %%%%% QUESTION 22 | \newenvironment{question}[1][]{\noindent \textbf{Question:}}{\bigskip} 23 | 24 | \renewcommand{\title}[1]{\textbf{(#1)}} 25 | \newcommand{\infocorrecteur}[1]{~\\ \noindent \textbf{Solution:} #1} 26 | 27 | % Dummy commands 28 | \newcommand{\type}[1]{} 29 | \newcommand{\generalfeedback}[1]{} 30 | \newcommand{\grade}[1]{} 31 | %\renewcommand{\penalty}[1]{} 32 | \newcommand{\hidden}[1]{} 33 | \newcommand{\idnumber}[1]{} 34 | \newcommand{\responseformat}[1]{} 35 | \newcommand{\responserequired}[1]{} 36 | \newcommand{\responsefieldlines}[1]{} 37 | \newcommand{\attachments}[1]{} 38 | \newcommand{\attachmentsrequired}[1]{} 39 | \newcommand{\responsetemplate}[1]{} 40 | \newcommand{\single}[1]{} 41 | \newcommand{\shuffleanswers}[1]{} 42 | \newcommand{\answernumbering}[1]{} 43 | \newcommand{\correctfeedback}[1]{} 44 | \newcommand{\partiallycorrectfeedback}[1]{} 45 | \newcommand{\incorrectfeedback}[1]{} 46 | \newcommand{\shownumcorrect}[1]{} 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_latex/latextomoodle.sty: -------------------------------------------------------------------------------- 1 | %%%% Define a family of environments and comments that we can use to define Moodle answers/questions/categories 2 | 3 | %%%%% ANSWER 4 | \usepackage{ifthen} 5 | \usepackage{wasysym} 6 | \newcommand{\goodanswer}{$\XBox$~} 7 | \newcommand{\badanswer}{$\Box$~} 8 | 9 | \newcommand{\answer}[2][]{% 10 | \ifthenelse{\lengthtest{#1 pt > 0.0pt}} 11 | {\leavevmode\newline \noindent \goodanswer #2 \hfill (${#1} \%$)} 12 | {\leavevmode\newline \noindent \badanswer #2 \hfill (${#1} \%$)} 13 | } 14 | 15 | %%%%% CATEGORY 16 | \newenvironment{category}[1][]{ \newpage \section{Catégorie: #1} }{\bigskip} 17 | 18 | \newcommand{\name}[1]{} 19 | \renewcommand{\description}[1]{} 20 | 21 | %%%%% QUESTION 22 | \newenvironment{question}[1][]{\noindent \textbf{Question:}}{\bigskip} 23 | 24 | \renewcommand{\title}[1]{\textbf{(#1)}} 25 | \newcommand{\infocorrecteur}[1]{~\\ \noindent \textbf{Solution:} #1} 26 | 27 | % Dummy commands 28 | \newcommand{\type}[1]{} 29 | \newcommand{\generalfeedback}[1]{} 30 | \newcommand{\grade}[1]{} 31 | %\renewcommand{\penalty}[1]{} 32 | \newcommand{\hidden}[1]{} 33 | \newcommand{\idnumber}[1]{} 34 | \newcommand{\responseformat}[1]{} 35 | \newcommand{\responserequired}[1]{} 36 | \newcommand{\responsefieldlines}[1]{} 37 | \newcommand{\attachments}[1]{} 38 | \newcommand{\attachmentsrequired}[1]{} 39 | \newcommand{\responsetemplate}[1]{} 40 | \newcommand{\single}[1]{} 41 | \newcommand{\shuffleanswers}[1]{} 42 | \newcommand{\answernumbering}[1]{} 43 | \newcommand{\correctfeedback}[1]{} 44 | \newcommand{\partiallycorrectfeedback}[1]{} 45 | \newcommand{\incorrectfeedback}[1]{} 46 | \newcommand{\shownumcorrect}[1]{} 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/latextomoodle.sty: -------------------------------------------------------------------------------- 1 | %%%% Define a family of environments and comments that we can use to define Moodle answers/questions/categories 2 | 3 | %%%%% ANSWER 4 | \usepackage{ifthen} 5 | \usepackage{wasysym} 6 | \newcommand{\goodanswer}{$\XBox$~} 7 | \newcommand{\badanswer}{$\Box$~} 8 | 9 | \newcommand{\answer}[2][]{% 10 | \ifthenelse{\lengthtest{#1 pt > 0.0pt}} 11 | {\leavevmode\newline \noindent \goodanswer #2 \hfill (${#1} \%$)} 12 | {\leavevmode\newline \noindent \badanswer #2 \hfill (${#1} \%$)} 13 | } 14 | 15 | %%%%% CATEGORY 16 | \newenvironment{category}[1][]{ \newpage \section{Catégorie: #1} }{\bigskip} 17 | 18 | \newcommand{\name}[1]{} 19 | \renewcommand{\description}[1]{} 20 | 21 | %%%%% QUESTION 22 | \newenvironment{question}[1][]{\noindent \textbf{Question:}}{\bigskip} 23 | 24 | \renewcommand{\title}[1]{\textbf{(#1)}} 25 | \newcommand{\infocorrecteur}[1]{~\\ \noindent \textbf{Solution:} #1} 26 | 27 | % Dummy commands 28 | \newcommand{\type}[1]{} 29 | \newcommand{\generalfeedback}[1]{} 30 | \newcommand{\grade}[1]{} 31 | %\renewcommand{\penalty}[1]{} 32 | \newcommand{\hidden}[1]{} 33 | \newcommand{\idnumber}[1]{} 34 | \newcommand{\responseformat}[1]{} 35 | \newcommand{\responserequired}[1]{} 36 | \newcommand{\responsefieldlines}[1]{} 37 | \newcommand{\attachments}[1]{} 38 | \newcommand{\attachmentsrequired}[1]{} 39 | \newcommand{\responsetemplate}[1]{} 40 | \newcommand{\single}[1]{} 41 | \newcommand{\shuffleanswers}[1]{} 42 | \newcommand{\answernumbering}[1]{} 43 | \newcommand{\correctfeedback}[1]{} 44 | \newcommand{\partiallycorrectfeedback}[1]{} 45 | \newcommand{\incorrectfeedback}[1]{} 46 | \newcommand{\shownumcorrect}[1]{} 47 | 48 | 49 | -------------------------------------------------------------------------------- /examples/simplest_essay_question_from_python/Simple-derivative.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $module$/top/Simple derivative 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Simple derivative 14 | 15 | 16 | \(\)What is the derivative of \(f(x)=x^2?\)

]]>
17 |
18 | 19 | 20 | 21 | 1.0 22 | 0.0 23 | 0 24 | 25 | editorfilepicker 26 | 0 27 | 10 28 | -1 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | true 38 | none 39 | 40 | Votre réponse est correcte.

]]>
41 |
42 | 43 | Votre réponse est partiellement correcte.

]]>
44 |
45 | 46 | Votre réponse est incorrecte.

]]>
47 |
48 | 49 | 50 |
51 |
-------------------------------------------------------------------------------- /examples/my first question.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $module$/top/Default category name 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Default question title 14 | 15 | 16 | \(\)What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$?

]]>
17 |
18 | 19 | 20 | 21 | 1.5 22 | 0.0 23 | 0 24 | 25 | editorfilepicker 26 | 0 27 | 10 28 | -1 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | true 38 | none 39 | 40 | \(\)Votre réponse est correcte.

]]>
41 |
42 | 43 | \(\)Votre réponse est partiellement correcte.

]]>
44 |
45 | 46 | \(\)Votre réponse est incorrecte.

]]>
47 |
48 | 49 | 50 |
51 |
-------------------------------------------------------------------------------- /doc/changelog.md: -------------------------------------------------------------------------------- 1 | 2 | # Changelog 3 | 4 | *Go back to the [main page](../README.md)* 5 | 6 | - v.0.0.32 Implements the option `path` for categories for Latex->Moodle conversion. 7 | - v.0.0.30 8 | - Solves a bug for Latex->Moodle conversion with multichoice question. The text of the question was being erased by the text of the answers. 9 | - Make the feedback(s) appear on the .pdf documents, when provided. Proposed by [@jcerezochem](https://github.com/jcerezochem) in issue #10 10 | - Updates in the documentation. Proposed by [@theresiavr](https://github.com/theresiavr) in issue #13 11 | - v.0.0.25 Solves two bugs for multichoice questions from issue #6, with code from [@Stivanification](https://github.com/Stivanification) 12 | - v.0.0.24 Solves issue #5 13 | - v.0.0.23 Forgot to load some modules. [PR](https://github.com/Guillaume-Garrigos/moodlexport/pull/4) from [@gregnordin](https://github.com/gregnordin) 14 | - v.0.0.22 Add a new feature to insert images. 15 | - v.0.0.21 The parser used to handle `$`'s was wayyy to slow. This is corrected now. 16 | - v.0.0.20 17 | - I realized that depending on Moodle's version, or depending on how the administrator implements it, inline math like `$e^x$` can not be recognized. Moodle's doc [says](https://docs.moodle.org/3x/fr/Utilisation_de_la_notation_TeX) it is not supported. So, now, every inline math `$e^x$` is converted into `\(e^x\)` just before exporting the data into XML. This allows the user to painlessly type latex as usual with `$`'s. 18 | - Now TEX files are generated without spaces or `_` in the filename. Because latexmk wasn't happy when generating pdfs. 19 | - v.0.0.19 20 | - Corrects bug #3 for multichoice questions, allowing now for negative grades for wrong answers. Proposed by [@Stivanification](https://github.com/Stivanification). 21 | - Corrects bug #2 caused by a broken backcompatibility from the TexSoup Module. Now this module requires the exact needed version 22 | -------------------------------------------------------------------------------- /moodlexport/templates/latextomoodle.sty: -------------------------------------------------------------------------------- 1 | %%%% Define a family of environments and comments that we can use to define Moodle answers/questions/categories 2 | 3 | %%%%% ANSWER 4 | \usepackage{ifthen} 5 | \usepackage{wasysym} 6 | \newcommand{\goodanswer}{$\XBox$~} 7 | \newcommand{\badanswer}{$\Box$~} 8 | \newcommand{\answer}[2][]{% 9 | \ifthenelse{\lengthtest{#1 pt > 0.0pt}} 10 | {\leavevmode\newline \noindent \goodanswer #2 \hfill (${#1} \%$)} 11 | {\leavevmode\newline \noindent \badanswer #2 \hfill (${#1} \%$)} 12 | } 13 | 14 | %%%%% CATEGORY 15 | \newenvironment{category}[1][]{ \newpage \section{Catégorie: #1} }{\bigskip} 16 | 17 | \newcommand{\name}[1]{} 18 | \renewcommand{\description}[1]{} 19 | \newcommand{\path}[1]{} 20 | 21 | %%%%% QUESTION 22 | \newenvironment{question}[1][]{\noindent \textbf{Question:}}{\bigskip} 23 | \renewcommand{\title}[1]{\textbf{(#1)}} 24 | \newcommand{\infocorrecteur}[1]{\smallskip ~\\ \noindent \textbf{Solution:} #1 \smallskip} 25 | 26 | %%%%% FEEDBACKS 27 | \newcommand{\generalfeedback}[1]{\smallskip ~\\ \noindent \textbf{General feedback:} #1 \smallskip} 28 | \newcommand{\correctfeedback}[1]{\smallskip ~\\ \noindent \textbf{Correct feedback:} #1 \smallskip} 29 | \newcommand{\partiallycorrectfeedback}[1]{\smallskip ~\\ \noindent \textbf{Partially correct feedback:} #1 \smallskip} 30 | \newcommand{\incorrectfeedback}[1]{\smallskip ~\\ \noindent \textbf{Incorrect feedback:} #1 \smallskip} 31 | 32 | %%%%% Dummy commands 33 | \newcommand{\type}[1]{} 34 | \newcommand{\grade}[1]{} 35 | %\renewcommand{\penalty}[1]{} 36 | \newcommand{\hidden}[1]{} 37 | \newcommand{\idnumber}[1]{} 38 | \newcommand{\responseformat}[1]{} 39 | \newcommand{\responserequired}[1]{} 40 | \newcommand{\responsefieldlines}[1]{} 41 | \newcommand{\attachments}[1]{} 42 | \newcommand{\attachmentsrequired}[1]{} 43 | \newcommand{\responsetemplate}[1]{} 44 | \newcommand{\single}[1]{} 45 | \newcommand{\shuffleanswers}[1]{} 46 | \newcommand{\answernumbering}[1]{} 47 | \newcommand{\shownumcorrect}[1]{} 48 | 49 | 50 | -------------------------------------------------------------------------------- /examples/simple_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Simple example" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "From Python:" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "from moodlexport import Question" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "question = Question(\"essay\")\n", 33 | "question.text(\"What is the derivative of $f(x) = e^x + 0.5 \\Vert x \\Vert^2$?\")\n", 34 | "question.grade(1.5)\n", 35 | "question.save(\"my first question\")" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "From Latex:" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 3, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "from moodlexport import latextomoodle" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 4, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "latextomoodle('myquestion.tex','my first question')" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [] 69 | } 70 | ], 71 | "metadata": { 72 | "kernelspec": { 73 | "display_name": "Python 3", 74 | "language": "python", 75 | "name": "python3" 76 | }, 77 | "language_info": { 78 | "codemirror_mode": { 79 | "name": "ipython", 80 | "version": 3 81 | }, 82 | "file_extension": ".py", 83 | "mimetype": "text/x-python", 84 | "name": "python", 85 | "nbconvert_exporter": "python", 86 | "pygments_lexer": "ipython3", 87 | "version": "3.7.6" 88 | } 89 | }, 90 | "nbformat": 4, 91 | "nbformat_minor": 4 92 | } 93 | -------------------------------------------------------------------------------- /examples/simple_random_question/template.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "We want to generate questions where we ask the student if a polynomial equation $aX^2 + bX +c = 0$ with integer coefficients has a solution or no." 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "from moodlexport import Category, Question\n", 17 | "from sympy.abc import x # allows to define polynomials in x\n", 18 | "from sympy import latex # conveniently returns latex strings\n", 19 | "\n", 20 | "coefficients = [-3, -2, -1, 1, 2, 3] # the coefficients we allow\n", 21 | "category = Category(\"Number of roots for a polynomial\") # Gather all the questions\n", 22 | "\n", 23 | "for a in coefficients: # we loop over the allowed coefficients\n", 24 | " for b in coefficients:\n", 25 | " for c in coefficients:\n", 26 | " question = Question(\"multichoice\") # a new question\n", 27 | " P = a*x**2 + b*x + c # our sympy polynomial\n", 28 | " question.text(\"The equation $\"+latex(P)+\"=0$ has:\")\n", 29 | " question.answer(\"at least a solution\", b**2 - 4*a*c > 0 )\n", 30 | " question.answer(\"no real solution\", b**2 - 4*a*c <= 0 )\n", 31 | " question.addto(category) # question goes into the category\n", 32 | " \n", 33 | "category.savepdf() # save the category\n", 34 | "category.savexml() # export the category to Moodle" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [] 43 | } 44 | ], 45 | "metadata": { 46 | "kernelspec": { 47 | "display_name": "Python 3", 48 | "language": "python", 49 | "name": "python3" 50 | }, 51 | "language_info": { 52 | "codemirror_mode": { 53 | "name": "ipython", 54 | "version": 3 55 | }, 56 | "file_extension": ".py", 57 | "mimetype": "text/x-python", 58 | "name": "python", 59 | "nbconvert_exporter": "python", 60 | "pygments_lexer": "ipython3", 61 | "version": "3.7.6" 62 | } 63 | }, 64 | "nbformat": 4, 65 | "nbformat_minor": 4 66 | } 67 | -------------------------------------------------------------------------------- /examples/many_questions_at_once.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Many questions at once" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "From Python " 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 1, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "from moodlexport import Question, Category" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 2, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "category = Category(\"My little catgory from python\")\n", 33 | "\n", 34 | "question = Question(\"essay\")\n", 35 | "question.text(\"What is the derivative of $f(x) = e^x + 0.5 \\Vert x \\Vert^2$?\")\n", 36 | "question.grade(1.5)\n", 37 | "question.addto(category)\n", 38 | " \n", 39 | "question = Question(\"multichoice\")\n", 40 | "question.text(\"Is every symmetric matrix invertible?\")\n", 41 | "question.grade(2.0)\n", 42 | "question.answer(\"Yes\", False)\n", 43 | "question.answer(\"No\", True)\n", 44 | "question.addto(category)\n", 45 | "\n", 46 | "category.save()" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 3, 52 | "metadata": {}, 53 | "outputs": [], 54 | "source": [ 55 | "from moodlexport import latextomoodle" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 4, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "latextomoodle('mycategory.tex')" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [] 73 | } 74 | ], 75 | "metadata": { 76 | "kernelspec": { 77 | "display_name": "Python 3", 78 | "language": "python", 79 | "name": "python3" 80 | }, 81 | "language_info": { 82 | "codemirror_mode": { 83 | "name": "ipython", 84 | "version": 3 85 | }, 86 | "file_extension": ".py", 87 | "mimetype": "text/x-python", 88 | "name": "python", 89 | "nbconvert_exporter": "python", 90 | "pygments_lexer": "ipython3", 91 | "version": "3.7.6" 92 | } 93 | }, 94 | "nbformat": 4, 95 | "nbformat_minor": 4 96 | } 97 | -------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_latex/Simple-arithmetic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $module$/top/Simple arithmetic 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Question with no title 14 | 15 | 16 | 49

]]>
17 |
18 | 19 | 20 | 21 | 1.0 22 | 0.0 23 | 0 24 | 25 | editorfilepicker 26 | 0 27 | 10 28 | -1 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | true 38 | none 39 | 40 | Votre réponse est correcte.

]]>
41 |
42 | 43 | Votre réponse est partiellement correcte.

]]>
44 |
45 | 46 | Votre réponse est incorrecte.

]]>
47 |
48 | 49 | 50 | 47

]]>
51 | 52 | 53 | 54 |
55 | 56 | 48

]]>
57 | 58 | 59 | 60 |
61 | 62 | 49

]]>
63 | 64 | 65 | 66 |
67 |
68 |
-------------------------------------------------------------------------------- /examples/simplest_multichoice_question_from_python/Simple-arithmetic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $module$/top/Simple arithmetic 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Simple arithmetic 14 | 15 | 16 | The product 6x8 is equal to ... :

]]>
17 |
18 | 19 | 20 | 21 | 1.0 22 | 0.0 23 | 0 24 | 25 | editorfilepicker 26 | 0 27 | 10 28 | -1 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | true 38 | none 39 | 40 | Votre réponse est correcte.

]]>
41 |
42 | 43 | Votre réponse est partiellement correcte.

]]>
44 |
45 | 46 | Votre réponse est incorrecte.

]]>
47 |
48 | 49 | 50 | 47

]]>
51 | 52 | 53 | 54 |
55 | 56 | 48

]]>
57 | 58 | 59 | 60 |
61 | 62 | 49

]]>
63 | 64 | 65 | 66 |
67 |
68 |
-------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/python,jupyternotebooks 3 | # Edit at https://www.gitignore.io/?templates=python,jupyternotebooks 4 | 5 | ### Personal documents ### 6 | TODO.md 7 | *ps1 8 | 9 | ### JupyterNotebooks ### 10 | # gitignore template for Jupyter Notebooks 11 | # website: http://jupyter.org/ 12 | 13 | .ipynb_checkpoints 14 | */.ipynb_checkpoints/* 15 | 16 | # IPython 17 | profile_default/ 18 | ipython_config.py 19 | 20 | # Remove previous ipynb_checkpoints 21 | # git rm -r .ipynb_checkpoints/ 22 | 23 | ### Python ### 24 | # Byte-compiled / optimized / DLL files 25 | __pycache__/ 26 | *.py[cod] 27 | *$py.class 28 | 29 | # C extensions 30 | *.so 31 | 32 | # Distribution / packaging 33 | .Python 34 | build/ 35 | test/ 36 | develop-eggs/ 37 | dist/ 38 | downloads/ 39 | eggs/ 40 | .eggs/ 41 | lib/ 42 | lib64/ 43 | parts/ 44 | sdist/ 45 | var/ 46 | wheels/ 47 | pip-wheel-metadata/ 48 | share/python-wheels/ 49 | *.egg-info/ 50 | .installed.cfg 51 | *.egg 52 | MANIFEST 53 | 54 | # PyInstaller 55 | # Usually these files are written by a python script from a template 56 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 57 | *.manifest 58 | *.spec 59 | 60 | # Installer logs 61 | pip-log.txt 62 | pip-delete-this-directory.txt 63 | 64 | # Unit test / coverage reports 65 | htmlcov/ 66 | .tox/ 67 | .nox/ 68 | .coverage 69 | .coverage.* 70 | .cache 71 | nosetests.xml 72 | coverage.xml 73 | *.cover 74 | .hypothesis/ 75 | .pytest_cache/ 76 | 77 | # Translations 78 | *.mo 79 | *.pot 80 | 81 | # Scrapy stuff: 82 | .scrapy 83 | 84 | # Sphinx documentation 85 | docs/_build/ 86 | 87 | # PyBuilder 88 | target/ 89 | 90 | # pyenv 91 | .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # celery beat schedule file 101 | celerybeat-schedule 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Spyder project settings 107 | .spyderproject 108 | .spyproject 109 | 110 | # Rope project settings 111 | .ropeproject 112 | 113 | # Mr Developer 114 | .mr.developer.cfg 115 | .project 116 | .pydevproject 117 | 118 | # mkdocs documentation 119 | /site 120 | 121 | # mypy 122 | .mypy_cache/ 123 | .dmypy.json 124 | dmypy.json 125 | 126 | # Pyre type checker 127 | .pyre/ 128 | 129 | # End of https://www.gitignore.io/api/python,jupyternotebooks 130 | -------------------------------------------------------------------------------- /moodlexport/python_to_latex.py: -------------------------------------------------------------------------------- 1 | 2 | from moodlexport.python_to_moodle import Category, Question 3 | from moodlexport.string_manager import latex_protect, alias, savestr 4 | 5 | import os.path 6 | 7 | LATEX_PACKAGE_URL = "https://raw.githubusercontent.com/Guillaume-Garrigos/moodlexport/master/latex/latextomoodle.sty" 8 | LATEX_PACKAGE_NAME = "latextomoodle" 9 | 10 | def latexfile_preamble(list_of_packages=[]): 11 | string = "\documentclass{article}\n" 12 | string += "\\usepackage{amsmath}\n" 13 | string += "\\usepackage{amssymb}\n" 14 | string += "\\usepackage{graphicx}\n" 15 | 16 | for package in list_of_packages: 17 | string += latex_protect("\\usepackage{")+ package +"}\n" 18 | return string 19 | 20 | def latexfile_begin(env_name, option = None): 21 | string = latex_protect('\begin{' + env_name + '}') 22 | if option is not None: 23 | string += '[' + str(option) + ']' 24 | return string + '\n' 25 | 26 | def latexfile_end(env_name): 27 | return latex_protect('\end{' + env_name + '}') + '\n' 28 | 29 | def latexfile_command(cmd_name, value, option = None): 30 | string = latex_protect("\\" + cmd_name ) 31 | if option is not None: 32 | string += '[' + str(option) + ']' 33 | string += '{' + latex_protect(str(value)) + '}\n' 34 | return string 35 | 36 | def latexfile_environement(env_name, value, option=None): 37 | string = latexfile_begin(env_name, option) 38 | string += value + '\n' 39 | string += latexfile_end(env_name) 40 | return string 41 | 42 | def latexfile_append_question(question): #Given a Question return the latex string 43 | content = "" 44 | if question.structure['name']['isset']: # First the title 45 | content += latexfile_command(alias('name'), question.get_name()) 46 | content += latex_protect(question.get_text()) + '\n' 47 | option = question.get_type() 48 | if question.has_answer(): 49 | content += '\n' 50 | for answer in question.get_answer(): 51 | content += latexfile_command('answer', answer.get_text(), str(answer.get_relativegrade())) 52 | content += '\n' 53 | for field in question.structure: 54 | if field not in ['@type', 'questiontext', 'answer', 'name']: # keep it for later/before 55 | if question.structure[field]['isset']: # if default we dont print it 56 | content += latexfile_command(alias(field), question.structure[field]['value']) 57 | return latexfile_environement('question', content, option) 58 | 59 | def latexfile_append_category(category): # Given a category return the latex string 60 | content = "" 61 | description = category.get_description() 62 | if description != "": 63 | content += latexfile_command('description', description) 64 | for question in category.get_question(): 65 | content += latexfile_append_question(question) 66 | return latexfile_environement('category', content, category.get_name()) 67 | 68 | def latexfile_document(category): 69 | import_latextomoodle() 70 | content = latexfile_preamble([LATEX_PACKAGE_NAME]) 71 | content += latexfile_environement('document', latexfile_append_category(category)) 72 | return content 73 | 74 | def import_latextomoodle(): 75 | # Importing a local template : idea taken from 76 | # https://stackoverflow.com/questions/6028000/how-to-read-a-static-file-from-inside-a-python-package 77 | import pkgutil, io 78 | if not os.path.isfile('latextomoodle.sty') : 79 | string = pkgutil.get_data("moodlexport", "templates/latextomoodle.sty").decode() 80 | savestr(string, 'latextomoodle.sty') 81 | 82 | -------------------------------------------------------------------------------- /examples/My little catgory from latex.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $module$/top/My little catgory from latex 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Default question title 14 | 15 | 16 | \(\)What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$?

]]>
17 |
18 | 19 | 20 | 21 | 1.5 22 | 0.0 23 | 0 24 | 25 | editorfilepicker 26 | 0 27 | 10 28 | -1 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | true 38 | none 39 | 40 | \(\)Votre réponse est correcte.

]]>
41 |
42 | 43 | \(\)Votre réponse est partiellement correcte.

]]>
44 |
45 | 46 | \(\)Votre réponse est incorrecte.

]]>
47 |
48 | 49 | 50 |
51 | 52 | 53 | Default question title 54 | 55 | 56 | \(\)Is every symmetric matrix invertible?

]]>
57 |
58 | 59 | 60 | 61 | 2.0 62 | 0.0 63 | 0 64 | 65 | editorfilepicker 66 | 0 67 | 10 68 | -1 69 | 0 70 | 71 | 72 | 73 | 74 | 75 | 76 | true 77 | true 78 | none 79 | 80 | \(\)Votre réponse est correcte.

]]>
81 |
82 | 83 | \(\)Votre réponse est partiellement correcte.

]]>
84 |
85 | 86 | \(\)Votre réponse est incorrecte.

]]>
87 |
88 | 89 | 90 | \(\)Yes

]]>
91 | 92 | 93 | 94 |
95 | 96 | \(\)No

]]>
97 | 98 | 99 | 100 |
101 |
102 |
-------------------------------------------------------------------------------- /examples/My little catgory from python.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $module$/top/My little catgory from python 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Default question title 14 | 15 | 16 | \(\)What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$?

]]>
17 |
18 | 19 | 20 | 21 | 1.5 22 | 0.0 23 | 0 24 | 25 | editorfilepicker 26 | 0 27 | 10 28 | -1 29 | 0 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | true 38 | none 39 | 40 | \(\)Votre réponse est correcte.

]]>
41 |
42 | 43 | \(\)Votre réponse est partiellement correcte.

]]>
44 |
45 | 46 | \(\)Votre réponse est incorrecte.

]]>
47 |
48 | 49 | 50 |
51 | 52 | 53 | Default question title 54 | 55 | 56 | \(\)Is every symmetric matrix invertible?

]]>
57 |
58 | 59 | 60 | 61 | 2.0 62 | 0.0 63 | 0 64 | 65 | editorfilepicker 66 | 0 67 | 10 68 | -1 69 | 0 70 | 71 | 72 | 73 | 74 | 75 | 76 | true 77 | true 78 | none 79 | 80 | \(\)Votre réponse est correcte.

]]>
81 |
82 | 83 | \(\)Votre réponse est partiellement correcte.

]]>
84 |
85 | 86 | \(\)Votre réponse est incorrecte.

]]>
87 |
88 | 89 | 90 | \(\)Yes

]]>
91 | 92 | 93 | 94 |
95 | 96 | \(\)No

]]>
97 | 98 | 99 | 100 |
101 |
102 |
-------------------------------------------------------------------------------- /moodlexport/tex_to_python.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | from moodlexport.python_to_moodle import Category, Question 4 | from moodlexport.string_manager import isfield, cleanstr 5 | import moodlexport.string_manager as strtools 6 | 7 | from TexSoup import TexSoup 8 | from TexSoup.data import TexNode 9 | from TexSoup.utils import TokenWithPosition 10 | 11 | # Given a latex question, returns a python question 12 | # we have to parse a lot here, and the parser isn't super smart so the code is a bit messy 13 | def read_latex_question(latex_question): 14 | if len(latex_question.args) == 1: # we got a optional argument for the type of question 15 | question = Question(latex_question.args[0].value) 16 | list_contents = list(latex_question.contents)[1:] # we skip the 1st content which should be option 17 | else: 18 | question = Question() 19 | list_contents = list(latex_question.contents) 20 | text = "" 21 | # we read all the contents and puts it in the structure 22 | for content in list_contents: 23 | # we check the type of the content : either a parameter or the main text 24 | if isinstance(content, TokenWithPosition): # main field 25 | text = text + content.text 26 | elif isinstance(content, TexNode): # optional parameter but careful because math is treated as TexNode... 27 | field = content.name # a string giving us the name of the option 28 | if isfield(field): # is it a field defined in DICT_DEFAULT_QUESTION_MOODLE ? 29 | if field == 'answer': # cas un peu compliqué 30 | if len(content.args) == 1: # pas d'option donc faux par défaut 31 | answer_text = strtools.latex_to_html_cleaner(content.args[0].value) 32 | question.answer(answer_text, False) 33 | elif len(content.args) == 2: # optional value for grade percentage 34 | answer_text = strtools.latex_to_html_cleaner(content.args[1].value) 35 | question.answer(answer_text, content.args[0].value) 36 | else: # general field, easy to manage 37 | value = content.string # a string containing the value of the said option 38 | getattr(question, field)(value) 39 | else: # annoying, certainly valid latex, most RISKY part of the code 40 | text = text + str(content) 41 | question.text(strtools.latex_to_html_cleaner(text)) 42 | return question 43 | 44 | def read_latex_category(category_latex): 45 | if len(category_latex.args) == 1: # we got a optional argument, it is the category name 46 | category = Category(category_latex.args[0].value) 47 | list_contents = list(category_latex.contents)[1:] # we skip the 1st content which should be option 48 | else: 49 | category = Category() 50 | list_contents = list(category_latex.contents) 51 | # we read all the contents and puts it in the structure 52 | for content in list_contents: 53 | if isinstance(content, TexNode): # There should be just stuff like that 54 | field = str(content.name) # a string giving us the name of the option 55 | if field == 'name': # don't compare with 'is' for some dark python reason. same content, but not identity 56 | category.name(content.string) 57 | elif field == 'description': 58 | category.description(strtools.latex_to_html_cleaner(content.string)) 59 | elif field == 'path': 60 | category.path(strtools.latex_to_html_cleaner(content.string)) 61 | elif field == 'question': 62 | question = read_latex_question(content) 63 | question.addto(category) 64 | return category 65 | 66 | def latextopython(file_name): 67 | # converts a latex file into a list of Category 68 | with open(extension_checker(file_name,'tex'), 'r', encoding='utf-8') as file: 69 | latex = file.read() 70 | # we clean the file from superfluous things, or operate conversions from latex to html 71 | #question.text(cleanstr(text, raw=True)) # if we want to have more fancy text in moodle like with

it must be done here.. 72 | # we parse the text to extract all the information into our python structures 73 | soup = TexSoup(latex) 74 | category_list = [] # The list of objects 75 | category_latex_list = list(soup.find_all('category')) # the list of latex-soup 76 | if len(category_latex_list) > 0: # we list the categories and return them 77 | for category_latex in category_latex_list: 78 | category_list.append(read_latex_category(category_latex)) 79 | else: # well at least we hope to find questions so we create a dummy category 80 | category = Category() 81 | question_latex_list = list(soup.find_all('question')) 82 | for question_latex in question_latex_list: 83 | read_latex_question(question_latex).addto(category) 84 | category_list = [category,] 85 | return category_list 86 | 87 | def latextomoodle(file_name=None, save_name = None): 88 | # converts a latex file into an XML file ready to export into Moodle 89 | # if no file_name is given, parse the current directory and applies the function to every .tex files 90 | if file_name is None: 91 | import glob 92 | for texfile in glob.glob("*.tex"): 93 | latextomoodle(texfile) 94 | return 95 | category_list = latextopython(file_name) 96 | counter = 1 97 | for category in category_list: 98 | if save_name is None: 99 | category.savexml() 100 | else: 101 | if len(category_list) == 1: 102 | string = save_name 103 | else: 104 | string = save_name + '-' + str(counter) 105 | counter = counter + 1 106 | category.savexml(string) 107 | 108 | def extension_checker(file_name, ext): 109 | if file_name[-len(ext)-1:] != '.'+ext: 110 | return file_name + '.'+ext 111 | else: 112 | return file_name 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # moodlexport 2 | 3 | [![PyPI version badge](https://img.shields.io/pypi/v/moodlexport)](doc/changelog.md) 4 | ![Last commit badge](https://img.shields.io/github/last-commit/Guillaume-Garrigos/moodlexport?color=blue) 5 | 6 | This Python module provides code which allows to easily generate families of questions (called *categories* in Moodle) that can be directly created from either Python or Latex document, and then directly exported into Moodle (through the Moodle XML import functionality), where they can be used to create a test. 7 | 8 | | Overview of the possible conversions done within moodlexport | 9 | | --- | 10 | | | 11 | 12 | ## Installing 13 | 14 | It can be installed with a pip command : `pip install moodlexport` 15 | 16 | ## Table of contents 17 | 18 | - [A quick overview of what this Module can do](#A-quick-overview-of-what-this-Module-can-do) 19 | - [Motivation](#Motivation) 20 | - [Advanced documentation](#Advanced-documentation) 21 | - [Changelog](#Changelog) 22 | - [Known issues](#Known-issues) 23 | 24 | ## A quick overview of what this Module can do 25 | 26 | This module focuses on two type of questions provided by Moodle : the `multichoice` question (the student chooses one or more answers among others), and the `essay` question (the student is provided a space to type its answer, or upload a document). 27 | 28 | | An essay question | A multichoice question | 29 | | --- | --- | 30 | | | | 31 | 32 | Say that you want to define a multiple choice question in Moodle. This requires a lot of parameters to tune, but for now let's focus on the essential : what you basically needs is 33 | 34 | 1. The body/text of your question 35 | 2. A list of potential answers 36 | 3. Setting which answer is the good one (see the documentation for more advanced settings like having more than one good answer) 37 | 4. Exporting that to Moodle 38 | 39 | Here is a short overview on how to do that from Pyhton with `moodlexport`. 40 | 41 | | Writing a multichoice question from Python | 42 | | --- | 43 | | | 44 | | | 45 | | | 46 | | From top to bottom: 1) the python code defining our question and producing a .xml file; 2) that question in Moodle after importing the .xml file; 3) a .pdf produced by the Python code, for convenience. You can find the corresponding code [here](examples/simplest_multichoice_question_from_python/template.ipynb) | 47 | 48 | You could equivalently obtain the very same result by typing the question in a Latex file, and using moodlexport to convert it: 49 | 50 | | Writing a multichoice question from Latex | 51 | | --- | 52 | | | 53 | | | 54 | | | 55 | | A latex file defining a question, and then converted to an .xml by Python. You can find the corresponding code [here](examples/simplest_multichoice_question_from_latex/template.ipynb) | 56 | 57 | To write an essay question, the syntax is as simple: 58 | 59 | | Writing an essay question from Python | 60 | | --- | 61 | | | 62 | | | 63 | | | 64 | | From top to bottom: 1) the python code defining our question and producing a .xml file; 2) that question in Moodle after importing the .xml file; 3) a .pdf produced by the Python code, for convenience. You can find the corresponding code [here](examples/simplest_essay_question_from_python/template.ipynb) | 65 | 66 | The interest of writing your questions in Python is that you can easily generate random problems. Suppose for instance that we want a random question where we ask the student if a polynomial equation $aX^2 + bX +c = 0$, with integer coefficients, has a solution or no. 67 | One way to go is to generate a bunch of those questions, and then let Moodle pick one question at random among those during a `test`. Here is one way to do: 68 | 69 | | Generating random questions | 70 | | --- | 71 | | | 72 | | | 73 | | | 74 | | | 75 | | From top to bottom: 1) the python code defining a category containing many variants of a same question, and producing a .xml file; 2) some of these questions appearing in a category in Moodle 3) one such question in Moodle; 4) a sample of the .pdf produced by the Python code. You can find the corresponding code [here](examples/simple_random_question/template.ipynb) | 76 | 77 | 78 | ### Motivation 79 | 80 | The main motivation behind this module is that : 81 | - it is more comfortable to type maths in your day-to-day Latex interface than within Moodle 82 | - it is easier to define mathematical objects (vectors, matrix) in Python than in Moodle 83 | - generating **random problems** is quite intricate in Moodle, because we quickly face issues such as solutions being too complicated for the students (e.g. non integer), or Moodle being unable to handle certain student's answers (how would could Moodle interpret that $x+x$ is the same than $2x$?). This is much simpler to handle in Python. 84 | - it is easier to manipulate locally a Latex or Python file than doing it on the Moodle interface. It also simplifies collaborating projects. 85 | - it is more convenient to store/read questions/answers in pdf files, than using the Moodle 'bank of questions' interface. 86 | 87 | ## Advanced documentation 88 | 89 | To read more about what this module can do, on how the parameters of your question can be set, see the complete documentation [here](doc/documentation.md). 90 | 91 | ## Changelog 92 | 93 | The changelog can be found [here](doc/changelog.md). 94 | 95 | ## Known issues 96 | 97 | - for the latex package, there is issues with `newcommand` and `renewcommand` because for instance the document class `amsart` defines `text` but it is not the case for `article`. 98 | - So far I have a bad time handling breaklines in a text written in python. Using explicit `
` tags should do the job. -------------------------------------------------------------------------------- /doc/documentation.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | *Go back to the [main page](../README.md)* 4 | 5 | 6 | Table of contents of this documentation: 7 | - [Main features of this module so far](#Main-features-of-this-module-so-far) 8 | - [Quick start](#Quick-start) 9 | - [Simple examples from Python](#Simple-examples-from-Python) 10 | - [Simple examples from Latex](#Simple-examples-from-Latex) 11 | - [Exporting many questions at once](#Exporting-many-questions-at-once) 12 | - [Advanced documentation](#Advanced-documentation) 13 | - [Main commands from Python](#Main-commands-from-Python) 14 | - [Main commands from Latex](#Main-commands-from-Latex) 15 | - [Miscellaneous](#Miscellaneous) 16 | - [Inserting an image](#Inserting-an-image) 17 | - [Turning variables into Latex](#Turning-variables-into-Latex) 18 | 19 | 20 | 21 | 22 | 23 | ## Main features of this module so far 24 | - Creating a question. The only supported classes of questions are: 25 | - "essay" : the student answers in a white text box. 26 | - "multichoice" : the question comes with at least 2 possible answers. 27 | - All the options available in Moodle are available here (defining a grade, information for the grader, feedback, etc). See more details below. 28 | - Creating a category (family) of questions. 29 | - Supports Unicode within python and latex : éàê ... 30 | - Supports Latex syntax, whether you write from latex or python, in way that Moodle understands. Supports inline latex with `$e^x$`, `\(e^x\)`, and equation with `$$ f(x) = \sum_i x_i^2 $$, \begin{equation*}...\end{equation*}, \begin{cases}` etc 31 | - Supports export to Moodle via a XML MOODLE file, but also to .tex and .pdf files (which allow more easily to see what you are doing) 32 | - Supports inserting images 33 | 34 | ## Quick start 35 | 36 | ### Simple examples from Python: 37 | 38 | 39 | ```python 40 | from moodlexport import Question 41 | 42 | question = Question("essay") 43 | question.text("What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$?") 44 | question.grade(1.5) 45 | question.save("my first question") 46 | ``` 47 | 48 | ### Simple examples from Latex 49 | 50 | You can produce the same result as above by defining your question directly in a Latex file. 51 | Suppose for isntance that you have a Latex file `myquestion.tex` containing the following : 52 | 53 | ```latex 54 | \documentclass{amsart} 55 | \usepackage{latextomoodle} 56 | \begin{document} 57 | \begin{question}[essay] 58 | What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$? 59 | \grade{1.5} 60 | \end{question} 61 | \end{document} 62 | ``` 63 | 64 | Then you can convert this `myquestion.tex` file directly into a `readytoexport.xml` file, by using the following Python commands: 65 | 66 | ```python 67 | from moodlexport import latextomoodle 68 | latextomoodle('myquestion.tex','my first question') 69 | ``` 70 | 71 | Note that if you wish to compile the `.tex` file without errors, you will need to place the Latex package `latextomoodle.sty` in the same folder. This package can be found in `moodlexport/templates` 72 | 73 | ### Exporting many questions at once 74 | 75 | If you want to export more than one question, you might want to gather them within a category, which will produce a single file containing all those questions. Here is how to proceed: 76 | 77 | In Python: 78 | 79 | ```python 80 | from moodlexport import Question, Category 81 | 82 | category = Category("My little catgory name") 83 | 84 | question = Question("essay") 85 | question.text("What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$?") 86 | question.grade(1.5) 87 | question.addto(category) 88 | 89 | question = Question("multichoice") 90 | question.text("Is every symmetric matrix invertible?") 91 | question.grade(2.0) 92 | question.answer("Yes", False) 93 | question.answer("No", True) 94 | question.addto(category) 95 | 96 | category.save() 97 | ``` 98 | In Latex, followed by the python command `latextomoodle('file_name.tex')` : 99 | 100 | ```latex 101 | \documentclass{amsart} 102 | \usepackage{latextomoodle} 103 | \begin{document} 104 | \begin{category}[My little catgory name] 105 | \begin{question}[essay] 106 | What is the derivative of $f(x) = e^x + 0.5 \Vert x \Vert^2$? 107 | \grade{1.5} 108 | \end{question} 109 | \begin{question}[multichoice] 110 | Is every symmetric matrix invertible? 111 | \answer[0]{Yes} 112 | \answer[100]{No} 113 | \grade{2.0} 114 | \end{question} 115 | \end{category} 116 | \end{document} 117 | ``` 118 | 119 | ## Advanced documentation 120 | 121 | ### Main commands from Python 122 | 123 | #### The Category Class 124 | 125 | `category = Category(string)` creates an object of class Category. `string` here specifies the name of the category, which will appear in Moodle. It comes with a few methods: 126 | 127 | - `category.savexml(string)` creates an XML file under the XML Moodle format, ready to import within Moodle. The name of the file is the name of the category by default. If a `string` is given, the name of the file will be `string.xml`. 128 | - `category.savetex(string)` creates a TEX file, containing all the questions of the category, nicely displayed. The name of the file is the name of the category by default (spaces and underscores will be replaced with `-`). If a `string` is given, the name of the file will be `string.tex`. 129 | - `category.savepdf(string)` creates a TEX file as above and then compiles it to generated a PDF file. 130 | - `category.description(string)` Adds a description to the category, which will appear in Moodle. 131 | - `category.path(string)` by default the category is imported at the root of the class. But you might want to order your categories with a tree structure (Moodle allows for subacategories). For instance `category.path("Default/main category/subcategory12/)` will ensure that after import you category will be a subcategory of `subcategory12`. Pay attention to the final `"/"`! 132 | 133 | #### The Question Class 134 | 135 | `question = Question(type)` creates an object of class Question. The `type` of the question can be `essay` (default) or `multichoice`. It comes with a family of methods `question.OPTION(value)` where `OPTION` describes every possible option that you can set in Moodle. The most important ones are: 136 | 137 | - `question.title(string)` sets the title of the question 138 | - `question.text(string)` sets the text (main body) of the question 139 | - `question.grade(float)` sets the grade of the quesiton 140 | - `question.graderinfo(string)` sets the information to be given to the grader 141 | - `question.addto(category)` adds the question to a `category` 142 | 143 | Methods specific to the `essay` type (answer via a text editor): 144 | - `question.responseformat(string)` : 145 | - `editorfilepicker` the student can upload a file as an answer or type in the textbox (default) 146 | - `editor` the student can only use the textbox, upload of a file is unavailable 147 | - `noinline` the textbox is unavailable, upload of a file is mandatory 148 | - `question.responserequired(bool)` : `0` if no response is required (default), `1` if a response is required. 149 | Methods specific to the `essay` type (answer via a text editor): 150 | - `question.responseformat(string)` : `editorfilepicker` lets the student upload a file as an answer (default) , `editor` forbids it, `noinline` gets rid of the text box and forces the student to upload at least a file 151 | - `question.responserequired(bool)` : `0` if no response is required (default), `1` if a response is required. 152 | - `question.attachments(int)`: lets the student upload at most `int` files. 153 | - `question.attachmentsrequired(int)`: student must upload at most `int` files. 154 | 155 | Methods specific to the `multichoice` type (finite number of possible answers): 156 | - `question.answer(string, value)` : Adds a possible answer to the question. `string` is the text of the answer, `value` describes if this answer is correct or no. It can be described in two ways: 157 | - as a boolean `True` or `False` (default) 158 | - as a percentage (integer between 0 and 100), which represents the fraction of the grade attributed to the answer. This is typically used for questions with more than 2 answers. A unique true answer has 100, a wrong answer has 0 (default) 159 | - `question.single(value)` : `true` if only one answer is possible (default), `false` if more than one answer can be selected by the student. 160 | 161 | 162 | 163 | ### Main commands from Latex 164 | 165 | It is possible to use a similar syntax within a TEX document : 166 | 167 | - `\begin{category}[name] ... \end{category}` defines the environment corresponding to a category. It is possible to write various categories within the same document. `name` is the (optional) name of the category. 168 | - `\description{string}` and `\path{string}` are commands working similarly to their python counterpart. 169 | - `\begin{question}[type] ... \end{question}` defines the environment corresponding to a question. It is possible to write various question within the same category. `type` is the type of the question, `essay` by default. 170 | - All the methods mentioned in the Python section can be used in latex. The analogue of `.OPTION(value)` becomes `\OPTION{value}` in Latex (and must be placed within the corresponding environment). For instance : 171 | - `\description{string}` sets the description of a category 172 | - `\grade{float}` sets the grade of a question 173 | - `\answer[value]{string}` adds an answer to a multichoice question 174 | 175 | 176 | The corresponding latex package can be found in `moodlexport/moodlexport/templates`, should be [here](https://github.com/Guillaume-Garrigos/moodlexport/tree/master/moodlexport/templates). 177 | 178 | To convert a .tex file into an .xml, use 179 | 180 | ```python 181 | from moodlexport import latextomoodle 182 | latextomoodle('file_name.tex') 183 | ``` 184 | 185 | You can also import the contents of your .tex file directly into python (you might want to do some modifications before exporting to Moodle). You .tex file must contain one or more categories of questions. To do so, use : 186 | 187 | ```python 188 | from moodlexport import latextopython 189 | # it outputs a list of Category objects, even if you have only one category. 190 | list_of_categories = latextopython('file_name.tex') 191 | ``` 192 | 193 | 194 | 195 | ### Miscellaneous 196 | 197 | #### Inserting an image 198 | 199 | From latex, the command `includegraphics` is supported. More exactly you can use a command like `\includegraphics[width=256px, height=128px]{./some_folder/my_image.png}` from the package `graphicx` 200 | - for the options `width` and `height`, the only supported unit is `px` 201 | - the option `scale` is not supported 202 | - if the command `\includegraphics` is called inline then it will be displayed inline in Moodle as well. 203 | - if the command is called in an environment `\begin{center} ... \end{center}`, the image will be centered as well in Moodle. 204 | - no other environments controlling the position of the image is supported for now. 205 | 206 | From python, the `moodlexport` module provides you with a `includegraphics` function, whose api is as close as possible to the Latex one: 207 | 208 | ```python 209 | from moodlexport import includegraphics 210 | 211 | text = 'here is a cool image:' + includegraphics("./some_folder/my_image.png", width=256, height=128) 212 | 213 | question = Question() 214 | question.text(text) 215 | ``` 216 | 217 | Options of this `includegraphics` python function: 218 | - `width` and `height` (integer). Modify the size of the image, in pixels. If no argument is passed, the image is displayed in its original shape. 219 | - `style` (string). Two possible values: 220 | * `"centered"` (default). The image is displayed in a new line and centered. 221 | * `"inline"`. The image is displayed next to the text. 222 | 223 | #### Turning variables into Latex 224 | 225 | When generating questions from python you will end up with mathematical objects (real number, vector, matrix, etc) that you want to use in your question or answer. This means that at some point you will need to convert those objects into a string, that can eventually be rendered as a Latex expression by Moodle's MathJax feature. 226 | 227 | The function [latexify](https://github.com/Guillaume-Garrigos/latexify) does exactly this for you. Note that it is part of `moodlexport`'s dependencies, so you likely have this module already installed in your environment. -------------------------------------------------------------------------------- /moodlexport/python_to_moodle.py: -------------------------------------------------------------------------------- 1 | 2 | from xml.sax.saxutils import unescape 3 | import copy 4 | import os 5 | import logging 6 | 7 | import xmltodict 8 | import numpy as np # only for np.bool ... too bad :/ 9 | 10 | from moodlexport.string_manager import dict_default_question_moodle, set_oparg 11 | import moodlexport.string_manager as strtools 12 | 13 | #################################### 14 | ## CLASS : CATEGORY 15 | #################################### 16 | 17 | class Category(): 18 | """ 19 | Object collecting Questions under the form of a category, ready to export to Moodle. 20 | Object.dict is a dictionary containing the ifnormation which will be converted into XML 21 | Object.structure is an other dict, which contains the same information, but more (and we don't want 22 | this "more" to appear in the XML. For instance text and latex is not encoded/escaped the same 23 | in .dict and .structure. For sure we could do better ... 24 | Methods: 25 | _set(name, description) : e.g. _set("my_category", "list of questions about ... ") 26 | append(question) : adds a Question to the Category 27 | save(file_name) : save the Category into Moodle-XML 28 | """ 29 | def __init__(self, name=None, path=""): 30 | self.structure = { 31 | "name" : "", 32 | "description" : "", 33 | "path" : "", 34 | "question" : []} 35 | self.name(name) 36 | self.path(path) 37 | self.dict = {} 38 | 39 | def name(self, string=None): 40 | if string is None: 41 | string = "Unnamed category " + strtools.clock() 42 | self.structure['name'] = string 43 | 44 | def description(self, string=""): 45 | self.structure['description'] = string 46 | 47 | def path(self, string=""): 48 | if len(string) > 0: 49 | if string[-1] == "/": 50 | self.structure['path'] = string 51 | else: 52 | raise ValueError("The path for a Category must end with '/' ") 53 | else: 54 | self.structure['path'] = "" 55 | 56 | def get_question(self, number=None): 57 | if number is None: 58 | return self.structure['question'] 59 | else: # we assume it is an integer 60 | return self.structure['question'][number] 61 | 62 | def get_name(self): 63 | return self.structure['name'] 64 | 65 | def get_description(self): 66 | return self.structure['description'] 67 | 68 | def get_path(self): 69 | return self.structure['path'] 70 | 71 | def append(self, question): # adds a Question to a Category 72 | question.addto(self) 73 | 74 | def compilation(self): # extract all the questions the Category contains, and puts it in a dict 75 | question_init = { 76 | "@type": "category", 77 | "category": {"text": "$module$/top/" + self.get_path() + self.get_name() }, 78 | "info": {"@format": "html", "text": strtools.html(self.get_description())} 79 | } 80 | self.dict = { "quiz": {"question": [question_init] } } 81 | for idx, question in enumerate(self.structure['question']): 82 | # here we need smarter rule for suffix because in alphabetic order gives 1, 10, 2, 3, etc 83 | question.namefrom(self, idx+1) # eventually gives a name + number to the question 84 | question.compilation() # redundant with Question.addto 85 | self.dict['quiz']['question'].append(question.dict) 86 | 87 | def savexml(self, file_name=None): 88 | """ Save a category under the format Moodle XML """ 89 | self.compilation() 90 | if file_name is None: 91 | file_name = self.get_name() 92 | file_name = strtools.filename_protect(file_name) 93 | category_xml = xmltodict.unparse(self.dict, pretty=True) # here all bools are converted to strings 94 | strtools.savestr(unescape(category_xml), file_name + ".xml") 95 | 96 | def save(self, file_name=None): #deprecated? 97 | self.savexml(file_name) 98 | 99 | def savetex(self, file_name=None): 100 | """ Save a category under the format TEX """ 101 | import moodlexport.python_to_latex # SO ANNOYING CIRCULAR IMPORT 102 | self.compilation() 103 | if file_name is None: 104 | file_name = self.get_name() 105 | file_name = strtools.filename_protect(file_name) 106 | string = moodlexport.python_to_latex.latexfile_document(self) 107 | string = strtools.html_to_latex(string) # we clean the file from all the html tags 108 | strtools.savestr(string, file_name + ".tex") 109 | 110 | def savepdf(self, file_name=None): 111 | """ Save a category under the format PDF """ 112 | if file_name is None: 113 | file_name = self.get_name() 114 | file_name = strtools.filename_protect(file_name) 115 | self.savetex(file_name) 116 | import moodlexport.python_to_latex 117 | moodlexport.python_to_latex.import_latextomoodle() 118 | os.system("latexmk -pdf "+file_name+".tex") 119 | os.system("latexmk -c "+file_name+".tex") 120 | 121 | 122 | 123 | #################################### 124 | ## CLASS : QUESTION 125 | #################################### 126 | 127 | class Question(): 128 | """ 129 | Object collecting the parameters of a question under the form of a dictionary. 130 | Methods: 131 | _set(field, value) : e.g. _set("questiontext", "What is $2+2$?") 132 | """ 133 | def __init__(self, question_type=None): 134 | question_type = set_oparg(question_type, "essay") 135 | self.structure = copy.deepcopy(dict_default_question_moodle()) # Need deep otherwise mess 136 | self.dict = {} # The proper question in a dictionary ready to turn into xml 137 | for field in self.structure: 138 | self._set(field, None) # None will trigger the default value 139 | self._set('@type', question_type) 140 | 141 | def _set(self, field, value=None): 142 | """ Assigns a value to a field of a Question. It is stored in both .structure and .dict """ 143 | #value = set_oparg(value, "") 144 | field_structure = self.structure[field] 145 | if value is None: # this happens when creating a question with an empty dict 146 | value = self.structure[field]['default'] 147 | field_structure['isset'] = False 148 | else: 149 | field_structure['isset'] = True 150 | # now 'value' has the good ... value 151 | field_structure['value'] = value 152 | if 'attribute' not in field_structure: # no attributes, just stupid value to assign 153 | self.dict[field] = value 154 | else: # we have "attributes" which means the field contains a "" element 155 | if 'html' in field_structure['attribute'].values(): # the value is a string to be turned... 156 | value = strtools.html(value) # ... into a html string (tackles latex,

's and stuff) 157 | # now we just fill the field with a text element, and its attributes 158 | self.dict[field] = {**field_structure['attribute'], **{"text": value}} # concatenation needs Python >= 3.5 159 | 160 | def multi_answer(self): # unlocks the multiple answer mode 161 | self.dict["single"] = "false" 162 | 163 | def has_answer(self): 164 | return (self.get_type() == "multichoice") and self.structure['answer']['isset'] 165 | 166 | def cumulated_grade_correct(self): # sums the grades of *correct* answers 167 | if self.structure['answer']['isset']: 168 | s = 0.0 169 | for answer in self.structure['answer']['list']: 170 | if answer.structure['relativegrade'] > 0: 171 | s += answer.structure['relativegrade'] 172 | return s 173 | else: 174 | return 100.0 175 | 176 | def should_it_be_single_choice(self): 177 | # Given the grades of the answers, try to guess whether the question 178 | # should be "single choice" or "multi choice". 179 | # returns a boolean 180 | # the default value is True (arbitrary choice but consistent with dict_default_question_moodle) 181 | if self.has_answer(): # if so we return True only if one of the grades is 100 182 | istheanswer100 = [int(ans.get_relativegrade()) == 100 for ans in self.get_answer()] # bunch of True/False 183 | return sum(istheanswer100) == 1 # True iff there is only one grade set to 100 184 | else: 185 | return True 186 | 187 | 188 | def addto(self, category): 189 | self.compilation() 190 | category.structure['question'].append(self) 191 | 192 | def namefrom(self, category, number=""): # eventually gets a generic name from the category 193 | if not self.structure['name']['isset']: # question name is not set 194 | if category.get_name()[:7] != 'Unnamed': # SO FRAGILE ERHHH 195 | self.name(category.get_name()+" "+str(number)) 196 | 197 | def compilation(self): 198 | """ This is where we put the Answers in the Question 199 | 1. Collects all the Answers if any 200 | 2. Check that the Answer's grades are okay 201 | 3. Check that the 'single' parameter is set and compatible with the grades 202 | 4. Check that the sum of positive grades is 100 (tolerance: 1e-3) 203 | """ 204 | tolerance = 1e-3 205 | if self.has_answer(): # if there are answers 206 | self.dict["answer"] = [] # instead of "" so far. Also reboots the dict if we did changes 207 | for answer in self.get_answer(): 208 | answer.compilation() # refresh the Answer.dict after eventual changes on Answer.structure 209 | self.dict["answer"].append(answer.dict) # loads the answer.dict into the question.dict 210 | 211 | if not self.structure['single']['isset']: 212 | # in that case we need to guess it 213 | self.single(self.should_it_be_single_choice()) # we give a bool, will be converted to string later in Category.savexml 214 | else: # in that case we just check nothing weird happens 215 | if self.get_single() and not self.should_it_be_single_choice(): 216 | raise ValueError("You have set the 'single' parameter to 'True', meaning that only one answer can be chosen. But it seems that you have more than one valid answers. Please make sure that this is what you want.") 217 | if not self.get_single() and self.should_it_be_single_choice(): 218 | logging.warning("You have set the 'single' parameter to 'False' for this Question, meaning that multiple answers can be chosen. But it seems that there is only one valid answer. Please make sure that this is what you want.") 219 | 220 | if abs(self.cumulated_grade_correct() - 100) > tolerance: # makes sure that the sum of grades for good answers is roughly 100 221 | raise ValueError('In a multichoice Question, the sum of the relative grades/percentages of the correct answers must be 100 (within a tolerance of '+str(tolerance)+'), but it apprears to be '+str(self.cumulated_grade_correct())) 222 | 223 | 224 | def savexml(self, name=None): 225 | # saves the question without category in a single file 226 | if name is None: 227 | name = self.get_name() 228 | elif not self.structure['name']['isset']: 229 | self.name(name) 230 | cat = Category(name) 231 | self.addto(cat) 232 | cat.savexml() 233 | 234 | def savetex(self, name=None): 235 | # saves the question without category in a single file 236 | if name is None: 237 | name = self.get_name() 238 | elif not self.structure['name']['isset']: 239 | self.name(name) 240 | cat = Category(name) 241 | self.addto(cat) 242 | cat.savetex() 243 | 244 | def savepdf(self, name=None): 245 | # saves the question without category in a single file 246 | if name is None: 247 | name = self.get_name() 248 | elif not self.structure['name']['isset']: 249 | self.name(name) 250 | cat = Category(name) 251 | self.addto(cat) 252 | cat.savepdf() 253 | 254 | def answer(self, answer_text="This is a default answer", grade=0): 255 | # appends an answer to the question. Calls the Answer class 256 | ans = Answer(answer_text, grade) 257 | ans.addto(self) 258 | #self.structure['answer']['value'].append({'text' : answer_text, 'grade': ans.dict['@fraction'] }) 259 | 260 | def get_answer(self, number=None): 261 | if self.has_answer(): 262 | if number is None: 263 | return self.structure['answer']['list'] 264 | else: 265 | return self.structure['answer']['list'][number] 266 | else: 267 | raise ValueError('This Question has no Answer') 268 | 269 | def get_relativegrade(self, number=None): # collects the grades of the Answers 270 | if self.has_answer(): 271 | if number is None: 272 | return [answer.get_relativegrade() for answer in self.get_answer()] 273 | else: 274 | return self.get_answer(number).get_relativegrade() 275 | else: 276 | raise ValueError('This Question has no Answer') 277 | 278 | # Here we define automatically methods to assign values to Question fields 279 | for key in dict_default_question_moodle().keys(): 280 | if key is not "answer": # could be misinterpreted with Question.dict["answer"] 281 | setattr(Question, strtools.alias(key), lambda self, value, key=key: self._set(key, value)) 282 | setattr(Question, key, lambda self, value, key=key: self._set(key, value)) 283 | 284 | # Here we define automatically methods to get values from Question fields 285 | for key in dict_default_question_moodle().keys(): 286 | if key is not "answer": # could be misinterpreted with Question.dict["answer"] 287 | setattr(Question, "get_"+strtools.alias(key), lambda self, key=key: self.structure[key]['value'] ) 288 | setattr(Question, "get_"+key, lambda self, key=key: self.structure[key]['value'] ) 289 | 290 | #################################### 291 | ## CLASS : ANSWER 292 | #################################### 293 | 294 | class Answer(): 295 | """ 296 | Object collecting an answer to a multichoice Question 297 | """ 298 | def __init__(self, answer_text="This is a default answer", grade=0.0): 299 | self.structure = { 300 | 'text' : answer_text, 301 | 'relativegrade' : strtools.filter_grade(grade), 302 | 'feedback' : "" 303 | } 304 | self.dict = {} 305 | 306 | # SET FIELDS 307 | def text(self, text): 308 | self.structure['text'] = text 309 | 310 | def relativegrade(self, grade): # must be a number contained in the list 'ACCEPTED_GRADES' in string_manger.py, or a bool (see the doc). 311 | self.structure['relativegrade'] = strtools.filter_grade(grade) 312 | 313 | def feedback(self, text): 314 | self.structure['feedback'] = text 315 | 316 | def istrue(self): # Says that this answer is THE good one 317 | self.relativegrade(100) 318 | 319 | def isfalse(self): # Says that this answer is not good 320 | self.relativegrade(0) 321 | 322 | # GET FIELDS 323 | def get_text(self): 324 | return self.structure['text'] 325 | 326 | def get_relativegrade(self): 327 | return self.structure['relativegrade'] 328 | 329 | def get_feedback(self): 330 | return self.structure['feedback'] 331 | 332 | # OTHER METHODS 333 | def compilation(self): # prepares the Answer by creating a dict 334 | self.dict = { 335 | '@fraction': self.structure['relativegrade'], 336 | '@format': 'html', 337 | 'text': strtools.html(self.structure['text']), 338 | 'feedback': { 339 | '@format': 'html', 340 | 'text': strtools.html(self.structure['feedback']) 341 | } 342 | } 343 | 344 | def addto(self, question): # includes the answer into a question, do some checks before. 345 | self.compilation() 346 | if question.structure['@type']['value'] != "multichoice": 347 | raise ValueError("Answers can only be added to a Question of type : multichoice. This can be set with the method Question.type('multichoice')") 348 | else: 349 | question.structure["answer"]["isset"] = True 350 | question.structure["answer"]["list"].append(self) 351 | if question.cumulated_grade_correct() > 100: 352 | raise ValueError("In this Question the sum of relative grades/percentages of the correct answers appears to be >100.") 353 | 354 | 355 | #################################### 356 | ## global functionalities 357 | #################################### 358 | 359 | def gather_questions(name=None): 360 | # Dependency : COPY 361 | # Look for all the objects of the class Question ever created 362 | # and gather them in a Category 363 | # I'm not sure going through global variables is the best but it seems to work so far 364 | # Doesn't work if the questions are defined inside a loop so.... 365 | category = Category(name) 366 | import __main__ # ok thats shameful but it works. So far. Seems fragile though 367 | current_vars = copy.copy(vars(__main__)) # gets the global variables where the questions should be 368 | question_list = [] 369 | for stuff in current_vars.values(): # there is a huge bunch of stuff here 370 | if isinstance(stuff, Question): 371 | if stuff not in question_list: 372 | question_list.append(stuff) 373 | stuff.addto(category) 374 | return category 375 | 376 | def no_category_name_warning(): 377 | logging.warning("Beware, you are exporting some question(s) without specifying a name for the category gathering them. If you want to avoid a default name, you can simply pass an argument to this function, something like : name='the name of my category' ") 378 | 379 | def savexml(name=None): 380 | if name is None: 381 | no_category_name_warning() 382 | gather_questions(name).savexml() 383 | 384 | def savetex(name=None): 385 | if name is None: 386 | no_category_name_warning() 387 | gather_questions(name).savetex() 388 | 389 | def savepdf(name=None): 390 | if name is None: 391 | no_category_name_warning() 392 | gather_questions(name).savepdf() 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | -------------------------------------------------------------------------------- /moodlexport/string_manager.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from xml.dom.minidom import parseString 3 | from xml.sax.saxutils import unescape 4 | import io 5 | import base64 6 | 7 | from bs4 import BeautifulSoup 8 | from TexSoup import TexSoup 9 | import numpy as np 10 | 11 | 12 | #################################### 13 | ## GLOBAL CONSTANTS 14 | #################################### 15 | 16 | # Dirty but needed : all the fields required to create a question 17 | # We also set their default value, and an alias when the fields has a weird/toolong name 18 | DICT_DEFAULT_QUESTION_MOODLE = { 19 | # general stuff 20 | '@type': {'default': "essay", 21 | 'alias': 'type' 22 | }, # can be "multichoice" for MCQs 23 | "name": {'default': "Question with no title", 24 | 'attribute': {'@format': 'txt'}, 25 | 'alias': 'title' 26 | }, 27 | "questiontext": {'default': "Default question text", 28 | 'attribute': {'@format': 'html'}, 29 | 'alias': 'text' 30 | }, 31 | "generalfeedback": {'default': "", 'attribute': {'@format': 'html'}}, 32 | "defaultgrade": {'default': 1.0, 33 | 'alias': 'grade' 34 | }, 35 | "penalty": {'default': 0.0}, 36 | "hidden": {'default': 0}, 37 | "idnumber": {'default': ""}, 38 | # 'essay' specifics 39 | "responseformat": {'default': "editorfilepicker"}, # by default allow to upload a file as answer. Set "editor" ottherwise 40 | "responserequired": {'default': 0}, # 0 for no response required, 1 for yes 41 | "responsefieldlines": {'default': 10}, 42 | "attachments": {'default': -1}, # number of attachments allowed. -1 is infinty 43 | "attachmentsrequired": {'default': 0}, # 0 for no attachment required, 1 for yes 44 | "graderinfo": {'default': "", # correction for the grader 45 | 'attribute': {'@format': 'html'}, 46 | 'alias': 'infocorrecteur' 47 | }, 48 | "responsetemplate": {'default': "", 'attribute': {'@format': 'html'}}, 49 | # 'multichoice' specifics 50 | "single" : {'default': "true"}, # Says if only a unique answer is possible 51 | "shuffleanswers" : {'default': "true"}, # Constantly shuffles the possible choices 52 | "answernumbering" : {'default': "none"}, # Other choices : 'abc', '123', 'iii', and certainly caps 53 | "correctfeedback": {'default': "Votre réponse est correcte.", 'attribute': {'@format': 'html'}}, 54 | "partiallycorrectfeedback": {'default': "Votre réponse est partiellement correcte.", 'attribute': {'@format': 'html'}}, 55 | "incorrectfeedback": {'default': "Votre réponse est incorrecte.", 'attribute': {'@format': 'html'}}, 56 | "shownumcorrect" : {'default': ""}, # No idea 57 | "answer" : {'default': "", 'list': []} # We deal with this in the Answer class 58 | } 59 | 60 | def dict_default_question_moodle(): 61 | return DICT_DEFAULT_QUESTION_MOODLE 62 | 63 | 64 | # to deal with mess between Latex, python and xml special characters 65 | # \u and \x not supported but useless for inline latex? 66 | UNESCAPE_LATEX = { 67 | '\x07' : '\\a', 68 | '\x0c' : '\\f', 69 | '\x0b' : '\\v', 70 | '\x08' : '\\b', 71 | '\n' : '\\n', 72 | '\r' : '\\r', 73 | '\t' : '\\t' 74 | } 75 | 76 | # we use that dictionary when saving files. We take care of forbidden characters in Windows. 77 | # Also when compiling in latex, spaces (and underscores!? it happened but idk why) can be annoying 78 | UNESCAPE_FILENAME = { 79 | '*' : '', 80 | '.' : '-', 81 | '"' : '', 82 | '/' : '', 83 | '\\' : '', 84 | '[' : '', 85 | ']' : '', 86 | ':' : '-', 87 | ';' : '', 88 | '|' : '', 89 | ' ' : '-', 90 | '_' : '-' 91 | } 92 | 93 | # The list of all legal grades accepted by Moodle 94 | ACCEPTED_GRADES = [-100.0, -90.0, -83.33333, -80.0, -75.0, -70.0, -66.66667, -60.0, -50.0, -50.0, -40.0, -33.33333, -30.0, -25.0, -20.0, -16.66667, -14.28571, -12.5, -11.11111, -10.0, 0.0, 10.0, 11.11111, 12.5, 14.28571, 16.66667, 20.0, 25.0, 30.0, 33.33333, 40.0, 50.0, 50.0, 60.0, 66.66667, 70.0, 75.0, 80.0, 83.33333, 90.0, 100.0] 95 | 96 | 97 | #################################### 98 | ## STRING FUNCTIONS 99 | #################################### 100 | 101 | def alias(field): # easy access to alias 102 | if 'alias' in dict_default_question_moodle()[field]: 103 | return dict_default_question_moodle()[field]['alias'] 104 | else: 105 | return field 106 | 107 | def isfield(string): 108 | for key in dict_default_question_moodle().keys(): 109 | if string in [key, alias(key)]: 110 | return True 111 | return False 112 | 113 | def cleanstr(string, raw=False): 114 | if raw: 115 | string = string.replace('\t','') # no tabs 116 | string = string.replace('\n','') # no linebreak BEWARE this might destroy protected string 117 | else: 118 | string = string.replace('\t',' ') # double space instead of tabs 119 | return string 120 | 121 | def savestr(string, filename="new.txt", raw=False): 122 | string = cleanstr(string, raw) 123 | text_file = io.open(filename, "w", encoding='utf8') # essential for accents and other characters 124 | text_file.write(string) 125 | text_file.close() 126 | 127 | def latex_protect(string): 128 | return unescape(string, UNESCAPE_LATEX) 129 | 130 | def filename_protect(string): # removes forbidden/annoying characters in filenames 131 | return unescape(string, UNESCAPE_FILENAME) 132 | 133 | def html(string): 134 | if string is "": 135 | return string 136 | else: 137 | content = tex_parse_dollar(latex_protect(string)) 138 | if latex_is_here(content): 139 | content = "\(\)" + content # \(\) is a hack to activate latex dans Moodle. Not always needed, not always working. Still a mystery to me. 140 | return "" + content + "

]]>" 141 | 142 | def latex_is_here(string): 143 | # returns a boolean saying wether the string contains common latex chain of characters 144 | # those are either \(, \), \[, \], $$, $, \begin{ 145 | # it seems that if/then is the fastest way to check it : https://stackoverflow.com/questions/5188792/how-to-check-a-string-for-specific-characters 146 | if ('\\(' in string) or ('\\[' in string) or ('\\begin{' in string) or ('$$' in string) or ('$' in string): 147 | return True 148 | else: 149 | return False 150 | 151 | def set_oparg(variable, default_value): #optional argument manager 152 | if variable is None: 153 | return default_value 154 | else: 155 | return variable 156 | 157 | def printmk(*tuple_of_text): 158 | from IPython.display import display, Markdown 159 | L = [Markdown(text) for text in tuple_of_text] 160 | return display(*tuple(L)) 161 | 162 | 163 | def replace_open_close(string, old, newopen, newclose): 164 | # Given a string containing PAIRS of 'old' chains of characters 165 | # replace 'old' with opening/closing chains of characters 166 | oldsize = len(old) 167 | target_idx = [idx for idx in range(len(string)) if string[idx:idx+oldsize] == old] 168 | if len(target_idx) % 2 == 0: 169 | target_open_idx = target_idx[0::2] 170 | target_close_idx = target_idx[1::2] 171 | diff = 0 # controls the difference in size bewtween old and new strings 172 | gap_open = len(newopen) - oldsize 173 | for idx in target_open_idx: 174 | string = string[:idx+diff] + newopen + string[idx+oldsize+diff:] 175 | diff = gap_open + diff 176 | diff = gap_open # we reset but not to zero since there is an already replaced "open" character before the first "close" one 177 | gap_close = len(newclose) - oldsize + gap_open # every time we move forward we accumulate a shit from both "open" and "close" characters 178 | for idx in target_close_idx: 179 | string = string[:idx+diff] + newclose + string[idx+oldsize+diff:] 180 | diff = gap_close + diff 181 | else: 182 | raise ValueError("I have to replace '"+old+"' with *pairs* of characters but I see "+str(len(target_idx))+" of them which is an odd number") 183 | return string 184 | 185 | def tex_parse_dollar(latex): 186 | # Transform a string containing latex expressions to make it compatible with most 187 | # web-based applications which prefer \(...\) or \[...\] syntax. 188 | latex = replace_open_close(latex, '$$', '\\[', '\\]') 189 | latex = replace_open_close(latex, '$', '\\(', '\\)') 190 | return latex 191 | 192 | def clock(utc=0): # returns UTC time (can be shifted) 193 | current_time = datetime.datetime.utcnow() + datetime.timedelta(hours=utc) 194 | return current_time.strftime("%y%m%d %H%M%S") + " UTC" 195 | 196 | 197 | 198 | #----------------------------------------------------- 199 | # Numbers and grades 200 | #----------------------------------------------------- 201 | 202 | def filter_grade(grade): 203 | """ DEPENDENCY : numpy 204 | we manage the default value of grade. 205 | grade can be either a bool (the answer is true (100) or not (0)), 206 | or any int/float value in [-100,100] close enough to Moodle's accepted_values, 207 | or any float value in [-1,1] such that 100*value is close to Moodle's accepted_values. 208 | Here 'close enough' within [-100,100] is arbitrarily set to mean 'up to rounding' 209 | """ 210 | # First we deal with the boolean case 211 | if isinstance(grade, bool) or isinstance(grade, np.bool): 212 | if grade: 213 | return 100.0 214 | else: 215 | return 0.0 216 | # now we deal with the numeric case 217 | else: 218 | grade = float(grade) 219 | if -1 <= grade and grade <= 1 and abs(grade) > 1/100: # we assume a [-1,1] syntax, except 0 or weird super small values 220 | return filter_grade(100*grade) 221 | else: # we expect a [-100,100] syntax 222 | # we check if value is close to an accepted value 223 | for candidate_value in ACCEPTED_GRADES: 224 | if np.floor(candidate_value) <= grade <= np.ceil(candidate_value): 225 | return candidate_value 226 | # no match has been found 227 | raise ValueError('For an answer, the value ' + str(grade) + ' for a (relative) grade is not accepted by Moodle. Accepted values are '+ str(ACCEPTED_VALUES)) 228 | 229 | 230 | 231 | """ 232 | This was INDECENTLY SLOW. Like 1 full second to convert an empty string????? 233 | I couldn't make any parser to work properly. In the end I hard coded it myself. 234 | It is quite fast now (10000 calls/second), and more robust (allows for newlines etc). 235 | 236 | # Taken from https://gist.github.com/erezsh/1f834f7d203cb1ac89b5b3aa877fa634 237 | 238 | class T(Transformer): 239 | def mathmode_offset(self, children): 240 | return '\\[' + ''.join(children[1:-1]) + '\\]' 241 | 242 | def mathmode_inline(self, children): 243 | return '\\(' + ''.join(children[1:-1]) + '\\)' 244 | 245 | def tex(self, children): 246 | return ''.join(children) 247 | 248 | def tex_parse_dollar(string): 249 | lark = Lark(r''' 250 | tex: (mathmode_offset | mathmode_inline | TEXT)+ 251 | mathmode_offset: OFFSETDOLLAR TEXT+ OFFSETDOLLAR | OFFSETOPEN TEXT+ OFFSETCLOSE 252 | mathmode_inline: INLINEOPEN TEXT+ INLINECLOSE | INLINE TEXT+ INLINE 253 | INLINE: "$" 254 | INLINEOPEN: "\\(" 255 | INLINECLOSE: "\\)" 256 | OFFSETDOLLAR: "$$" 257 | OFFSETOPEN: "\\[" 258 | OFFSETCLOSE: "\\]" 259 | TEXT: /[^\]$]+/s 260 | ''', start='tex', parser='lalr') 261 | return T().transform(lark.parse(string)) # string.replace('\n', '') destroys the protected \\n, we need to be smarter here 262 | """ 263 | 264 | 265 | #----------------------------------------------------- 266 | # Images : python --> html 267 | #----------------------------------------------------- 268 | 269 | def img_to_html64(path, **options): 270 | ''' Given an image path, returns an html string containgin the image in base 64 271 | OPTIONS: 272 | width : int 273 | heigth : int 274 | alt : string (alternative text) 275 | style : 'inline' or 'centered' (default). The latter adds
around the image. 276 | ''' 277 | if 'style' not in options.keys(): 278 | options['style'] = 'centered' 279 | 280 | with open(path, "rb") as img_file: 281 | img64 = base64.b64encode(img_file.read()).decode('utf-8') 282 | imghtml = 'ALT_TEXT' 287 | 288 | if options['style'] == 'inline': 289 | return imghtml 290 | elif options['style'] == 'centered': 291 | return '

' + imghtml + '

' 292 | 293 | def includegraphics(path, **options): 294 | return img_to_html64(path, **options) 295 | 296 | 297 | #----------------------------------------------------- 298 | # Images : python --> latex 299 | #----------------------------------------------------- 300 | 301 | def img64_to_latex(string): 302 | # we assume the input is a string starting with 303 | # and that it has an attribute src="path" 304 | # the function returns a string \includegraphics[options]{path} 305 | parsed_html = BeautifulSoup(string, features="lxml") 306 | dico = parsed_html.find('img').attrs # a dict containing all the attributes of this image tag 307 | latex = '\\includegraphics' 308 | 309 | options = '' 310 | if 'width' in dico.keys(): 311 | options = options + 'width=' + dico['width'] + 'px,' 312 | if 'heigth' in dico.keys(): 313 | options = options + 'heigth=' + dico['heigth'] + 'px,' 314 | if len(options) > 0: 315 | options = '[' + options[:-1] + ']' # we delete the last comma ',' 316 | 317 | latex = latex + options + '{' + dico['origin'] + '}' 318 | 319 | if 'style' in dico.keys() and dico['style'] == 'centered': 320 | latex = '\n\\begin{center}\n ' + latex + '\n\\end{center}\n' 321 | return latex 322 | 323 | def findall(pattern, string): 324 | '''Yields all the positions of the pattern in the string in an iterator''' 325 | i = string.find(pattern) 326 | while i != -1: 327 | yield i 328 | i = string.find(pattern, i+1) 329 | 330 | def html_to_latex(string): 331 | # Input : a string containing eventually html tags 332 | # we pick each of them and convert them into latex instructions 333 | ''' we should deal here with all the html code :
and also the

's ''' 334 | # the breaklines tags 335 | string = string.replace('
','\n\n') 336 | 337 | # the paragraphs tags 338 | # those are introduced in the function img_to_html64 and we know exactly what they look like 339 | string = string.replace('

', '') 340 | string = string.replace('

', '') 341 | 342 | # the image tags 343 | # those are introduced in the function img_to_html64 and and are a bit more complicated to deal with 344 | open_img = list(findall('', idx) for idx in open_img] # list of where the tags get closed 349 | list_img64 = [img64_to_latex(str(tag)) for tag in BeautifulSoup(string, features="lxml").find_all('img')] # list of strings with the tags 350 | nb_tag = len(list_img64) 351 | 352 | latex = string[:open_img[0]] 353 | for k in range(nb_tag-1): # for every tag we add the latexified tag, and the non-tag text following 354 | latex = latex + list_img64[k] + string[close_img[k]+1:open_img[k+1]] 355 | latex = latex + list_img64[nb_tag-1] + string[close_img[nb_tag-1]+1:] 356 | return latex 357 | 358 | #----------------------------------------------------- 359 | # Images : latex --> python 360 | #----------------------------------------------------- 361 | 362 | def option_string_to_dict(string): 363 | # Converts a string like 'a=2, b=3' into a dict { a:2, b:3 } 364 | # taken from https://stackoverflow.com/questions/20263839/python-convert-a-string-to-arguments-list 365 | string = string.replace(' ','') 366 | return dict(e.split('=') for e in string.split(',')) 367 | 368 | def includegraphics_latex_to_html(string, style): 369 | # input : a string containing only one latex command 'includegraphics' 370 | # input : style is 'inline' or 'centered' (see img_to_html64) 371 | # output : an html string containing an image tag 372 | arguments = list(TexSoup(string).find_all('includegraphics'))[0].args 373 | # arguments is a list, containing all the arguments, following the following pattern: 374 | # if there is only the required argument (here the filepath), it has length 1 375 | # if there is also n optional arguments, it has length 2, 376 | if len(arguments) == 1: 377 | path = arguments[0].value 378 | options = {} 379 | elif len(arguments) == 2: 380 | path = arguments[1].value 381 | options = option_string_to_dict(arguments[0].value) 382 | # annoying fix to do because latex wants units like '100px' while html just needs '100' 383 | for key in options.keys(): 384 | options[key] = options[key].replace('px','') 385 | else: 386 | raise ValueError('unknown bug here') 387 | # ok now we have all we need : 388 | options = {**options, 'style' : style } 389 | return img_to_html64(path, **options) 390 | 391 | def convert_centered_images_to_html(latex): 392 | listbegin = list(findall('\\begin{center}', latex)) 393 | listend = list(findall('\\end{center}', latex)) 394 | listend = [idx + 12 for idx in listend] # we have the real end of the block 395 | nb_images = len(listbegin) 396 | if nb_images == 0: 397 | return latex 398 | 399 | output = latex[:listbegin[0]] 400 | for k in range(nb_images-1): 401 | string_image = latex[listbegin[k]:listend[k]+1] 402 | output = output + includegraphics_latex_to_html(string_image, style='centered') + latex[listend[k]+1:listbegin[k+1]] 403 | string_image = latex[listbegin[nb_images-1]:listend[nb_images-1]+1] 404 | output = output + includegraphics_latex_to_html(string_image, style='centered') + latex[listend[nb_images-1]+1:] 405 | return output 406 | 407 | def convert_images_to_html(latex): 408 | latex = convert_centered_images_to_html(latex) 409 | imgopen = list(findall('\\includegraphics', latex)) 410 | imgclose = [latex.find('}', idx) for idx in imgopen] 411 | nb_images = len(imgopen) 412 | if nb_images == 0: 413 | return latex 414 | 415 | output = latex[:imgopen[0]] 416 | for k in range(nb_images-1): 417 | string_image = latex[imgopen[k]:imgclose[k]+1] 418 | output = output + includegraphics_latex_to_html(string_image, style='inline') + latex[imgclose[k]+1:imgopen[k+1]] 419 | string_image = latex[imgopen[nb_images-1]:imgclose[nb_images-1]+1] 420 | output = output + includegraphics_latex_to_html(string_image, style='inline') + latex[imgclose[nb_images-1]+1:] 421 | return output 422 | 423 | def latex_to_html_cleaner(latex): 424 | latex = convert_images_to_html(latex) 425 | latex = latex.replace('\t','') 426 | latex = latex.replace('\n\n','
') 427 | latex = latex.replace('\n','') 428 | return latex 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | -------------------------------------------------------------------------------- /examples/simple_random_question/Number-of-roots-for-a-polynomial.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{amsmath} 3 | \usepackage{amssymb} 4 | \usepackage{graphicx} 5 | \usepackage{latextomoodle} 6 | \begin{document} 7 | \begin{category}[Number of roots for a polynomial] 8 | \begin{question}[multichoice] 9 | \title{Number of roots for a polynomial 1} 10 | The equation $- 3 x^{2} - 3 x - 3=0$ has: 11 | 12 | \answer[0.0]{at least a solution} 13 | \answer[100.0]{no real solution} 14 | 15 | \single{True} 16 | 17 | \end{question} 18 | \begin{question}[multichoice] 19 | \title{Number of roots for a polynomial 2} 20 | The equation $- 3 x^{2} - 3 x - 2=0$ has: 21 | 22 | \answer[0.0]{at least a solution} 23 | \answer[100.0]{no real solution} 24 | 25 | \single{True} 26 | 27 | \end{question} 28 | \begin{question}[multichoice] 29 | \title{Number of roots for a polynomial 3} 30 | The equation $- 3 x^{2} - 3 x - 1=0$ has: 31 | 32 | \answer[0.0]{at least a solution} 33 | \answer[100.0]{no real solution} 34 | 35 | \single{True} 36 | 37 | \end{question} 38 | \begin{question}[multichoice] 39 | \title{Number of roots for a polynomial 4} 40 | The equation $- 3 x^{2} - 3 x + 1=0$ has: 41 | 42 | \answer[100.0]{at least a solution} 43 | \answer[0.0]{no real solution} 44 | 45 | \single{True} 46 | 47 | \end{question} 48 | \begin{question}[multichoice] 49 | \title{Number of roots for a polynomial 5} 50 | The equation $- 3 x^{2} - 3 x + 2=0$ has: 51 | 52 | \answer[100.0]{at least a solution} 53 | \answer[0.0]{no real solution} 54 | 55 | \single{True} 56 | 57 | \end{question} 58 | \begin{question}[multichoice] 59 | \title{Number of roots for a polynomial 6} 60 | The equation $- 3 x^{2} - 3 x + 3=0$ has: 61 | 62 | \answer[100.0]{at least a solution} 63 | \answer[0.0]{no real solution} 64 | 65 | \single{True} 66 | 67 | \end{question} 68 | \begin{question}[multichoice] 69 | \title{Number of roots for a polynomial 7} 70 | The equation $- 3 x^{2} - 2 x - 3=0$ has: 71 | 72 | \answer[0.0]{at least a solution} 73 | \answer[100.0]{no real solution} 74 | 75 | \single{True} 76 | 77 | \end{question} 78 | \begin{question}[multichoice] 79 | \title{Number of roots for a polynomial 8} 80 | The equation $- 3 x^{2} - 2 x - 2=0$ has: 81 | 82 | \answer[0.0]{at least a solution} 83 | \answer[100.0]{no real solution} 84 | 85 | \single{True} 86 | 87 | \end{question} 88 | \begin{question}[multichoice] 89 | \title{Number of roots for a polynomial 9} 90 | The equation $- 3 x^{2} - 2 x - 1=0$ has: 91 | 92 | \answer[0.0]{at least a solution} 93 | \answer[100.0]{no real solution} 94 | 95 | \single{True} 96 | 97 | \end{question} 98 | \begin{question}[multichoice] 99 | \title{Number of roots for a polynomial 10} 100 | The equation $- 3 x^{2} - 2 x + 1=0$ has: 101 | 102 | \answer[100.0]{at least a solution} 103 | \answer[0.0]{no real solution} 104 | 105 | \single{True} 106 | 107 | \end{question} 108 | \begin{question}[multichoice] 109 | \title{Number of roots for a polynomial 11} 110 | The equation $- 3 x^{2} - 2 x + 2=0$ has: 111 | 112 | \answer[100.0]{at least a solution} 113 | \answer[0.0]{no real solution} 114 | 115 | \single{True} 116 | 117 | \end{question} 118 | \begin{question}[multichoice] 119 | \title{Number of roots for a polynomial 12} 120 | The equation $- 3 x^{2} - 2 x + 3=0$ has: 121 | 122 | \answer[100.0]{at least a solution} 123 | \answer[0.0]{no real solution} 124 | 125 | \single{True} 126 | 127 | \end{question} 128 | \begin{question}[multichoice] 129 | \title{Number of roots for a polynomial 13} 130 | The equation $- 3 x^{2} - x - 3=0$ has: 131 | 132 | \answer[0.0]{at least a solution} 133 | \answer[100.0]{no real solution} 134 | 135 | \single{True} 136 | 137 | \end{question} 138 | \begin{question}[multichoice] 139 | \title{Number of roots for a polynomial 14} 140 | The equation $- 3 x^{2} - x - 2=0$ has: 141 | 142 | \answer[0.0]{at least a solution} 143 | \answer[100.0]{no real solution} 144 | 145 | \single{True} 146 | 147 | \end{question} 148 | \begin{question}[multichoice] 149 | \title{Number of roots for a polynomial 15} 150 | The equation $- 3 x^{2} - x - 1=0$ has: 151 | 152 | \answer[0.0]{at least a solution} 153 | \answer[100.0]{no real solution} 154 | 155 | \single{True} 156 | 157 | \end{question} 158 | \begin{question}[multichoice] 159 | \title{Number of roots for a polynomial 16} 160 | The equation $- 3 x^{2} - x + 1=0$ has: 161 | 162 | \answer[100.0]{at least a solution} 163 | \answer[0.0]{no real solution} 164 | 165 | \single{True} 166 | 167 | \end{question} 168 | \begin{question}[multichoice] 169 | \title{Number of roots for a polynomial 17} 170 | The equation $- 3 x^{2} - x + 2=0$ has: 171 | 172 | \answer[100.0]{at least a solution} 173 | \answer[0.0]{no real solution} 174 | 175 | \single{True} 176 | 177 | \end{question} 178 | \begin{question}[multichoice] 179 | \title{Number of roots for a polynomial 18} 180 | The equation $- 3 x^{2} - x + 3=0$ has: 181 | 182 | \answer[100.0]{at least a solution} 183 | \answer[0.0]{no real solution} 184 | 185 | \single{True} 186 | 187 | \end{question} 188 | \begin{question}[multichoice] 189 | \title{Number of roots for a polynomial 19} 190 | The equation $- 3 x^{2} + x - 3=0$ has: 191 | 192 | \answer[0.0]{at least a solution} 193 | \answer[100.0]{no real solution} 194 | 195 | \single{True} 196 | 197 | \end{question} 198 | \begin{question}[multichoice] 199 | \title{Number of roots for a polynomial 20} 200 | The equation $- 3 x^{2} + x - 2=0$ has: 201 | 202 | \answer[0.0]{at least a solution} 203 | \answer[100.0]{no real solution} 204 | 205 | \single{True} 206 | 207 | \end{question} 208 | \begin{question}[multichoice] 209 | \title{Number of roots for a polynomial 21} 210 | The equation $- 3 x^{2} + x - 1=0$ has: 211 | 212 | \answer[0.0]{at least a solution} 213 | \answer[100.0]{no real solution} 214 | 215 | \single{True} 216 | 217 | \end{question} 218 | \begin{question}[multichoice] 219 | \title{Number of roots for a polynomial 22} 220 | The equation $- 3 x^{2} + x + 1=0$ has: 221 | 222 | \answer[100.0]{at least a solution} 223 | \answer[0.0]{no real solution} 224 | 225 | \single{True} 226 | 227 | \end{question} 228 | \begin{question}[multichoice] 229 | \title{Number of roots for a polynomial 23} 230 | The equation $- 3 x^{2} + x + 2=0$ has: 231 | 232 | \answer[100.0]{at least a solution} 233 | \answer[0.0]{no real solution} 234 | 235 | \single{True} 236 | 237 | \end{question} 238 | \begin{question}[multichoice] 239 | \title{Number of roots for a polynomial 24} 240 | The equation $- 3 x^{2} + x + 3=0$ has: 241 | 242 | \answer[100.0]{at least a solution} 243 | \answer[0.0]{no real solution} 244 | 245 | \single{True} 246 | 247 | \end{question} 248 | \begin{question}[multichoice] 249 | \title{Number of roots for a polynomial 25} 250 | The equation $- 3 x^{2} + 2 x - 3=0$ has: 251 | 252 | \answer[0.0]{at least a solution} 253 | \answer[100.0]{no real solution} 254 | 255 | \single{True} 256 | 257 | \end{question} 258 | \begin{question}[multichoice] 259 | \title{Number of roots for a polynomial 26} 260 | The equation $- 3 x^{2} + 2 x - 2=0$ has: 261 | 262 | \answer[0.0]{at least a solution} 263 | \answer[100.0]{no real solution} 264 | 265 | \single{True} 266 | 267 | \end{question} 268 | \begin{question}[multichoice] 269 | \title{Number of roots for a polynomial 27} 270 | The equation $- 3 x^{2} + 2 x - 1=0$ has: 271 | 272 | \answer[0.0]{at least a solution} 273 | \answer[100.0]{no real solution} 274 | 275 | \single{True} 276 | 277 | \end{question} 278 | \begin{question}[multichoice] 279 | \title{Number of roots for a polynomial 28} 280 | The equation $- 3 x^{2} + 2 x + 1=0$ has: 281 | 282 | \answer[100.0]{at least a solution} 283 | \answer[0.0]{no real solution} 284 | 285 | \single{True} 286 | 287 | \end{question} 288 | \begin{question}[multichoice] 289 | \title{Number of roots for a polynomial 29} 290 | The equation $- 3 x^{2} + 2 x + 2=0$ has: 291 | 292 | \answer[100.0]{at least a solution} 293 | \answer[0.0]{no real solution} 294 | 295 | \single{True} 296 | 297 | \end{question} 298 | \begin{question}[multichoice] 299 | \title{Number of roots for a polynomial 30} 300 | The equation $- 3 x^{2} + 2 x + 3=0$ has: 301 | 302 | \answer[100.0]{at least a solution} 303 | \answer[0.0]{no real solution} 304 | 305 | \single{True} 306 | 307 | \end{question} 308 | \begin{question}[multichoice] 309 | \title{Number of roots for a polynomial 31} 310 | The equation $- 3 x^{2} + 3 x - 3=0$ has: 311 | 312 | \answer[0.0]{at least a solution} 313 | \answer[100.0]{no real solution} 314 | 315 | \single{True} 316 | 317 | \end{question} 318 | \begin{question}[multichoice] 319 | \title{Number of roots for a polynomial 32} 320 | The equation $- 3 x^{2} + 3 x - 2=0$ has: 321 | 322 | \answer[0.0]{at least a solution} 323 | \answer[100.0]{no real solution} 324 | 325 | \single{True} 326 | 327 | \end{question} 328 | \begin{question}[multichoice] 329 | \title{Number of roots for a polynomial 33} 330 | The equation $- 3 x^{2} + 3 x - 1=0$ has: 331 | 332 | \answer[0.0]{at least a solution} 333 | \answer[100.0]{no real solution} 334 | 335 | \single{True} 336 | 337 | \end{question} 338 | \begin{question}[multichoice] 339 | \title{Number of roots for a polynomial 34} 340 | The equation $- 3 x^{2} + 3 x + 1=0$ has: 341 | 342 | \answer[100.0]{at least a solution} 343 | \answer[0.0]{no real solution} 344 | 345 | \single{True} 346 | 347 | \end{question} 348 | \begin{question}[multichoice] 349 | \title{Number of roots for a polynomial 35} 350 | The equation $- 3 x^{2} + 3 x + 2=0$ has: 351 | 352 | \answer[100.0]{at least a solution} 353 | \answer[0.0]{no real solution} 354 | 355 | \single{True} 356 | 357 | \end{question} 358 | \begin{question}[multichoice] 359 | \title{Number of roots for a polynomial 36} 360 | The equation $- 3 x^{2} + 3 x + 3=0$ has: 361 | 362 | \answer[100.0]{at least a solution} 363 | \answer[0.0]{no real solution} 364 | 365 | \single{True} 366 | 367 | \end{question} 368 | \begin{question}[multichoice] 369 | \title{Number of roots for a polynomial 37} 370 | The equation $- 2 x^{2} - 3 x - 3=0$ has: 371 | 372 | \answer[0.0]{at least a solution} 373 | \answer[100.0]{no real solution} 374 | 375 | \single{True} 376 | 377 | \end{question} 378 | \begin{question}[multichoice] 379 | \title{Number of roots for a polynomial 38} 380 | The equation $- 2 x^{2} - 3 x - 2=0$ has: 381 | 382 | \answer[0.0]{at least a solution} 383 | \answer[100.0]{no real solution} 384 | 385 | \single{True} 386 | 387 | \end{question} 388 | \begin{question}[multichoice] 389 | \title{Number of roots for a polynomial 39} 390 | The equation $- 2 x^{2} - 3 x - 1=0$ has: 391 | 392 | \answer[100.0]{at least a solution} 393 | \answer[0.0]{no real solution} 394 | 395 | \single{True} 396 | 397 | \end{question} 398 | \begin{question}[multichoice] 399 | \title{Number of roots for a polynomial 40} 400 | The equation $- 2 x^{2} - 3 x + 1=0$ has: 401 | 402 | \answer[100.0]{at least a solution} 403 | \answer[0.0]{no real solution} 404 | 405 | \single{True} 406 | 407 | \end{question} 408 | \begin{question}[multichoice] 409 | \title{Number of roots for a polynomial 41} 410 | The equation $- 2 x^{2} - 3 x + 2=0$ has: 411 | 412 | \answer[100.0]{at least a solution} 413 | \answer[0.0]{no real solution} 414 | 415 | \single{True} 416 | 417 | \end{question} 418 | \begin{question}[multichoice] 419 | \title{Number of roots for a polynomial 42} 420 | The equation $- 2 x^{2} - 3 x + 3=0$ has: 421 | 422 | \answer[100.0]{at least a solution} 423 | \answer[0.0]{no real solution} 424 | 425 | \single{True} 426 | 427 | \end{question} 428 | \begin{question}[multichoice] 429 | \title{Number of roots for a polynomial 43} 430 | The equation $- 2 x^{2} - 2 x - 3=0$ has: 431 | 432 | \answer[0.0]{at least a solution} 433 | \answer[100.0]{no real solution} 434 | 435 | \single{True} 436 | 437 | \end{question} 438 | \begin{question}[multichoice] 439 | \title{Number of roots for a polynomial 44} 440 | The equation $- 2 x^{2} - 2 x - 2=0$ has: 441 | 442 | \answer[0.0]{at least a solution} 443 | \answer[100.0]{no real solution} 444 | 445 | \single{True} 446 | 447 | \end{question} 448 | \begin{question}[multichoice] 449 | \title{Number of roots for a polynomial 45} 450 | The equation $- 2 x^{2} - 2 x - 1=0$ has: 451 | 452 | \answer[0.0]{at least a solution} 453 | \answer[100.0]{no real solution} 454 | 455 | \single{True} 456 | 457 | \end{question} 458 | \begin{question}[multichoice] 459 | \title{Number of roots for a polynomial 46} 460 | The equation $- 2 x^{2} - 2 x + 1=0$ has: 461 | 462 | \answer[100.0]{at least a solution} 463 | \answer[0.0]{no real solution} 464 | 465 | \single{True} 466 | 467 | \end{question} 468 | \begin{question}[multichoice] 469 | \title{Number of roots for a polynomial 47} 470 | The equation $- 2 x^{2} - 2 x + 2=0$ has: 471 | 472 | \answer[100.0]{at least a solution} 473 | \answer[0.0]{no real solution} 474 | 475 | \single{True} 476 | 477 | \end{question} 478 | \begin{question}[multichoice] 479 | \title{Number of roots for a polynomial 48} 480 | The equation $- 2 x^{2} - 2 x + 3=0$ has: 481 | 482 | \answer[100.0]{at least a solution} 483 | \answer[0.0]{no real solution} 484 | 485 | \single{True} 486 | 487 | \end{question} 488 | \begin{question}[multichoice] 489 | \title{Number of roots for a polynomial 49} 490 | The equation $- 2 x^{2} - x - 3=0$ has: 491 | 492 | \answer[0.0]{at least a solution} 493 | \answer[100.0]{no real solution} 494 | 495 | \single{True} 496 | 497 | \end{question} 498 | \begin{question}[multichoice] 499 | \title{Number of roots for a polynomial 50} 500 | The equation $- 2 x^{2} - x - 2=0$ has: 501 | 502 | \answer[0.0]{at least a solution} 503 | \answer[100.0]{no real solution} 504 | 505 | \single{True} 506 | 507 | \end{question} 508 | \begin{question}[multichoice] 509 | \title{Number of roots for a polynomial 51} 510 | The equation $- 2 x^{2} - x - 1=0$ has: 511 | 512 | \answer[0.0]{at least a solution} 513 | \answer[100.0]{no real solution} 514 | 515 | \single{True} 516 | 517 | \end{question} 518 | \begin{question}[multichoice] 519 | \title{Number of roots for a polynomial 52} 520 | The equation $- 2 x^{2} - x + 1=0$ has: 521 | 522 | \answer[100.0]{at least a solution} 523 | \answer[0.0]{no real solution} 524 | 525 | \single{True} 526 | 527 | \end{question} 528 | \begin{question}[multichoice] 529 | \title{Number of roots for a polynomial 53} 530 | The equation $- 2 x^{2} - x + 2=0$ has: 531 | 532 | \answer[100.0]{at least a solution} 533 | \answer[0.0]{no real solution} 534 | 535 | \single{True} 536 | 537 | \end{question} 538 | \begin{question}[multichoice] 539 | \title{Number of roots for a polynomial 54} 540 | The equation $- 2 x^{2} - x + 3=0$ has: 541 | 542 | \answer[100.0]{at least a solution} 543 | \answer[0.0]{no real solution} 544 | 545 | \single{True} 546 | 547 | \end{question} 548 | \begin{question}[multichoice] 549 | \title{Number of roots for a polynomial 55} 550 | The equation $- 2 x^{2} + x - 3=0$ has: 551 | 552 | \answer[0.0]{at least a solution} 553 | \answer[100.0]{no real solution} 554 | 555 | \single{True} 556 | 557 | \end{question} 558 | \begin{question}[multichoice] 559 | \title{Number of roots for a polynomial 56} 560 | The equation $- 2 x^{2} + x - 2=0$ has: 561 | 562 | \answer[0.0]{at least a solution} 563 | \answer[100.0]{no real solution} 564 | 565 | \single{True} 566 | 567 | \end{question} 568 | \begin{question}[multichoice] 569 | \title{Number of roots for a polynomial 57} 570 | The equation $- 2 x^{2} + x - 1=0$ has: 571 | 572 | \answer[0.0]{at least a solution} 573 | \answer[100.0]{no real solution} 574 | 575 | \single{True} 576 | 577 | \end{question} 578 | \begin{question}[multichoice] 579 | \title{Number of roots for a polynomial 58} 580 | The equation $- 2 x^{2} + x + 1=0$ has: 581 | 582 | \answer[100.0]{at least a solution} 583 | \answer[0.0]{no real solution} 584 | 585 | \single{True} 586 | 587 | \end{question} 588 | \begin{question}[multichoice] 589 | \title{Number of roots for a polynomial 59} 590 | The equation $- 2 x^{2} + x + 2=0$ has: 591 | 592 | \answer[100.0]{at least a solution} 593 | \answer[0.0]{no real solution} 594 | 595 | \single{True} 596 | 597 | \end{question} 598 | \begin{question}[multichoice] 599 | \title{Number of roots for a polynomial 60} 600 | The equation $- 2 x^{2} + x + 3=0$ has: 601 | 602 | \answer[100.0]{at least a solution} 603 | \answer[0.0]{no real solution} 604 | 605 | \single{True} 606 | 607 | \end{question} 608 | \begin{question}[multichoice] 609 | \title{Number of roots for a polynomial 61} 610 | The equation $- 2 x^{2} + 2 x - 3=0$ has: 611 | 612 | \answer[0.0]{at least a solution} 613 | \answer[100.0]{no real solution} 614 | 615 | \single{True} 616 | 617 | \end{question} 618 | \begin{question}[multichoice] 619 | \title{Number of roots for a polynomial 62} 620 | The equation $- 2 x^{2} + 2 x - 2=0$ has: 621 | 622 | \answer[0.0]{at least a solution} 623 | \answer[100.0]{no real solution} 624 | 625 | \single{True} 626 | 627 | \end{question} 628 | \begin{question}[multichoice] 629 | \title{Number of roots for a polynomial 63} 630 | The equation $- 2 x^{2} + 2 x - 1=0$ has: 631 | 632 | \answer[0.0]{at least a solution} 633 | \answer[100.0]{no real solution} 634 | 635 | \single{True} 636 | 637 | \end{question} 638 | \begin{question}[multichoice] 639 | \title{Number of roots for a polynomial 64} 640 | The equation $- 2 x^{2} + 2 x + 1=0$ has: 641 | 642 | \answer[100.0]{at least a solution} 643 | \answer[0.0]{no real solution} 644 | 645 | \single{True} 646 | 647 | \end{question} 648 | \begin{question}[multichoice] 649 | \title{Number of roots for a polynomial 65} 650 | The equation $- 2 x^{2} + 2 x + 2=0$ has: 651 | 652 | \answer[100.0]{at least a solution} 653 | \answer[0.0]{no real solution} 654 | 655 | \single{True} 656 | 657 | \end{question} 658 | \begin{question}[multichoice] 659 | \title{Number of roots for a polynomial 66} 660 | The equation $- 2 x^{2} + 2 x + 3=0$ has: 661 | 662 | \answer[100.0]{at least a solution} 663 | \answer[0.0]{no real solution} 664 | 665 | \single{True} 666 | 667 | \end{question} 668 | \begin{question}[multichoice] 669 | \title{Number of roots for a polynomial 67} 670 | The equation $- 2 x^{2} + 3 x - 3=0$ has: 671 | 672 | \answer[0.0]{at least a solution} 673 | \answer[100.0]{no real solution} 674 | 675 | \single{True} 676 | 677 | \end{question} 678 | \begin{question}[multichoice] 679 | \title{Number of roots for a polynomial 68} 680 | The equation $- 2 x^{2} + 3 x - 2=0$ has: 681 | 682 | \answer[0.0]{at least a solution} 683 | \answer[100.0]{no real solution} 684 | 685 | \single{True} 686 | 687 | \end{question} 688 | \begin{question}[multichoice] 689 | \title{Number of roots for a polynomial 69} 690 | The equation $- 2 x^{2} + 3 x - 1=0$ has: 691 | 692 | \answer[100.0]{at least a solution} 693 | \answer[0.0]{no real solution} 694 | 695 | \single{True} 696 | 697 | \end{question} 698 | \begin{question}[multichoice] 699 | \title{Number of roots for a polynomial 70} 700 | The equation $- 2 x^{2} + 3 x + 1=0$ has: 701 | 702 | \answer[100.0]{at least a solution} 703 | \answer[0.0]{no real solution} 704 | 705 | \single{True} 706 | 707 | \end{question} 708 | \begin{question}[multichoice] 709 | \title{Number of roots for a polynomial 71} 710 | The equation $- 2 x^{2} + 3 x + 2=0$ has: 711 | 712 | \answer[100.0]{at least a solution} 713 | \answer[0.0]{no real solution} 714 | 715 | \single{True} 716 | 717 | \end{question} 718 | \begin{question}[multichoice] 719 | \title{Number of roots for a polynomial 72} 720 | The equation $- 2 x^{2} + 3 x + 3=0$ has: 721 | 722 | \answer[100.0]{at least a solution} 723 | \answer[0.0]{no real solution} 724 | 725 | \single{True} 726 | 727 | \end{question} 728 | \begin{question}[multichoice] 729 | \title{Number of roots for a polynomial 73} 730 | The equation $- x^{2} - 3 x - 3=0$ has: 731 | 732 | \answer[0.0]{at least a solution} 733 | \answer[100.0]{no real solution} 734 | 735 | \single{True} 736 | 737 | \end{question} 738 | \begin{question}[multichoice] 739 | \title{Number of roots for a polynomial 74} 740 | The equation $- x^{2} - 3 x - 2=0$ has: 741 | 742 | \answer[100.0]{at least a solution} 743 | \answer[0.0]{no real solution} 744 | 745 | \single{True} 746 | 747 | \end{question} 748 | \begin{question}[multichoice] 749 | \title{Number of roots for a polynomial 75} 750 | The equation $- x^{2} - 3 x - 1=0$ has: 751 | 752 | \answer[100.0]{at least a solution} 753 | \answer[0.0]{no real solution} 754 | 755 | \single{True} 756 | 757 | \end{question} 758 | \begin{question}[multichoice] 759 | \title{Number of roots for a polynomial 76} 760 | The equation $- x^{2} - 3 x + 1=0$ has: 761 | 762 | \answer[100.0]{at least a solution} 763 | \answer[0.0]{no real solution} 764 | 765 | \single{True} 766 | 767 | \end{question} 768 | \begin{question}[multichoice] 769 | \title{Number of roots for a polynomial 77} 770 | The equation $- x^{2} - 3 x + 2=0$ has: 771 | 772 | \answer[100.0]{at least a solution} 773 | \answer[0.0]{no real solution} 774 | 775 | \single{True} 776 | 777 | \end{question} 778 | \begin{question}[multichoice] 779 | \title{Number of roots for a polynomial 78} 780 | The equation $- x^{2} - 3 x + 3=0$ has: 781 | 782 | \answer[100.0]{at least a solution} 783 | \answer[0.0]{no real solution} 784 | 785 | \single{True} 786 | 787 | \end{question} 788 | \begin{question}[multichoice] 789 | \title{Number of roots for a polynomial 79} 790 | The equation $- x^{2} - 2 x - 3=0$ has: 791 | 792 | \answer[0.0]{at least a solution} 793 | \answer[100.0]{no real solution} 794 | 795 | \single{True} 796 | 797 | \end{question} 798 | \begin{question}[multichoice] 799 | \title{Number of roots for a polynomial 80} 800 | The equation $- x^{2} - 2 x - 2=0$ has: 801 | 802 | \answer[0.0]{at least a solution} 803 | \answer[100.0]{no real solution} 804 | 805 | \single{True} 806 | 807 | \end{question} 808 | \begin{question}[multichoice] 809 | \title{Number of roots for a polynomial 81} 810 | The equation $- x^{2} - 2 x - 1=0$ has: 811 | 812 | \answer[0.0]{at least a solution} 813 | \answer[100.0]{no real solution} 814 | 815 | \single{True} 816 | 817 | \end{question} 818 | \begin{question}[multichoice] 819 | \title{Number of roots for a polynomial 82} 820 | The equation $- x^{2} - 2 x + 1=0$ has: 821 | 822 | \answer[100.0]{at least a solution} 823 | \answer[0.0]{no real solution} 824 | 825 | \single{True} 826 | 827 | \end{question} 828 | \begin{question}[multichoice] 829 | \title{Number of roots for a polynomial 83} 830 | The equation $- x^{2} - 2 x + 2=0$ has: 831 | 832 | \answer[100.0]{at least a solution} 833 | \answer[0.0]{no real solution} 834 | 835 | \single{True} 836 | 837 | \end{question} 838 | \begin{question}[multichoice] 839 | \title{Number of roots for a polynomial 84} 840 | The equation $- x^{2} - 2 x + 3=0$ has: 841 | 842 | \answer[100.0]{at least a solution} 843 | \answer[0.0]{no real solution} 844 | 845 | \single{True} 846 | 847 | \end{question} 848 | \begin{question}[multichoice] 849 | \title{Number of roots for a polynomial 85} 850 | The equation $- x^{2} - x - 3=0$ has: 851 | 852 | \answer[0.0]{at least a solution} 853 | \answer[100.0]{no real solution} 854 | 855 | \single{True} 856 | 857 | \end{question} 858 | \begin{question}[multichoice] 859 | \title{Number of roots for a polynomial 86} 860 | The equation $- x^{2} - x - 2=0$ has: 861 | 862 | \answer[0.0]{at least a solution} 863 | \answer[100.0]{no real solution} 864 | 865 | \single{True} 866 | 867 | \end{question} 868 | \begin{question}[multichoice] 869 | \title{Number of roots for a polynomial 87} 870 | The equation $- x^{2} - x - 1=0$ has: 871 | 872 | \answer[0.0]{at least a solution} 873 | \answer[100.0]{no real solution} 874 | 875 | \single{True} 876 | 877 | \end{question} 878 | \begin{question}[multichoice] 879 | \title{Number of roots for a polynomial 88} 880 | The equation $- x^{2} - x + 1=0$ has: 881 | 882 | \answer[100.0]{at least a solution} 883 | \answer[0.0]{no real solution} 884 | 885 | \single{True} 886 | 887 | \end{question} 888 | \begin{question}[multichoice] 889 | \title{Number of roots for a polynomial 89} 890 | The equation $- x^{2} - x + 2=0$ has: 891 | 892 | \answer[100.0]{at least a solution} 893 | \answer[0.0]{no real solution} 894 | 895 | \single{True} 896 | 897 | \end{question} 898 | \begin{question}[multichoice] 899 | \title{Number of roots for a polynomial 90} 900 | The equation $- x^{2} - x + 3=0$ has: 901 | 902 | \answer[100.0]{at least a solution} 903 | \answer[0.0]{no real solution} 904 | 905 | \single{True} 906 | 907 | \end{question} 908 | \begin{question}[multichoice] 909 | \title{Number of roots for a polynomial 91} 910 | The equation $- x^{2} + x - 3=0$ has: 911 | 912 | \answer[0.0]{at least a solution} 913 | \answer[100.0]{no real solution} 914 | 915 | \single{True} 916 | 917 | \end{question} 918 | \begin{question}[multichoice] 919 | \title{Number of roots for a polynomial 92} 920 | The equation $- x^{2} + x - 2=0$ has: 921 | 922 | \answer[0.0]{at least a solution} 923 | \answer[100.0]{no real solution} 924 | 925 | \single{True} 926 | 927 | \end{question} 928 | \begin{question}[multichoice] 929 | \title{Number of roots for a polynomial 93} 930 | The equation $- x^{2} + x - 1=0$ has: 931 | 932 | \answer[0.0]{at least a solution} 933 | \answer[100.0]{no real solution} 934 | 935 | \single{True} 936 | 937 | \end{question} 938 | \begin{question}[multichoice] 939 | \title{Number of roots for a polynomial 94} 940 | The equation $- x^{2} + x + 1=0$ has: 941 | 942 | \answer[100.0]{at least a solution} 943 | \answer[0.0]{no real solution} 944 | 945 | \single{True} 946 | 947 | \end{question} 948 | \begin{question}[multichoice] 949 | \title{Number of roots for a polynomial 95} 950 | The equation $- x^{2} + x + 2=0$ has: 951 | 952 | \answer[100.0]{at least a solution} 953 | \answer[0.0]{no real solution} 954 | 955 | \single{True} 956 | 957 | \end{question} 958 | \begin{question}[multichoice] 959 | \title{Number of roots for a polynomial 96} 960 | The equation $- x^{2} + x + 3=0$ has: 961 | 962 | \answer[100.0]{at least a solution} 963 | \answer[0.0]{no real solution} 964 | 965 | \single{True} 966 | 967 | \end{question} 968 | \begin{question}[multichoice] 969 | \title{Number of roots for a polynomial 97} 970 | The equation $- x^{2} + 2 x - 3=0$ has: 971 | 972 | \answer[0.0]{at least a solution} 973 | \answer[100.0]{no real solution} 974 | 975 | \single{True} 976 | 977 | \end{question} 978 | \begin{question}[multichoice] 979 | \title{Number of roots for a polynomial 98} 980 | The equation $- x^{2} + 2 x - 2=0$ has: 981 | 982 | \answer[0.0]{at least a solution} 983 | \answer[100.0]{no real solution} 984 | 985 | \single{True} 986 | 987 | \end{question} 988 | \begin{question}[multichoice] 989 | \title{Number of roots for a polynomial 99} 990 | The equation $- x^{2} + 2 x - 1=0$ has: 991 | 992 | \answer[0.0]{at least a solution} 993 | \answer[100.0]{no real solution} 994 | 995 | \single{True} 996 | 997 | \end{question} 998 | \begin{question}[multichoice] 999 | \title{Number of roots for a polynomial 100} 1000 | The equation $- x^{2} + 2 x + 1=0$ has: 1001 | 1002 | \answer[100.0]{at least a solution} 1003 | \answer[0.0]{no real solution} 1004 | 1005 | \single{True} 1006 | 1007 | \end{question} 1008 | \begin{question}[multichoice] 1009 | \title{Number of roots for a polynomial 101} 1010 | The equation $- x^{2} + 2 x + 2=0$ has: 1011 | 1012 | \answer[100.0]{at least a solution} 1013 | \answer[0.0]{no real solution} 1014 | 1015 | \single{True} 1016 | 1017 | \end{question} 1018 | \begin{question}[multichoice] 1019 | \title{Number of roots for a polynomial 102} 1020 | The equation $- x^{2} + 2 x + 3=0$ has: 1021 | 1022 | \answer[100.0]{at least a solution} 1023 | \answer[0.0]{no real solution} 1024 | 1025 | \single{True} 1026 | 1027 | \end{question} 1028 | \begin{question}[multichoice] 1029 | \title{Number of roots for a polynomial 103} 1030 | The equation $- x^{2} + 3 x - 3=0$ has: 1031 | 1032 | \answer[0.0]{at least a solution} 1033 | \answer[100.0]{no real solution} 1034 | 1035 | \single{True} 1036 | 1037 | \end{question} 1038 | \begin{question}[multichoice] 1039 | \title{Number of roots for a polynomial 104} 1040 | The equation $- x^{2} + 3 x - 2=0$ has: 1041 | 1042 | \answer[100.0]{at least a solution} 1043 | \answer[0.0]{no real solution} 1044 | 1045 | \single{True} 1046 | 1047 | \end{question} 1048 | \begin{question}[multichoice] 1049 | \title{Number of roots for a polynomial 105} 1050 | The equation $- x^{2} + 3 x - 1=0$ has: 1051 | 1052 | \answer[100.0]{at least a solution} 1053 | \answer[0.0]{no real solution} 1054 | 1055 | \single{True} 1056 | 1057 | \end{question} 1058 | \begin{question}[multichoice] 1059 | \title{Number of roots for a polynomial 106} 1060 | The equation $- x^{2} + 3 x + 1=0$ has: 1061 | 1062 | \answer[100.0]{at least a solution} 1063 | \answer[0.0]{no real solution} 1064 | 1065 | \single{True} 1066 | 1067 | \end{question} 1068 | \begin{question}[multichoice] 1069 | \title{Number of roots for a polynomial 107} 1070 | The equation $- x^{2} + 3 x + 2=0$ has: 1071 | 1072 | \answer[100.0]{at least a solution} 1073 | \answer[0.0]{no real solution} 1074 | 1075 | \single{True} 1076 | 1077 | \end{question} 1078 | \begin{question}[multichoice] 1079 | \title{Number of roots for a polynomial 108} 1080 | The equation $- x^{2} + 3 x + 3=0$ has: 1081 | 1082 | \answer[100.0]{at least a solution} 1083 | \answer[0.0]{no real solution} 1084 | 1085 | \single{True} 1086 | 1087 | \end{question} 1088 | \begin{question}[multichoice] 1089 | \title{Number of roots for a polynomial 109} 1090 | The equation $x^{2} - 3 x - 3=0$ has: 1091 | 1092 | \answer[100.0]{at least a solution} 1093 | \answer[0.0]{no real solution} 1094 | 1095 | \single{True} 1096 | 1097 | \end{question} 1098 | \begin{question}[multichoice] 1099 | \title{Number of roots for a polynomial 110} 1100 | The equation $x^{2} - 3 x - 2=0$ has: 1101 | 1102 | \answer[100.0]{at least a solution} 1103 | \answer[0.0]{no real solution} 1104 | 1105 | \single{True} 1106 | 1107 | \end{question} 1108 | \begin{question}[multichoice] 1109 | \title{Number of roots for a polynomial 111} 1110 | The equation $x^{2} - 3 x - 1=0$ has: 1111 | 1112 | \answer[100.0]{at least a solution} 1113 | \answer[0.0]{no real solution} 1114 | 1115 | \single{True} 1116 | 1117 | \end{question} 1118 | \begin{question}[multichoice] 1119 | \title{Number of roots for a polynomial 112} 1120 | The equation $x^{2} - 3 x + 1=0$ has: 1121 | 1122 | \answer[100.0]{at least a solution} 1123 | \answer[0.0]{no real solution} 1124 | 1125 | \single{True} 1126 | 1127 | \end{question} 1128 | \begin{question}[multichoice] 1129 | \title{Number of roots for a polynomial 113} 1130 | The equation $x^{2} - 3 x + 2=0$ has: 1131 | 1132 | \answer[100.0]{at least a solution} 1133 | \answer[0.0]{no real solution} 1134 | 1135 | \single{True} 1136 | 1137 | \end{question} 1138 | \begin{question}[multichoice] 1139 | \title{Number of roots for a polynomial 114} 1140 | The equation $x^{2} - 3 x + 3=0$ has: 1141 | 1142 | \answer[0.0]{at least a solution} 1143 | \answer[100.0]{no real solution} 1144 | 1145 | \single{True} 1146 | 1147 | \end{question} 1148 | \begin{question}[multichoice] 1149 | \title{Number of roots for a polynomial 115} 1150 | The equation $x^{2} - 2 x - 3=0$ has: 1151 | 1152 | \answer[100.0]{at least a solution} 1153 | \answer[0.0]{no real solution} 1154 | 1155 | \single{True} 1156 | 1157 | \end{question} 1158 | \begin{question}[multichoice] 1159 | \title{Number of roots for a polynomial 116} 1160 | The equation $x^{2} - 2 x - 2=0$ has: 1161 | 1162 | \answer[100.0]{at least a solution} 1163 | \answer[0.0]{no real solution} 1164 | 1165 | \single{True} 1166 | 1167 | \end{question} 1168 | \begin{question}[multichoice] 1169 | \title{Number of roots for a polynomial 117} 1170 | The equation $x^{2} - 2 x - 1=0$ has: 1171 | 1172 | \answer[100.0]{at least a solution} 1173 | \answer[0.0]{no real solution} 1174 | 1175 | \single{True} 1176 | 1177 | \end{question} 1178 | \begin{question}[multichoice] 1179 | \title{Number of roots for a polynomial 118} 1180 | The equation $x^{2} - 2 x + 1=0$ has: 1181 | 1182 | \answer[0.0]{at least a solution} 1183 | \answer[100.0]{no real solution} 1184 | 1185 | \single{True} 1186 | 1187 | \end{question} 1188 | \begin{question}[multichoice] 1189 | \title{Number of roots for a polynomial 119} 1190 | The equation $x^{2} - 2 x + 2=0$ has: 1191 | 1192 | \answer[0.0]{at least a solution} 1193 | \answer[100.0]{no real solution} 1194 | 1195 | \single{True} 1196 | 1197 | \end{question} 1198 | \begin{question}[multichoice] 1199 | \title{Number of roots for a polynomial 120} 1200 | The equation $x^{2} - 2 x + 3=0$ has: 1201 | 1202 | \answer[0.0]{at least a solution} 1203 | \answer[100.0]{no real solution} 1204 | 1205 | \single{True} 1206 | 1207 | \end{question} 1208 | \begin{question}[multichoice] 1209 | \title{Number of roots for a polynomial 121} 1210 | The equation $x^{2} - x - 3=0$ has: 1211 | 1212 | \answer[100.0]{at least a solution} 1213 | \answer[0.0]{no real solution} 1214 | 1215 | \single{True} 1216 | 1217 | \end{question} 1218 | \begin{question}[multichoice] 1219 | \title{Number of roots for a polynomial 122} 1220 | The equation $x^{2} - x - 2=0$ has: 1221 | 1222 | \answer[100.0]{at least a solution} 1223 | \answer[0.0]{no real solution} 1224 | 1225 | \single{True} 1226 | 1227 | \end{question} 1228 | \begin{question}[multichoice] 1229 | \title{Number of roots for a polynomial 123} 1230 | The equation $x^{2} - x - 1=0$ has: 1231 | 1232 | \answer[100.0]{at least a solution} 1233 | \answer[0.0]{no real solution} 1234 | 1235 | \single{True} 1236 | 1237 | \end{question} 1238 | \begin{question}[multichoice] 1239 | \title{Number of roots for a polynomial 124} 1240 | The equation $x^{2} - x + 1=0$ has: 1241 | 1242 | \answer[0.0]{at least a solution} 1243 | \answer[100.0]{no real solution} 1244 | 1245 | \single{True} 1246 | 1247 | \end{question} 1248 | \begin{question}[multichoice] 1249 | \title{Number of roots for a polynomial 125} 1250 | The equation $x^{2} - x + 2=0$ has: 1251 | 1252 | \answer[0.0]{at least a solution} 1253 | \answer[100.0]{no real solution} 1254 | 1255 | \single{True} 1256 | 1257 | \end{question} 1258 | \begin{question}[multichoice] 1259 | \title{Number of roots for a polynomial 126} 1260 | The equation $x^{2} - x + 3=0$ has: 1261 | 1262 | \answer[0.0]{at least a solution} 1263 | \answer[100.0]{no real solution} 1264 | 1265 | \single{True} 1266 | 1267 | \end{question} 1268 | \begin{question}[multichoice] 1269 | \title{Number of roots for a polynomial 127} 1270 | The equation $x^{2} + x - 3=0$ has: 1271 | 1272 | \answer[100.0]{at least a solution} 1273 | \answer[0.0]{no real solution} 1274 | 1275 | \single{True} 1276 | 1277 | \end{question} 1278 | \begin{question}[multichoice] 1279 | \title{Number of roots for a polynomial 128} 1280 | The equation $x^{2} + x - 2=0$ has: 1281 | 1282 | \answer[100.0]{at least a solution} 1283 | \answer[0.0]{no real solution} 1284 | 1285 | \single{True} 1286 | 1287 | \end{question} 1288 | \begin{question}[multichoice] 1289 | \title{Number of roots for a polynomial 129} 1290 | The equation $x^{2} + x - 1=0$ has: 1291 | 1292 | \answer[100.0]{at least a solution} 1293 | \answer[0.0]{no real solution} 1294 | 1295 | \single{True} 1296 | 1297 | \end{question} 1298 | \begin{question}[multichoice] 1299 | \title{Number of roots for a polynomial 130} 1300 | The equation $x^{2} + x + 1=0$ has: 1301 | 1302 | \answer[0.0]{at least a solution} 1303 | \answer[100.0]{no real solution} 1304 | 1305 | \single{True} 1306 | 1307 | \end{question} 1308 | \begin{question}[multichoice] 1309 | \title{Number of roots for a polynomial 131} 1310 | The equation $x^{2} + x + 2=0$ has: 1311 | 1312 | \answer[0.0]{at least a solution} 1313 | \answer[100.0]{no real solution} 1314 | 1315 | \single{True} 1316 | 1317 | \end{question} 1318 | \begin{question}[multichoice] 1319 | \title{Number of roots for a polynomial 132} 1320 | The equation $x^{2} + x + 3=0$ has: 1321 | 1322 | \answer[0.0]{at least a solution} 1323 | \answer[100.0]{no real solution} 1324 | 1325 | \single{True} 1326 | 1327 | \end{question} 1328 | \begin{question}[multichoice] 1329 | \title{Number of roots for a polynomial 133} 1330 | The equation $x^{2} + 2 x - 3=0$ has: 1331 | 1332 | \answer[100.0]{at least a solution} 1333 | \answer[0.0]{no real solution} 1334 | 1335 | \single{True} 1336 | 1337 | \end{question} 1338 | \begin{question}[multichoice] 1339 | \title{Number of roots for a polynomial 134} 1340 | The equation $x^{2} + 2 x - 2=0$ has: 1341 | 1342 | \answer[100.0]{at least a solution} 1343 | \answer[0.0]{no real solution} 1344 | 1345 | \single{True} 1346 | 1347 | \end{question} 1348 | \begin{question}[multichoice] 1349 | \title{Number of roots for a polynomial 135} 1350 | The equation $x^{2} + 2 x - 1=0$ has: 1351 | 1352 | \answer[100.0]{at least a solution} 1353 | \answer[0.0]{no real solution} 1354 | 1355 | \single{True} 1356 | 1357 | \end{question} 1358 | \begin{question}[multichoice] 1359 | \title{Number of roots for a polynomial 136} 1360 | The equation $x^{2} + 2 x + 1=0$ has: 1361 | 1362 | \answer[0.0]{at least a solution} 1363 | \answer[100.0]{no real solution} 1364 | 1365 | \single{True} 1366 | 1367 | \end{question} 1368 | \begin{question}[multichoice] 1369 | \title{Number of roots for a polynomial 137} 1370 | The equation $x^{2} + 2 x + 2=0$ has: 1371 | 1372 | \answer[0.0]{at least a solution} 1373 | \answer[100.0]{no real solution} 1374 | 1375 | \single{True} 1376 | 1377 | \end{question} 1378 | \begin{question}[multichoice] 1379 | \title{Number of roots for a polynomial 138} 1380 | The equation $x^{2} + 2 x + 3=0$ has: 1381 | 1382 | \answer[0.0]{at least a solution} 1383 | \answer[100.0]{no real solution} 1384 | 1385 | \single{True} 1386 | 1387 | \end{question} 1388 | \begin{question}[multichoice] 1389 | \title{Number of roots for a polynomial 139} 1390 | The equation $x^{2} + 3 x - 3=0$ has: 1391 | 1392 | \answer[100.0]{at least a solution} 1393 | \answer[0.0]{no real solution} 1394 | 1395 | \single{True} 1396 | 1397 | \end{question} 1398 | \begin{question}[multichoice] 1399 | \title{Number of roots for a polynomial 140} 1400 | The equation $x^{2} + 3 x - 2=0$ has: 1401 | 1402 | \answer[100.0]{at least a solution} 1403 | \answer[0.0]{no real solution} 1404 | 1405 | \single{True} 1406 | 1407 | \end{question} 1408 | \begin{question}[multichoice] 1409 | \title{Number of roots for a polynomial 141} 1410 | The equation $x^{2} + 3 x - 1=0$ has: 1411 | 1412 | \answer[100.0]{at least a solution} 1413 | \answer[0.0]{no real solution} 1414 | 1415 | \single{True} 1416 | 1417 | \end{question} 1418 | \begin{question}[multichoice] 1419 | \title{Number of roots for a polynomial 142} 1420 | The equation $x^{2} + 3 x + 1=0$ has: 1421 | 1422 | \answer[100.0]{at least a solution} 1423 | \answer[0.0]{no real solution} 1424 | 1425 | \single{True} 1426 | 1427 | \end{question} 1428 | \begin{question}[multichoice] 1429 | \title{Number of roots for a polynomial 143} 1430 | The equation $x^{2} + 3 x + 2=0$ has: 1431 | 1432 | \answer[100.0]{at least a solution} 1433 | \answer[0.0]{no real solution} 1434 | 1435 | \single{True} 1436 | 1437 | \end{question} 1438 | \begin{question}[multichoice] 1439 | \title{Number of roots for a polynomial 144} 1440 | The equation $x^{2} + 3 x + 3=0$ has: 1441 | 1442 | \answer[0.0]{at least a solution} 1443 | \answer[100.0]{no real solution} 1444 | 1445 | \single{True} 1446 | 1447 | \end{question} 1448 | \begin{question}[multichoice] 1449 | \title{Number of roots for a polynomial 145} 1450 | The equation $2 x^{2} - 3 x - 3=0$ has: 1451 | 1452 | \answer[100.0]{at least a solution} 1453 | \answer[0.0]{no real solution} 1454 | 1455 | \single{True} 1456 | 1457 | \end{question} 1458 | \begin{question}[multichoice] 1459 | \title{Number of roots for a polynomial 146} 1460 | The equation $2 x^{2} - 3 x - 2=0$ has: 1461 | 1462 | \answer[100.0]{at least a solution} 1463 | \answer[0.0]{no real solution} 1464 | 1465 | \single{True} 1466 | 1467 | \end{question} 1468 | \begin{question}[multichoice] 1469 | \title{Number of roots for a polynomial 147} 1470 | The equation $2 x^{2} - 3 x - 1=0$ has: 1471 | 1472 | \answer[100.0]{at least a solution} 1473 | \answer[0.0]{no real solution} 1474 | 1475 | \single{True} 1476 | 1477 | \end{question} 1478 | \begin{question}[multichoice] 1479 | \title{Number of roots for a polynomial 148} 1480 | The equation $2 x^{2} - 3 x + 1=0$ has: 1481 | 1482 | \answer[100.0]{at least a solution} 1483 | \answer[0.0]{no real solution} 1484 | 1485 | \single{True} 1486 | 1487 | \end{question} 1488 | \begin{question}[multichoice] 1489 | \title{Number of roots for a polynomial 149} 1490 | The equation $2 x^{2} - 3 x + 2=0$ has: 1491 | 1492 | \answer[0.0]{at least a solution} 1493 | \answer[100.0]{no real solution} 1494 | 1495 | \single{True} 1496 | 1497 | \end{question} 1498 | \begin{question}[multichoice] 1499 | \title{Number of roots for a polynomial 150} 1500 | The equation $2 x^{2} - 3 x + 3=0$ has: 1501 | 1502 | \answer[0.0]{at least a solution} 1503 | \answer[100.0]{no real solution} 1504 | 1505 | \single{True} 1506 | 1507 | \end{question} 1508 | \begin{question}[multichoice] 1509 | \title{Number of roots for a polynomial 151} 1510 | The equation $2 x^{2} - 2 x - 3=0$ has: 1511 | 1512 | \answer[100.0]{at least a solution} 1513 | \answer[0.0]{no real solution} 1514 | 1515 | \single{True} 1516 | 1517 | \end{question} 1518 | \begin{question}[multichoice] 1519 | \title{Number of roots for a polynomial 152} 1520 | The equation $2 x^{2} - 2 x - 2=0$ has: 1521 | 1522 | \answer[100.0]{at least a solution} 1523 | \answer[0.0]{no real solution} 1524 | 1525 | \single{True} 1526 | 1527 | \end{question} 1528 | \begin{question}[multichoice] 1529 | \title{Number of roots for a polynomial 153} 1530 | The equation $2 x^{2} - 2 x - 1=0$ has: 1531 | 1532 | \answer[100.0]{at least a solution} 1533 | \answer[0.0]{no real solution} 1534 | 1535 | \single{True} 1536 | 1537 | \end{question} 1538 | \begin{question}[multichoice] 1539 | \title{Number of roots for a polynomial 154} 1540 | The equation $2 x^{2} - 2 x + 1=0$ has: 1541 | 1542 | \answer[0.0]{at least a solution} 1543 | \answer[100.0]{no real solution} 1544 | 1545 | \single{True} 1546 | 1547 | \end{question} 1548 | \begin{question}[multichoice] 1549 | \title{Number of roots for a polynomial 155} 1550 | The equation $2 x^{2} - 2 x + 2=0$ has: 1551 | 1552 | \answer[0.0]{at least a solution} 1553 | \answer[100.0]{no real solution} 1554 | 1555 | \single{True} 1556 | 1557 | \end{question} 1558 | \begin{question}[multichoice] 1559 | \title{Number of roots for a polynomial 156} 1560 | The equation $2 x^{2} - 2 x + 3=0$ has: 1561 | 1562 | \answer[0.0]{at least a solution} 1563 | \answer[100.0]{no real solution} 1564 | 1565 | \single{True} 1566 | 1567 | \end{question} 1568 | \begin{question}[multichoice] 1569 | \title{Number of roots for a polynomial 157} 1570 | The equation $2 x^{2} - x - 3=0$ has: 1571 | 1572 | \answer[100.0]{at least a solution} 1573 | \answer[0.0]{no real solution} 1574 | 1575 | \single{True} 1576 | 1577 | \end{question} 1578 | \begin{question}[multichoice] 1579 | \title{Number of roots for a polynomial 158} 1580 | The equation $2 x^{2} - x - 2=0$ has: 1581 | 1582 | \answer[100.0]{at least a solution} 1583 | \answer[0.0]{no real solution} 1584 | 1585 | \single{True} 1586 | 1587 | \end{question} 1588 | \begin{question}[multichoice] 1589 | \title{Number of roots for a polynomial 159} 1590 | The equation $2 x^{2} - x - 1=0$ has: 1591 | 1592 | \answer[100.0]{at least a solution} 1593 | \answer[0.0]{no real solution} 1594 | 1595 | \single{True} 1596 | 1597 | \end{question} 1598 | \begin{question}[multichoice] 1599 | \title{Number of roots for a polynomial 160} 1600 | The equation $2 x^{2} - x + 1=0$ has: 1601 | 1602 | \answer[0.0]{at least a solution} 1603 | \answer[100.0]{no real solution} 1604 | 1605 | \single{True} 1606 | 1607 | \end{question} 1608 | \begin{question}[multichoice] 1609 | \title{Number of roots for a polynomial 161} 1610 | The equation $2 x^{2} - x + 2=0$ has: 1611 | 1612 | \answer[0.0]{at least a solution} 1613 | \answer[100.0]{no real solution} 1614 | 1615 | \single{True} 1616 | 1617 | \end{question} 1618 | \begin{question}[multichoice] 1619 | \title{Number of roots for a polynomial 162} 1620 | The equation $2 x^{2} - x + 3=0$ has: 1621 | 1622 | \answer[0.0]{at least a solution} 1623 | \answer[100.0]{no real solution} 1624 | 1625 | \single{True} 1626 | 1627 | \end{question} 1628 | \begin{question}[multichoice] 1629 | \title{Number of roots for a polynomial 163} 1630 | The equation $2 x^{2} + x - 3=0$ has: 1631 | 1632 | \answer[100.0]{at least a solution} 1633 | \answer[0.0]{no real solution} 1634 | 1635 | \single{True} 1636 | 1637 | \end{question} 1638 | \begin{question}[multichoice] 1639 | \title{Number of roots for a polynomial 164} 1640 | The equation $2 x^{2} + x - 2=0$ has: 1641 | 1642 | \answer[100.0]{at least a solution} 1643 | \answer[0.0]{no real solution} 1644 | 1645 | \single{True} 1646 | 1647 | \end{question} 1648 | \begin{question}[multichoice] 1649 | \title{Number of roots for a polynomial 165} 1650 | The equation $2 x^{2} + x - 1=0$ has: 1651 | 1652 | \answer[100.0]{at least a solution} 1653 | \answer[0.0]{no real solution} 1654 | 1655 | \single{True} 1656 | 1657 | \end{question} 1658 | \begin{question}[multichoice] 1659 | \title{Number of roots for a polynomial 166} 1660 | The equation $2 x^{2} + x + 1=0$ has: 1661 | 1662 | \answer[0.0]{at least a solution} 1663 | \answer[100.0]{no real solution} 1664 | 1665 | \single{True} 1666 | 1667 | \end{question} 1668 | \begin{question}[multichoice] 1669 | \title{Number of roots for a polynomial 167} 1670 | The equation $2 x^{2} + x + 2=0$ has: 1671 | 1672 | \answer[0.0]{at least a solution} 1673 | \answer[100.0]{no real solution} 1674 | 1675 | \single{True} 1676 | 1677 | \end{question} 1678 | \begin{question}[multichoice] 1679 | \title{Number of roots for a polynomial 168} 1680 | The equation $2 x^{2} + x + 3=0$ has: 1681 | 1682 | \answer[0.0]{at least a solution} 1683 | \answer[100.0]{no real solution} 1684 | 1685 | \single{True} 1686 | 1687 | \end{question} 1688 | \begin{question}[multichoice] 1689 | \title{Number of roots for a polynomial 169} 1690 | The equation $2 x^{2} + 2 x - 3=0$ has: 1691 | 1692 | \answer[100.0]{at least a solution} 1693 | \answer[0.0]{no real solution} 1694 | 1695 | \single{True} 1696 | 1697 | \end{question} 1698 | \begin{question}[multichoice] 1699 | \title{Number of roots for a polynomial 170} 1700 | The equation $2 x^{2} + 2 x - 2=0$ has: 1701 | 1702 | \answer[100.0]{at least a solution} 1703 | \answer[0.0]{no real solution} 1704 | 1705 | \single{True} 1706 | 1707 | \end{question} 1708 | \begin{question}[multichoice] 1709 | \title{Number of roots for a polynomial 171} 1710 | The equation $2 x^{2} + 2 x - 1=0$ has: 1711 | 1712 | \answer[100.0]{at least a solution} 1713 | \answer[0.0]{no real solution} 1714 | 1715 | \single{True} 1716 | 1717 | \end{question} 1718 | \begin{question}[multichoice] 1719 | \title{Number of roots for a polynomial 172} 1720 | The equation $2 x^{2} + 2 x + 1=0$ has: 1721 | 1722 | \answer[0.0]{at least a solution} 1723 | \answer[100.0]{no real solution} 1724 | 1725 | \single{True} 1726 | 1727 | \end{question} 1728 | \begin{question}[multichoice] 1729 | \title{Number of roots for a polynomial 173} 1730 | The equation $2 x^{2} + 2 x + 2=0$ has: 1731 | 1732 | \answer[0.0]{at least a solution} 1733 | \answer[100.0]{no real solution} 1734 | 1735 | \single{True} 1736 | 1737 | \end{question} 1738 | \begin{question}[multichoice] 1739 | \title{Number of roots for a polynomial 174} 1740 | The equation $2 x^{2} + 2 x + 3=0$ has: 1741 | 1742 | \answer[0.0]{at least a solution} 1743 | \answer[100.0]{no real solution} 1744 | 1745 | \single{True} 1746 | 1747 | \end{question} 1748 | \begin{question}[multichoice] 1749 | \title{Number of roots for a polynomial 175} 1750 | The equation $2 x^{2} + 3 x - 3=0$ has: 1751 | 1752 | \answer[100.0]{at least a solution} 1753 | \answer[0.0]{no real solution} 1754 | 1755 | \single{True} 1756 | 1757 | \end{question} 1758 | \begin{question}[multichoice] 1759 | \title{Number of roots for a polynomial 176} 1760 | The equation $2 x^{2} + 3 x - 2=0$ has: 1761 | 1762 | \answer[100.0]{at least a solution} 1763 | \answer[0.0]{no real solution} 1764 | 1765 | \single{True} 1766 | 1767 | \end{question} 1768 | \begin{question}[multichoice] 1769 | \title{Number of roots for a polynomial 177} 1770 | The equation $2 x^{2} + 3 x - 1=0$ has: 1771 | 1772 | \answer[100.0]{at least a solution} 1773 | \answer[0.0]{no real solution} 1774 | 1775 | \single{True} 1776 | 1777 | \end{question} 1778 | \begin{question}[multichoice] 1779 | \title{Number of roots for a polynomial 178} 1780 | The equation $2 x^{2} + 3 x + 1=0$ has: 1781 | 1782 | \answer[100.0]{at least a solution} 1783 | \answer[0.0]{no real solution} 1784 | 1785 | \single{True} 1786 | 1787 | \end{question} 1788 | \begin{question}[multichoice] 1789 | \title{Number of roots for a polynomial 179} 1790 | The equation $2 x^{2} + 3 x + 2=0$ has: 1791 | 1792 | \answer[0.0]{at least a solution} 1793 | \answer[100.0]{no real solution} 1794 | 1795 | \single{True} 1796 | 1797 | \end{question} 1798 | \begin{question}[multichoice] 1799 | \title{Number of roots for a polynomial 180} 1800 | The equation $2 x^{2} + 3 x + 3=0$ has: 1801 | 1802 | \answer[0.0]{at least a solution} 1803 | \answer[100.0]{no real solution} 1804 | 1805 | \single{True} 1806 | 1807 | \end{question} 1808 | \begin{question}[multichoice] 1809 | \title{Number of roots for a polynomial 181} 1810 | The equation $3 x^{2} - 3 x - 3=0$ has: 1811 | 1812 | \answer[100.0]{at least a solution} 1813 | \answer[0.0]{no real solution} 1814 | 1815 | \single{True} 1816 | 1817 | \end{question} 1818 | \begin{question}[multichoice] 1819 | \title{Number of roots for a polynomial 182} 1820 | The equation $3 x^{2} - 3 x - 2=0$ has: 1821 | 1822 | \answer[100.0]{at least a solution} 1823 | \answer[0.0]{no real solution} 1824 | 1825 | \single{True} 1826 | 1827 | \end{question} 1828 | \begin{question}[multichoice] 1829 | \title{Number of roots for a polynomial 183} 1830 | The equation $3 x^{2} - 3 x - 1=0$ has: 1831 | 1832 | \answer[100.0]{at least a solution} 1833 | \answer[0.0]{no real solution} 1834 | 1835 | \single{True} 1836 | 1837 | \end{question} 1838 | \begin{question}[multichoice] 1839 | \title{Number of roots for a polynomial 184} 1840 | The equation $3 x^{2} - 3 x + 1=0$ has: 1841 | 1842 | \answer[0.0]{at least a solution} 1843 | \answer[100.0]{no real solution} 1844 | 1845 | \single{True} 1846 | 1847 | \end{question} 1848 | \begin{question}[multichoice] 1849 | \title{Number of roots for a polynomial 185} 1850 | The equation $3 x^{2} - 3 x + 2=0$ has: 1851 | 1852 | \answer[0.0]{at least a solution} 1853 | \answer[100.0]{no real solution} 1854 | 1855 | \single{True} 1856 | 1857 | \end{question} 1858 | \begin{question}[multichoice] 1859 | \title{Number of roots for a polynomial 186} 1860 | The equation $3 x^{2} - 3 x + 3=0$ has: 1861 | 1862 | \answer[0.0]{at least a solution} 1863 | \answer[100.0]{no real solution} 1864 | 1865 | \single{True} 1866 | 1867 | \end{question} 1868 | \begin{question}[multichoice] 1869 | \title{Number of roots for a polynomial 187} 1870 | The equation $3 x^{2} - 2 x - 3=0$ has: 1871 | 1872 | \answer[100.0]{at least a solution} 1873 | \answer[0.0]{no real solution} 1874 | 1875 | \single{True} 1876 | 1877 | \end{question} 1878 | \begin{question}[multichoice] 1879 | \title{Number of roots for a polynomial 188} 1880 | The equation $3 x^{2} - 2 x - 2=0$ has: 1881 | 1882 | \answer[100.0]{at least a solution} 1883 | \answer[0.0]{no real solution} 1884 | 1885 | \single{True} 1886 | 1887 | \end{question} 1888 | \begin{question}[multichoice] 1889 | \title{Number of roots for a polynomial 189} 1890 | The equation $3 x^{2} - 2 x - 1=0$ has: 1891 | 1892 | \answer[100.0]{at least a solution} 1893 | \answer[0.0]{no real solution} 1894 | 1895 | \single{True} 1896 | 1897 | \end{question} 1898 | \begin{question}[multichoice] 1899 | \title{Number of roots for a polynomial 190} 1900 | The equation $3 x^{2} - 2 x + 1=0$ has: 1901 | 1902 | \answer[0.0]{at least a solution} 1903 | \answer[100.0]{no real solution} 1904 | 1905 | \single{True} 1906 | 1907 | \end{question} 1908 | \begin{question}[multichoice] 1909 | \title{Number of roots for a polynomial 191} 1910 | The equation $3 x^{2} - 2 x + 2=0$ has: 1911 | 1912 | \answer[0.0]{at least a solution} 1913 | \answer[100.0]{no real solution} 1914 | 1915 | \single{True} 1916 | 1917 | \end{question} 1918 | \begin{question}[multichoice] 1919 | \title{Number of roots for a polynomial 192} 1920 | The equation $3 x^{2} - 2 x + 3=0$ has: 1921 | 1922 | \answer[0.0]{at least a solution} 1923 | \answer[100.0]{no real solution} 1924 | 1925 | \single{True} 1926 | 1927 | \end{question} 1928 | \begin{question}[multichoice] 1929 | \title{Number of roots for a polynomial 193} 1930 | The equation $3 x^{2} - x - 3=0$ has: 1931 | 1932 | \answer[100.0]{at least a solution} 1933 | \answer[0.0]{no real solution} 1934 | 1935 | \single{True} 1936 | 1937 | \end{question} 1938 | \begin{question}[multichoice] 1939 | \title{Number of roots for a polynomial 194} 1940 | The equation $3 x^{2} - x - 2=0$ has: 1941 | 1942 | \answer[100.0]{at least a solution} 1943 | \answer[0.0]{no real solution} 1944 | 1945 | \single{True} 1946 | 1947 | \end{question} 1948 | \begin{question}[multichoice] 1949 | \title{Number of roots for a polynomial 195} 1950 | The equation $3 x^{2} - x - 1=0$ has: 1951 | 1952 | \answer[100.0]{at least a solution} 1953 | \answer[0.0]{no real solution} 1954 | 1955 | \single{True} 1956 | 1957 | \end{question} 1958 | \begin{question}[multichoice] 1959 | \title{Number of roots for a polynomial 196} 1960 | The equation $3 x^{2} - x + 1=0$ has: 1961 | 1962 | \answer[0.0]{at least a solution} 1963 | \answer[100.0]{no real solution} 1964 | 1965 | \single{True} 1966 | 1967 | \end{question} 1968 | \begin{question}[multichoice] 1969 | \title{Number of roots for a polynomial 197} 1970 | The equation $3 x^{2} - x + 2=0$ has: 1971 | 1972 | \answer[0.0]{at least a solution} 1973 | \answer[100.0]{no real solution} 1974 | 1975 | \single{True} 1976 | 1977 | \end{question} 1978 | \begin{question}[multichoice] 1979 | \title{Number of roots for a polynomial 198} 1980 | The equation $3 x^{2} - x + 3=0$ has: 1981 | 1982 | \answer[0.0]{at least a solution} 1983 | \answer[100.0]{no real solution} 1984 | 1985 | \single{True} 1986 | 1987 | \end{question} 1988 | \begin{question}[multichoice] 1989 | \title{Number of roots for a polynomial 199} 1990 | The equation $3 x^{2} + x - 3=0$ has: 1991 | 1992 | \answer[100.0]{at least a solution} 1993 | \answer[0.0]{no real solution} 1994 | 1995 | \single{True} 1996 | 1997 | \end{question} 1998 | \begin{question}[multichoice] 1999 | \title{Number of roots for a polynomial 200} 2000 | The equation $3 x^{2} + x - 2=0$ has: 2001 | 2002 | \answer[100.0]{at least a solution} 2003 | \answer[0.0]{no real solution} 2004 | 2005 | \single{True} 2006 | 2007 | \end{question} 2008 | \begin{question}[multichoice] 2009 | \title{Number of roots for a polynomial 201} 2010 | The equation $3 x^{2} + x - 1=0$ has: 2011 | 2012 | \answer[100.0]{at least a solution} 2013 | \answer[0.0]{no real solution} 2014 | 2015 | \single{True} 2016 | 2017 | \end{question} 2018 | \begin{question}[multichoice] 2019 | \title{Number of roots for a polynomial 202} 2020 | The equation $3 x^{2} + x + 1=0$ has: 2021 | 2022 | \answer[0.0]{at least a solution} 2023 | \answer[100.0]{no real solution} 2024 | 2025 | \single{True} 2026 | 2027 | \end{question} 2028 | \begin{question}[multichoice] 2029 | \title{Number of roots for a polynomial 203} 2030 | The equation $3 x^{2} + x + 2=0$ has: 2031 | 2032 | \answer[0.0]{at least a solution} 2033 | \answer[100.0]{no real solution} 2034 | 2035 | \single{True} 2036 | 2037 | \end{question} 2038 | \begin{question}[multichoice] 2039 | \title{Number of roots for a polynomial 204} 2040 | The equation $3 x^{2} + x + 3=0$ has: 2041 | 2042 | \answer[0.0]{at least a solution} 2043 | \answer[100.0]{no real solution} 2044 | 2045 | \single{True} 2046 | 2047 | \end{question} 2048 | \begin{question}[multichoice] 2049 | \title{Number of roots for a polynomial 205} 2050 | The equation $3 x^{2} + 2 x - 3=0$ has: 2051 | 2052 | \answer[100.0]{at least a solution} 2053 | \answer[0.0]{no real solution} 2054 | 2055 | \single{True} 2056 | 2057 | \end{question} 2058 | \begin{question}[multichoice] 2059 | \title{Number of roots for a polynomial 206} 2060 | The equation $3 x^{2} + 2 x - 2=0$ has: 2061 | 2062 | \answer[100.0]{at least a solution} 2063 | \answer[0.0]{no real solution} 2064 | 2065 | \single{True} 2066 | 2067 | \end{question} 2068 | \begin{question}[multichoice] 2069 | \title{Number of roots for a polynomial 207} 2070 | The equation $3 x^{2} + 2 x - 1=0$ has: 2071 | 2072 | \answer[100.0]{at least a solution} 2073 | \answer[0.0]{no real solution} 2074 | 2075 | \single{True} 2076 | 2077 | \end{question} 2078 | \begin{question}[multichoice] 2079 | \title{Number of roots for a polynomial 208} 2080 | The equation $3 x^{2} + 2 x + 1=0$ has: 2081 | 2082 | \answer[0.0]{at least a solution} 2083 | \answer[100.0]{no real solution} 2084 | 2085 | \single{True} 2086 | 2087 | \end{question} 2088 | \begin{question}[multichoice] 2089 | \title{Number of roots for a polynomial 209} 2090 | The equation $3 x^{2} + 2 x + 2=0$ has: 2091 | 2092 | \answer[0.0]{at least a solution} 2093 | \answer[100.0]{no real solution} 2094 | 2095 | \single{True} 2096 | 2097 | \end{question} 2098 | \begin{question}[multichoice] 2099 | \title{Number of roots for a polynomial 210} 2100 | The equation $3 x^{2} + 2 x + 3=0$ has: 2101 | 2102 | \answer[0.0]{at least a solution} 2103 | \answer[100.0]{no real solution} 2104 | 2105 | \single{True} 2106 | 2107 | \end{question} 2108 | \begin{question}[multichoice] 2109 | \title{Number of roots for a polynomial 211} 2110 | The equation $3 x^{2} + 3 x - 3=0$ has: 2111 | 2112 | \answer[100.0]{at least a solution} 2113 | \answer[0.0]{no real solution} 2114 | 2115 | \single{True} 2116 | 2117 | \end{question} 2118 | \begin{question}[multichoice] 2119 | \title{Number of roots for a polynomial 212} 2120 | The equation $3 x^{2} + 3 x - 2=0$ has: 2121 | 2122 | \answer[100.0]{at least a solution} 2123 | \answer[0.0]{no real solution} 2124 | 2125 | \single{True} 2126 | 2127 | \end{question} 2128 | \begin{question}[multichoice] 2129 | \title{Number of roots for a polynomial 213} 2130 | The equation $3 x^{2} + 3 x - 1=0$ has: 2131 | 2132 | \answer[100.0]{at least a solution} 2133 | \answer[0.0]{no real solution} 2134 | 2135 | \single{True} 2136 | 2137 | \end{question} 2138 | \begin{question}[multichoice] 2139 | \title{Number of roots for a polynomial 214} 2140 | The equation $3 x^{2} + 3 x + 1=0$ has: 2141 | 2142 | \answer[0.0]{at least a solution} 2143 | \answer[100.0]{no real solution} 2144 | 2145 | \single{True} 2146 | 2147 | \end{question} 2148 | \begin{question}[multichoice] 2149 | \title{Number of roots for a polynomial 215} 2150 | The equation $3 x^{2} + 3 x + 2=0$ has: 2151 | 2152 | \answer[0.0]{at least a solution} 2153 | \answer[100.0]{no real solution} 2154 | 2155 | \single{True} 2156 | 2157 | \end{question} 2158 | \begin{question}[multichoice] 2159 | \title{Number of roots for a polynomial 216} 2160 | The equation $3 x^{2} + 3 x + 3=0$ has: 2161 | 2162 | \answer[0.0]{at least a solution} 2163 | \answer[100.0]{no real solution} 2164 | 2165 | \single{True} 2166 | 2167 | \end{question} 2168 | 2169 | \end{category} 2170 | 2171 | \end{document} 2172 | --------------------------------------------------------------------------------