diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b98865e301..645984cb97 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,8 @@ These are notable changes in edx-platform. This is a rolling list of changes, in roughly chronological order, most recent first. Add your entries at or near the top. Include a label indicating the component affected. +Blades: Allow regexp strings as the correct answer to a string response question. BLD-475. + Common: Add feature flags to allow developer use of pure XBlocks - ALLOW_ALL_ADVANCED_COMPONENTS disables the hard-coded list of advanced components in Studio, and allows any xblock to be added as an diff --git a/common/lib/capa/capa/responsetypes.py b/common/lib/capa/capa/responsetypes.py index 4d36d44f9e..971f89674b 100644 --- a/common/lib/capa/capa/responsetypes.py +++ b/common/lib/capa/capa/responsetypes.py @@ -329,8 +329,8 @@ class LoncapaResponse(object): rephints = hintgroup.findall(self.hint_tag) hints_to_show = self.check_hint_condition( rephints, student_answers) - # can be 'on_request' or 'always' (default) + hintmode = hintgroup.get('mode', 'always') for hintpart in hintgroup.findall('hintpart'): if hintpart.get('on') in hints_to_show: @@ -947,21 +947,35 @@ class NumericalResponse(LoncapaResponse): class StringResponse(LoncapaResponse): ''' - This response type allows one or more answers. Use `_or_` separator to set - more than 1 answer. + This response type allows one or more answers. - Example: + Additional answers are added by `additional_answer` tag. + If `regexp` is in `type` attribute, than answers and hints are treated as regular expressions. - # One answer + Examples: - - - - # Multiple answers - - + + + \d5 + a3 + + + + + + + +1 + + + -1 + + + Any number+5 + + + ''' response_tag = 'stringresponse' hint_tag = 'stringhint' @@ -969,11 +983,30 @@ class StringResponse(LoncapaResponse): required_attributes = ['answer'] max_inputfields = 1 correct_answer = [] - SEPARATOR = '_or_' + + def setup_response_backward(self): + self.correct_answer = [ + contextualize_text(answer, self.context).strip() for answer in self.xml.get('answer').split('_or_') + ] def setup_response(self): - self.correct_answer = [contextualize_text(answer, self.context).strip() - for answer in self.xml.get('answer').split(self.SEPARATOR)] + + self.backward = '_or_' in self.xml.get('answer').lower() + self.regexp = 'regexp' in self.xml.get('type').lower().split(' ') + self.case_insensitive = 'ci' in self.xml.get('type').lower().split(' ') + + # backward compatibility, can be removed in future, it is up to @Lyla Fisher. + if self.backward: + self.setup_response_backward() + return + # end of backward compatibility + + correct_answers = [self.xml.get('answer')] + [el.text for el in self.xml.findall('additional_answer')] + self.correct_answer = [contextualize_text(answer, self.context).strip() for answer in correct_answers] + + # remove additional_answer from xml, otherwise they will be displayed + for el in self.xml.findall('additional_answer'): + self.xml.remove(el) def get_score(self, student_answers): '''Grade a string response ''' @@ -981,21 +1014,61 @@ class StringResponse(LoncapaResponse): correct = self.check_string(self.correct_answer, student_answer) return CorrectMap(self.answer_id, 'correct' if correct else 'incorrect') - def check_string(self, expected, given): - if self.xml.get('type') == 'ci': + def check_string_backward(self, expected, given): + if self.case_insensitive: return given.lower() in [i.lower() for i in expected] return given in expected + def check_string(self, expected, given): + """ + Find given in expected. + + If self.regexp is true, regular expression search is used. + if self.case_insensitive is true, case insensitive search is used, otherwise case sensitive search is used. + Spaces around values of attributes are stripped in XML parsing step. + + Args: + expected: list. + given: str. + + Returns: bool + + Raises: `ResponseError` if it fails to compile regular expression. + + Note: for old code, which supports _or_ separator, we add some backward compatibility handling. + Should be removed soon. When to remove it, is up to Lyla Fisher. + """ + # backward compatibility, should be removed in future. + if self.backward: + return self.check_string_backward(expected, given) + # end of backward compatibility + + if self.regexp: # regexp match + flags = re.IGNORECASE if self.case_insensitive else 0 + try: + regexp = re.compile('^'+ '|'.join(expected) + '$', flags=flags | re.UNICODE) + result = re.search(regexp, given) + except Exception as err: + msg = '[courseware.capa.responsetypes.stringresponse] error: {}'.format(err.message) + log.error(msg, exc_info=True) + raise ResponseError(msg) + return bool(result) + else: # string match + if self.case_insensitive: + return given.lower() in [i.lower() for i in expected] + else: + return given in expected + + def check_hint_condition(self, hxml_set, student_answers): given = student_answers[self.answer_id].strip() hints_to_show = [] for hxml in hxml_set: name = hxml.get('name') - correct_answer = [contextualize_text(answer, self.context).strip() - for answer in hxml.get('answer').split(self.SEPARATOR)] + hinted_answer = contextualize_text(hxml.get('answer'), self.context).strip() - if self.check_string(correct_answer, given): + if self.check_string([hinted_answer], given): hints_to_show.append(name) log.debug('hints_to_show = %s', hints_to_show) return hints_to_show diff --git a/common/lib/capa/capa/tests/response_xml_factory.py b/common/lib/capa/capa/tests/response_xml_factory.py index ceb2da6809..735fa20288 100644 --- a/common/lib/capa/capa/tests/response_xml_factory.py +++ b/common/lib/capa/capa/tests/response_xml_factory.py @@ -690,22 +690,30 @@ class StringResponseXMLFactory(ResponseXMLFactory): *hintfn*: The name of a function in the script to use for hints. + *regexp*: Whether the response is regexp + + *additional_answers*: list of additional asnwers. + """ # Retrieve the **kwargs answer = kwargs.get("answer", None) case_sensitive = kwargs.get("case_sensitive", True) hint_list = kwargs.get('hints', None) hint_fn = kwargs.get('hintfn', None) + regexp = kwargs.get('regexp', None) + additional_answers = kwargs.get('additional_answers', []) assert answer # Create the element response_element = etree.Element("stringresponse") # Set the answer attribute - response_element.set("answer", str(answer)) + response_element.set("answer", unicode(answer)) - # Set the case sensitivity - response_element.set("type", "cs" if case_sensitive else "ci") + # Set the case sensitivity and regexp: + type_value = "cs" if case_sensitive else "ci" + type_value += ' regexp' if regexp else '' + response_element.set("type", type_value) # Add the hints if specified if hint_list or hint_fn: @@ -727,6 +735,9 @@ class StringResponseXMLFactory(ResponseXMLFactory): assert not hint_list hintgroup_element.set("hintfn", hint_fn) + for additional_answer in additional_answers: + etree.SubElement(response_element, "additional_answer").text = additional_answer + return response_element def create_input_element(self, **kwargs): diff --git a/common/lib/capa/capa/tests/test_responsetypes.py b/common/lib/capa/capa/tests/test_responsetypes.py index 6b400dc653..dec3b7bad7 100644 --- a/common/lib/capa/capa/tests/test_responsetypes.py +++ b/common/lib/capa/capa/tests/test_responsetypes.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """ Tests of responsetypes """ @@ -502,6 +503,135 @@ class StringResponseTest(ResponseTest): from capa.tests.response_xml_factory import StringResponseXMLFactory xml_factory_class = StringResponseXMLFactory + def test_backward_compatibility_for_multiple_answers(self): + """ + Remove this test, once support for _or_ separator will be removed. + """ + + answers = ["Second", "Third", "Fourth"] + problem = self.build_problem(answer="_or_".join(answers), case_sensitive=True) + + for answer in answers: + # Exact string should be correct + self.assert_grade(problem, answer, "correct") + # Other strings and the lowercase version of the string are incorrect + self.assert_grade(problem, "Other String", "incorrect") + + problem = self.build_problem(answer="_or_".join(answers), case_sensitive=False) + for answer in answers: + # Exact string should be correct + self.assert_grade(problem, answer, "correct") + self.assert_grade(problem, answer.lower(), "correct") + self.assert_grade(problem, "Other String", "incorrect") + + def test_regexp(self): + problem = self.build_problem(answer="Second", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Second", "correct") + + problem = self.build_problem(answer="sec", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Second", "incorrect") + + problem = self.build_problem(answer="sec.*", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Second", "correct") + + problem = self.build_problem(answer="sec.*", case_sensitive=True, regexp=True) + self.assert_grade(problem, "Second", "incorrect") + + problem = self.build_problem(answer="Sec.*$", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Second", "correct") + + problem = self.build_problem(answer="^sec$", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Second", "incorrect") + + problem = self.build_problem(answer="^Sec(ond)?$", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Second", "correct") + + problem = self.build_problem(answer="^Sec(ond)?$", case_sensitive=False, regexp=True) + self.assert_grade(problem, "Sec", "correct") + + problem = self.build_problem(answer="tre+", case_sensitive=False, regexp=True) + self.assert_grade(problem, "There is a tree", "incorrect") + + problem = self.build_problem(answer=".*tre+", case_sensitive=False, regexp=True) + self.assert_grade(problem, "There is a tree", "correct") + + answers = [ + "Martin Luther King Junior", + "Doctor Martin Luther King Junior", + "Dr. Martin Luther King Jr.", + "Martin Luther King" + ] + + problem = self.build_problem(answer="\w*\.?.*Luther King\s*.*", case_sensitive=True, regexp=True) + + for answer in answers: + self.assert_grade(problem, answer, "correct") + + problem = self.build_problem(answer="^(-\|){2,5}$", case_sensitive=False, regexp=True) + self.assert_grade(problem, "-|-|-|", "correct") + self.assert_grade(problem, "-|", "incorrect") + self.assert_grade(problem, "-|-|-|-|-|-|", "incorrect") + + regexps = [ + "^One$", + "two", + "^thre+", + "^4|Four$", + ] + problem = self.build_problem( + answer="just_sample", + case_sensitive=False, + regexp=True, + additional_answers=regexps + ) + + self.assert_grade(problem, "One", "correct") + self.assert_grade(problem, "two", "correct") + self.assert_grade(problem, "!!two!!", "correct") + self.assert_grade(problem, "threeeee", "correct") + self.assert_grade(problem, "three", "correct") + self.assert_grade(problem, "4", "correct") + self.assert_grade(problem, "Four", "correct") + self.assert_grade(problem, "Five", "incorrect") + self.assert_grade(problem, "|", "incorrect") + + # test unicode + problem = self.build_problem(answer=u"æ", case_sensitive=False, regexp=True, additional_answers=[u'ö']) + self.assert_grade(problem, u"æ", "correct") + self.assert_grade(problem, u"ö", "correct") + self.assert_grade(problem, u"î", "incorrect") + self.assert_grade(problem, u"o", "incorrect") + + def test_backslash_and_unicode_regexps(self): + """ + Test some special cases of [unicode] regexps. + + One needs to use either r'' strings or write real `repr` of unicode strings, because of the following + (from python docs, http://docs.python.org/2/library/re.html): + + 'for example, to match a literal backslash, one might have to write '\\\\' as the pattern string, + because the regular expression must be \\, + and each backslash must be expressed as \\ inside a regular Python string literal.' + + Example of real use case in Studio: + a) user inputs regexp in usual regexp language, + b) regexp is saved to xml and is read in python as repr of that string + So a\d in front-end editor will become a\\\\d in xml, so it will match a1 as student answer. + """ + problem = self.build_problem(answer=ur"5\\æ", case_sensitive=False, regexp=True) + self.assert_grade(problem, u"5\æ", "correct") + + problem = self.build_problem(answer=u"5\\\\æ", case_sensitive=False, regexp=True) + self.assert_grade(problem, u"5\æ", "correct") + + def test_backslash(self): + problem = self.build_problem(answer=u"a\\\\c1", case_sensitive=False, regexp=True) + self.assert_grade(problem, u"a\c1", "correct") + + def test_special_chars(self): + problem = self.build_problem(answer=ur"a \s1", case_sensitive=False, regexp=True) + self.assert_grade(problem, u"a 1", "correct") + def test_case_sensitive(self): # Test single answer problem = self.build_problem(answer="Second", case_sensitive=True) @@ -515,7 +645,7 @@ class StringResponseTest(ResponseTest): # Test multiple answers answers = ["Second", "Third", "Fourth"] - problem = self.build_problem(answer="_or_".join(answers), case_sensitive=True) + problem = self.build_problem(answer="sample_answer", case_sensitive=True, additional_answers=answers) for answer in answers: # Exact string should be correct @@ -525,6 +655,18 @@ class StringResponseTest(ResponseTest): self.assert_grade(problem, "Other String", "incorrect") self.assert_grade(problem, "second", "incorrect") + def test_bogus_escape_not_raised(self): + """ + We now adding ^ and $ around regexp, so no bogus escape error will be raised. + """ + problem = self.build_problem(answer=u"\\", case_sensitive=False, regexp=True) + + self.assert_grade(problem, u"\\", "incorrect") + + # right way to search for \ + problem = self.build_problem(answer=u"\\\\", case_sensitive=False, regexp=True) + self.assert_grade(problem, u"\\", "correct") + def test_case_insensitive(self): # Test single answer problem = self.build_problem(answer="Second", case_sensitive=False) @@ -539,7 +681,7 @@ class StringResponseTest(ResponseTest): # Test multiple answers answers = ["Second", "Third", "Fourth"] - problem = self.build_problem(answer="_or_".join(answers), case_sensitive=False) + problem = self.build_problem(answer="sample_answer", case_sensitive=False, additional_answers=answers) for answer in answers: # Exact string should be correct @@ -549,20 +691,77 @@ class StringResponseTest(ResponseTest): # Other strings and the lowercase version of the string are incorrect self.assert_grade(problem, "Other String", "incorrect") - def test_hints(self): - multiple_answers = [ - "Martin Luther King Junior", - "Doctor Martin Luther King Junior", - "Dr. Martin Luther King Jr.", - "Martin Luther King" - ] - hints = [("wisconsin", "wisc", "The state capital of Wisconsin is Madison"), - ("minnesota", "minn", "The state capital of Minnesota is St. Paul"), - ("_or_".join(multiple_answers), "mlk", "He lead the civil right movement in the United States of America.")] + def test_partial_matching(self): + problem = self.build_problem(answer="a2", case_sensitive=False, regexp=True, additional_answers=['.?\\d.?']) + self.assert_grade(problem, "a3", "correct") + self.assert_grade(problem, "3a", "correct") - problem = self.build_problem(answer="Michigan", - case_sensitive=False, - hints=hints) + def test_exception(self): + problem = self.build_problem(answer="a2", case_sensitive=False, regexp=True, additional_answers=['?\\d?']) + with self.assertRaises(Exception) as cm: + self.assert_grade(problem, "a3", "correct") + exception_message = cm.exception.message + self.assertIn("nothing to repeat", exception_message) + + def test_hints(self): + + hints = [ + ("wisconsin", "wisc", "The state capital of Wisconsin is Madison"), + ("minnesota", "minn", "The state capital of Minnesota is St. Paul"), + ] + problem = self.build_problem( + answer="Michigan", + case_sensitive=False, + hints=hints, + ) + # We should get a hint for Wisconsin + input_dict = {'1_2_1': 'Wisconsin'} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_hint('1_2_1'), + "The state capital of Wisconsin is Madison") + + # We should get a hint for Minnesota + input_dict = {'1_2_1': 'Minnesota'} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_hint('1_2_1'), + "The state capital of Minnesota is St. Paul") + + # We should NOT get a hint for Michigan (the correct answer) + input_dict = {'1_2_1': 'Michigan'} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_hint('1_2_1'), "") + + # We should NOT get a hint for any other string + input_dict = {'1_2_1': 'California'} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_hint('1_2_1'), "") + + def test_hints_regexp_and_answer_regexp(self): + different_student_answers = [ + "May be it is Boston", + "Boston, really?", + "Boston", + "OK, I see, this is Boston", + ] + + # if problem has regexp = true, it will accept hints written in regexp + hints = [ + ("wisconsin", "wisc", "The state capital of Wisconsin is Madison"), + ("minnesota", "minn", "The state capital of Minnesota is St. Paul"), + (".*Boston.*", "bst", "First letter of correct answer is M."), + ('^\\d9$', "numbers", "Should not end with 9."), + ] + + additional_answers = [ + '^\\d[0-8]$', + ] + problem = self.build_problem( + answer="Michigan", + case_sensitive=False, + hints=hints, + additional_answers=additional_answers, + regexp=True + ) # We should get a hint for Wisconsin input_dict = {'1_2_1': 'Wisconsin'} @@ -587,12 +786,18 @@ class StringResponseTest(ResponseTest): self.assertEquals(correct_map.get_hint('1_2_1'), "") # We should get the same hint for each answer - for answer in multiple_answers: + for answer in different_student_answers: input_dict = {'1_2_1': answer} correct_map = problem.grade_answers(input_dict) - self.assertEquals(correct_map.get_hint('1_2_1'), - "He lead the civil right movement in the United States of America.") + self.assertEquals(correct_map.get_hint('1_2_1'), "First letter of correct answer is M.") + input_dict = {'1_2_1': '59'} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_hint('1_2_1'), "Should not end with 9.") + + input_dict = {'1_2_1': '57'} + correct_map = problem.grade_answers(input_dict) + self.assertEquals(correct_map.get_hint('1_2_1'), "") def test_computed_hints(self): problem = self.build_problem( diff --git a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee index d7f163dd02..a1a6c7bd79 100644 --- a/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee +++ b/common/lib/xmodule/xmodule/js/spec/problem/edit_spec.coffee @@ -270,7 +270,7 @@ describe 'MarkdownEditingDescriptor', ->

The answer is correct if it matches every character of the expected answer. This can be a problem with international spelling, dates, or anything where the format of the answer is not clear.

Which US state has Lansing as its capital?

- + @@ -280,6 +280,29 @@ describe 'MarkdownEditingDescriptor', ->

Lansing is the capital of Michigan, although it is not Michgan's largest city, or even the seat of the county in which it resides.

+ + + """) + it 'converts StringResponse with regular expression to xml', -> + data = MarkdownEditingDescriptor.markdownToXml("""Who lead the civil right movement in the United States of America? + = | \w*\.?\s*Luther King\s*.* + + [Explanation] + Test Explanation. + [Explanation] + """) + expect(data).toEqual(""" +

Who lead the civil right movement in the United States of America?

+ + + + + +
+

Explanation

+ +

Test Explanation.

+
""") @@ -296,7 +319,39 @@ describe 'MarkdownEditingDescriptor', -> """) expect(data).toEqual("""

Who lead the civil right movement in the United States of America?

- + + Doctor Martin Luther King Junior + Martin Luther King + Martin Luther King Junior + + + + +
+

Explanation

+ +

Test Explanation.

+ +
+
+
""") + it 'converts StringResponse with multiple answers and regular expressions to xml', -> + data = MarkdownEditingDescriptor.markdownToXml("""Write a number from 1 to 4. + =| ^One$ + or= two + or= ^thre+ + or= ^4|Four$ + + [Explanation] + Test Explanation. + [Explanation] + """) + expect(data).toEqual(""" +

Write a number from 1 to 4.

+ + two + ^thre+ + ^4|Four$ diff --git a/common/lib/xmodule/xmodule/js/src/problem/edit.coffee b/common/lib/xmodule/xmodule/js/src/problem/edit.coffee index d50cbae865..bc29bacec5 100644 --- a/common/lib/xmodule/xmodule/js/src/problem/edit.coffee +++ b/common/lib/xmodule/xmodule/js/src/problem/edit.coffee @@ -247,13 +247,17 @@ class @MarkdownEditingDescriptor extends XModule.Descriptor string += ' \n'; string += '\n\n'; } else { - var answers = []; - - for(var i = 0; i < answersList.length; i++) { - answers.push(answersList[i]) + var firstAnswer = answersList.shift(); + if (firstAnswer[0] === '|') { // this is regexp case + string = '\n' } - - string = '\n \n\n\n'; + else { + string = '\n' + } + for(var i = 0; i < answersList.length; i++) { + string += ' ' + answersList[i] + '\n' + } + string += ' \n\n\n'; } return string; }); diff --git a/docs/course_authors/source/appendices/e.rst b/docs/course_authors/source/appendices/e.rst index 40865ce64f..a3608351a8 100644 --- a/docs/course_authors/source/appendices/e.rst +++ b/docs/course_authors/source/appendices/e.rst @@ -1,5 +1,5 @@ .. raw:: latex - + \newpage % .. _Appendix E: @@ -25,7 +25,7 @@ differences between the two include the following. Sample Problem: .. image:: ../Images/image287.png - :width: 600 + :width: 600 **Problem Code:** @@ -70,7 +70,7 @@ Sample Problem:
-
+ @@ -88,11 +88,11 @@ Sample Problem: .. raw:: latex - + \newpage % -Multiple Choice +Multiple Choice =============== @@ -110,14 +110,14 @@ differences between the two include the following. • The Option Response drop-down input format makes it more likely for students to think of an answer and then search for it, rather than relying purely on recognition to answer the question. -• The Multiple Choice format is more explicit and visual. This makes it a more appropriate choice for presenting tricky or complicated answer options which areintended to get the student to pause and think. +• The Multiple Choice format is more explicit and visual. This makes it a more appropriate choice for presenting tricky or complicated answer options which are intended to get the student to pause and think. Sample Problem: .. image:: ../Images/image289.png - :width: 600 + :width: 600 -**Problem Code:** +**Problem Code:** .. code-block:: xml @@ -137,7 +137,7 @@ Sample Problem:

Explanation

-

It depends on how many choices are marked as correct in the underlying XML.

+

It depends on how many choices are marked as correct in the underlying XML.

Note that if all choices are marked as incorrect, there is no correct response.

@@ -145,7 +145,7 @@ Sample Problem: -**Template** +**Template** .. code-block:: xml @@ -185,7 +185,7 @@ Sample Problem: .. raw:: latex - + \newpage % @@ -206,7 +206,7 @@ have zero correct responses. Sample Problem: .. image:: ../Images/image290.png - :width: 600 + :width: 600 **Problem Code:** @@ -244,7 +244,7 @@ Sample Problem: .. raw:: latex - + \newpage % @@ -266,7 +266,7 @@ clear. Sample Problem: .. image:: ../Images/image291.png - :width: 600 + :width: 600 **Problem Code:** @@ -301,19 +301,104 @@ Sample Problem:
+ +This response type allows to add more than one answer. Use `additional_answer` tag to add more answers. + +You can add `regexp` to value of `type` attribute, for example: `type="ci regexp"` or `type="regexp"` or `type="regexp cs"`. +In this case, any answer and hint will be treated as regular expressions. +Regular expression has to match whole answer, for answer to be correct. +Student answers "foobar", "o foo" or " ==foo==", will be correct if teacher has set answer=".*foo.*" with type="regexp". + +**Template** + +.. code-block:: xml + + + + \d5 + a3 + + + + + + + +1 + + + -1 + + + Any number+5 + + + + + + **XML Attribute Information** - .. image:: ../Images/stringresponse.png + .. raw:: html + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionNotes
type(optional) “[ci] [regex]”. Add “ci” if the student response should be graded case-insensitively. The default is to take case into consideration when grading. Add “regexp” for correct answer to be treated as regular expression. 
answerThe string that is used to compare with student answer. If "regexp" is not presented in value of type attribute, student should enter value equal to exact value of this attribute in order to get credit. If "regexp" is presented in value of type attribute, value of answer is treated as regular expression and exact match of this expression and student answer will be done. If search is successful, student will get credit. 
+ + + + + + + + + + + + + + + + + + + + + + + +
ChildrenDescriptionNotes
textlineused to accept student input. See description below. 
additional_answertodo 
+ .. image:: ../Images/stringresponse2.png + - Can be unlimited number of this tags. Any tag adds one more additional answer for matching. .. raw:: latex - + \newpage % @@ -339,7 +424,7 @@ only, and the examples below show its use. Sample Problem: .. image:: ../Images/image292.png - :width: 600 + :width: 600 **Problem Code**: @@ -366,7 +451,7 @@ Sample Problem: - +

What is the distance in the plane between the points (pi, 0) and (0, e)? You can type math. @@ -383,7 +468,7 @@ Sample Problem: the square root of the sum of the squares of the differences of each coordinate. Even though an exact numerical value is checked in this case, the easiest way to enter this answer is to type - sqrt(pi^2+e^2) into the editor. + sqrt(pi^2+e^2) into the editor. Other answers like sqrt((pi-0)^2+(0-e)^2) also work.

@@ -589,7 +674,7 @@ default. These include: Operators and Functions ~~~~~~~~~~~~~~~~~~~~~~~ -As expected, the normal operators apply (with normal order of operations): +As expected, the normal operators apply (with normal order of operations): ``+ - * / ^``. Also provided is a special "parallel resistors" operator given by ``||``. For example, an input of ``1 || 2`` would represent the resistance of a pair of parallel resistors (of resistance 1 and 2 ohms), evaluating to 2/3 @@ -610,7 +695,7 @@ The default included functions are the following: coth, arcsinh, arccosh, arctanh, arcsech, arccsch, arccoth .. raw:: latex - + \newpage % @@ -651,7 +736,7 @@ backward 3. Sample Problem: .. image:: ../Images/image293.png - :width: 600 + :width: 600 **Problem Code**: @@ -663,7 +748,7 @@ Sample Problem:

Write an expression for the product of R_1, R_2, and the inverse of R_3.

- + @@ -672,7 +757,7 @@ Sample Problem: VoVi = "(R_1*R_2)/R_3" - + E = @@ -681,13 +766,13 @@ Sample Problem: derivative = "n*x^(n-1)" - + - + @@ -736,7 +821,7 @@ size (optional) defines the size (i.e. the width) ========= ============================================= ===== .. raw:: latex - + \newpage % @@ -751,7 +836,7 @@ Images have to be uploaded to the courseware Assets directory. Response clicks a Sample Problem: .. image:: ../Images/image294.png - :width: 600 + :width: 600 **Problem Code**: @@ -771,7 +856,7 @@ Sample Problem: - + XML Attribute Information @@ -786,7 +871,7 @@ XML Attribute Information .. image:: ../Images/imageresponse2.png .. raw:: latex - + \newpage % .. _Custom Response: @@ -799,7 +884,7 @@ A Custom Response input type accepts one or more lines of text input from the st Sample Problem: .. image:: ../Images/image295.png - :width: 600 + :width: 600 **Problem Code**: @@ -846,7 +931,7 @@ Sample Problem:

Explanation

For the first part, any two numbers of the form n - and 10-n, where n is any integer, will work. + and 10-n, where n is any integer, will work. One possible answer would be the pair 0 and 10.

For the second part, any pair x and 20-x will work, where x is any real number with a finite decimal representation. Both inputs have to be entered either in standard decimal notation or in scientific exponential notation. One possible answer would be the pair 0.5 and 19.5. Another way to write this would be 5e-1 and 1.95e1. @@ -915,7 +1000,7 @@ Sample Problem: .. raw:: latex - + \newpage % .. _Chemical Equation Response: @@ -924,12 +1009,12 @@ Chemical Equation Response ========================== The Chemical Equation Response input type is a special type of Custom Response -that allows the student to enter chemical equations as answers. +that allows the student to enter chemical equations as answers. Sample Problem: .. image:: ../Images/image296.png - :width: 600 + :width: 600 **Problem Code**: @@ -945,7 +1030,7 @@ Sample Problem: - if chemcalc.chemical_equations_equal(submission[0], 'H2SO4 -> H^+ + HSO4^-'): + if chemcalc.chemical_equations_equal(submission[0], 'H2SO4 -> H^+ + HSO4^-'): correct = ['correct'] else: correct = ['incorrect'] @@ -955,28 +1040,28 @@ Sample Problem:

Some tips:

  • Only real element symbols are permitted.
  • Subscripts are entered with plain text.
  • Superscripts are indicated with a caret (^).
  • The reaction arrow (\(\longrightarrow\)) is indicated with "->".
So, you can enter "H2SO4 -> H^+ + HSO4^-".

- + .. raw:: latex - + \newpage % Schematic Response ================== The Schematic Response input type provides an interactive grid on which the -student can construct a schematic answer, such as a circuit. +student can construct a schematic answer, such as a circuit. Sample Problem: .. image:: ../Images/image297.png - :width: 600 + :width: 600 .. image:: ../Images/image298.png - :width: 600 + :width: 600 .. image:: ../Images/image299.png - :width: 600 + :width: 600 **Problem Code**: diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index 7b98e64692..59fda5f76b 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -17,7 +17,7 @@ # Our libraries: -e git+https://github.com/edx/XBlock.git@a1a3e76b269d15b7bbd11976d8aef63e1db6c4c2#egg=XBlock -e git+https://github.com/edx/codejail.git@e3d98f9455#egg=codejail --e git+https://github.com/edx/diff-cover.git@v0.2.6#egg=diff_cover +-e git+https://github.com/edx/diff-cover.git@v0.2.9#egg=diff_cover -e git+https://github.com/edx/js-test-tool.git@v0.1.5#egg=js_test_tool -e git+https://github.com/edx/django-waffle.git@823a102e48#egg=django-waffle -e git+https://github.com/edx/event-tracking.git@f0211d702d#egg=event-tracking