<?xml version="1.0" encoding="UTF-8"?>
<quiz>
<!-- question: 11719  -->
  <question type="coderunner">
    <name>
      <text>Input example (Scratchpad copy) (input wrapper)</text>
    </name>
    <questiontext format="html">
      <text><![CDATA[<h4></h4>
<h4>Advanced Wrapper: Python with Input<br></h4>
<p dir="ltr" style="text-align: left;">Using a cunning trade secret, the Scratchpad can be used to run code that uses the Python <em>input()</em>&nbsp;function. You enter the response to a prompt into an entry field and type <em>Enter</em>&nbsp;to proceed. [Yeah, OK, it's actually a hack. But our students haven't noticed yet, so it's a workable hack.]</p>
<p dir="ltr" style="text-align: left;">The 'cunning trade secret' is to re-run the program each time an additional input is required with an expanding list of known inputs, i.e. collect one input, rerun program with that input and all the prevouis inputs, repeat until no more inputs. The hack in more detail follows (when using the recommended "json" output display mode): <br></p>
<ol>
    <li>Set stdin to be an empty string.<br></li>
    <li>Run the program as normal until stdin is required.<br></li>
    <li>If stdin, exit with the error code 42.<ul>
            <li>Setting returncode to 42 will add an input field to the end of the output, when in the json output display mode.<br></li>
            <li>When enter is pressed inside the input field the value inside will be appended to the run stdin and the program is run again..</li>
        </ul>
    </li>
    <li>Repeat steps 2-4 until the program completes without error code 42.<br></li>
</ol>
<p dir="ltr" style="text-align: left;">Listed below is a simplified version of the wrapper used in this question (with restrictions on output size left out). <br></p><p dir="ltr" style="text-align: left;">Note: because <code>answer_code</code> and <code>test_code</code> are inserted inside a multi-line string we must escape all double-quotes (<code>"</code>) before insertion into the wrapper. To do this we must set the UI parameter <code>escape</code><code> </code>to <code>true</code>.<br></p>
<p dir="ltr" style="text-align: left;"><em></em></p>
<pre class="language-python" data-ace-highlight-code=""><code>import sys, io, subprocess, ast, traceback, json

student_code = """
{| ANSWER_CODE |}
{| SCRATCHPAD_CODE |}
"""

subproc_code = """
import sys<br>
__saved_input__ = input

def input(prompt=''):
    try:
        line = __saved_input__()
    except EOFError:
        print(prompt, end = '')
        sys.stderr.flush()
        sys.stdout.flush()
        sys.exit(42)
    print(prompt, end='')
    print(line)
    return line

"""

subproc_code += student_code

def check_syntax():
    try:
        ast.parse(student_code)
        return ''
    except SyntaxError:
        catcher = io.StringIO()
        traceback.print_exc(limit=0, file=catcher)
        return catcher.getvalue()

stdout = ''
stderr = check_syntax()
if stderr == '':  # No syntax errors
    program_code = subproc_code
    with open('prog.py', 'w') as outfile:
        outfile.write(program_code)
    proc = subprocess.Popen([sys.executable, 'prog.py'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    try:
        stdout, stderr = proc.communicate(timeout=3)
        returncode = proc.returncode
    except subprocess.TimeoutExpired:
        proc.kill()
        stdout, stderr = proc.communicate()
        returncode = 13
else:
    returncode = 1 # Syntax errors

output = {
    'returncode': returncode,
    'stdout' : stdout,
    'stderr' : stderr,
    'files'  : [],
}

print(json.dumps(output))</code>
</pre>
<p>Listed below is the embedded Python code from <code>subproc_code</code>:</p>
<pre class="language-python" data-ace-highlight-code=""><code>import sys
__saved_input__ = input

def input(prompt=''):
    try:
        line = __saved_input__()
    except EOFError:
        print(prompt, end = '')
        sys.stderr.flush()
        sys.stdout.flush()
        sys.exit(42)
    print(prompt, end='')
    print(line)
    return line</code>
</pre><a href="@@PLUGINFILE@@/questions-CodeRunner-Input%20example%20%28Scratchpad%20copy%29%20%28input%20wrapper%29-20230215-1613.xml">Question XML file</a><br><p><br></p><h4>Question Specification</h4>
<p>Write a function get_int(low, high)&nbsp;that asks
    the user to enter an integer in the range low to high inclusive. If an
    out-of-bounds answer is entered, the user is given an error message and
    reprompted. You may assume that only ints&nbsp;are entered (to simplify, so we don't have to deal with exceptions).</p>
<p><em>In this example, the answer box has been preloaded with a correct answer
        to the question, the scratchpad has been reloaded with the first test
        -- to see it in action click Run.</em><br></p><em></em>
<p></p>]]></text>
<file name="questions-CodeRunner-Input example (Scratchpad copy) (input wrapper)-20230215-1613.xml" path="/" encoding="base64">PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHF1aXo+CjwhLS0gcXVlc3Rpb246IDExMzQ2ICAtLT4KICA8cXVlc3Rpb24gdHlwZT0iY29kZXJ1bm5lciI+CiAgICA8bmFtZT4KICAgICAgPHRleHQ+SW5wdXQgZXhhbXBsZSAoU2NyYXRjaHBhZCBjb3B5KSAoaW5wdXQgd3JhcHBlcik8L3RleHQ+CiAgICA8L25hbWU+CiAgICA8cXVlc3Rpb250ZXh0IGZvcm1hdD0iaHRtbCI+CiAgICAgIDx0ZXh0PjwhW0NEQVRBWzxoND48L2g0Pg0KPGg0PkFkdmFuY2VkIFdyYXBwZXI6IFB5dGhvbiB3aXRoIElucHV0PGJyPjwvaDQ+DQo8cCBkaXI9Imx0ciIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij5Vc2luZyBhIGN1bm5pbmcgdHJhZGUgc2VjcmV0LCB0aGUgU2NyYXRjaHBhZCBjYW4gYmUgdXNlZCB0byBydW4gY29kZSB0aGF0IHVzZXMgdGhlIFB5dGhvbiA8ZW0+aW5wdXQoKTwvZW0+Jm5ic3A7ZnVuY3Rpb24uIFlvdSBlbnRlciB0aGUgcmVzcG9uc2UgdG8gYSBwcm9tcHQgaW50byBhbiBlbnRyeSBmaWVsZCBhbmQgdHlwZSA8ZW0+RW50ZXI8L2VtPiZuYnNwO3RvIHByb2NlZWQuIFtZZWFoLCBPSywgaXQncyBhY3R1YWxseSBhIGhhY2suIEJ1dCBvdXIgc3R1ZGVudHMgaGF2ZW4ndCBub3RpY2VkIHlldCwgc28gaXQncyBhIHdvcmthYmxlIGhhY2suXTwvcD4NCjxwIGRpcj0ibHRyIiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPlRoZSAnY3VubmluZyB0cmFkZSBzZWNyZXQnIGlzIHRvIHJlLXJ1biB0aGUgcHJvZ3JhbSBlYWNoIHRpbWUgYW4gYWRkaXRpb25hbCBpbnB1dCBpcyByZXF1aXJlZCB3aXRoIGFuIGV4cGFuZGluZyBsaXN0IG9mIGtub3duIGlucHV0cywgaS5lLiBjb2xsZWN0IG9uZSBpbnB1dCwgcmVydW4gcHJvZ3JhbSB3aXRoIHRoYXQgaW5wdXQgYW5kIGFsbCB0aGUgcHJldm91aXMgaW5wdXRzLCByZXBlYXQgdW50aWwgbm8gbW9yZSBpbnB1dHMuIFRoZSBoYWNrIGluIG1vcmUgZGV0YWlsIGZvbGxvd3MgKHdoZW4gdXNpbmcgdGhlIHJlY29tbWVuZGVkICJqc29uIiBvdXRwdXQgZGlzcGxheSBtb2RlKTogPGJyPjwvcD4NCjxvbD4NCiAgICA8bGk+U2V0IHN0ZGluIHRvIGJlIGFuIGVtcHR5IHN0cmluZy48YnI+PC9saT4NCiAgICA8bGk+UnVuIHRoZSBwcm9ncmFtIGFzIG5vcm1hbCB1bnRpbCBzdGRpbiBpcyByZXF1aXJlZC48YnI+PC9saT4NCiAgICA8bGk+SWYgc3RkaW4sIGV4aXQgd2l0aCB0aGUgZXJyb3IgY29kZSA0Mi48dWw+DQogICAgICAgICAgICA8bGk+U2V0dGluZyByZXR1cm5jb2RlIHRvIDQyIHdpbGwgYWRkIGFuIGlucHV0IGZpZWxkIHRvIHRoZSBlbmQgb2YgdGhlIG91dHB1dCwgd2hlbiBpbiB0aGUganNvbiBvdXRwdXQgZGlzcGxheSBtb2RlLjxicj48L2xpPg0KICAgICAgICAgICAgPGxpPldoZW4gZW50ZXIgaXMgcHJlc3NlZCBpbnNpZGUgdGhlIGlucHV0IGZpZWxkIHRoZSB2YWx1ZSBpbnNpZGUgd2lsbCBiZSBhcHBlbmRlZCB0byB0aGUgcnVuIHN0ZGluIGFuZCB0aGUgcHJvZ3JhbSBpcyBydW4gYWdhaW4uLjwvbGk+DQogICAgICAgIDwvdWw+DQogICAgPC9saT4NCiAgICA8bGk+UmVwZWF0IHN0ZXBzIDItNCB1bnRpbCB0aGUgcHJvZ3JhbSBjb21wbGV0ZXMgd2l0aG91dCBlcnJvciBjb2RlIDQyLjxicj48L2xpPg0KPC9vbD4NCjxwIGRpcj0ibHRyIiBzdHlsZT0idGV4dC1hbGlnbjogbGVmdDsiPkxpc3RlZCBiZWxvdyBpcyBhIHNpbXBsaWZpZWQgdmVyc2lvbiBvZiB0aGUgd3JhcHBlciB1c2VkIGluIHRoaXMgcXVlc3Rpb24gKHdpdGggcmVzdHJpY3Rpb25zIG9uIG91dHB1dCBzaXplIGxlZnQgb3V0KS4gPGJyPjwvcD48cCBkaXI9Imx0ciIgc3R5bGU9InRleHQtYWxpZ246IGxlZnQ7Ij5Ob3RlOiBiZWNhdXNlIDxjb2RlPmFuc3dlcl9jb2RlPC9jb2RlPiBhbmQgPGNvZGU+dGVzdF9jb2RlPC9jb2RlPiBhcmUgaW5zZXJ0ZWQgaW5zaWRlIGEgbXVsdGktbGluZSBzdHJpbmcgd2UgbXVzdCBlc2NhcGUgYWxsIGRvdWJsZS1xdW90ZXMgKDxjb2RlPiI8L2NvZGU+KSBiZWZvcmUgaW5zZXJ0aW9uIGludG8gdGhlIHdyYXBwZXIuIFRvIGRvIHRoaXMgd2UgbXVzdCBzZXQgdGhlIFVJIHBhcmFtZXRlciA8Y29kZT5lc2NhcGU8L2NvZGU+PGNvZGU+IDwvY29kZT50byA8Y29kZT50cnVlPC9jb2RlPi48YnI+PC9wPg0KPHAgZGlyPSJsdHIiIHN0eWxlPSJ0ZXh0LWFsaWduOiBsZWZ0OyI+PGVtPjwvZW0+PC9wPg0KPHByZSBjbGFzcz0ibGFuZ3VhZ2UtcHl0aG9uIiBkYXRhLWFjZS1oaWdobGlnaHQtY29kZT0iIj48Y29kZT5pbXBvcnQgc3lzLCBpbywgc3VicHJvY2VzcywgYXN0LCB0cmFjZWJhY2ssIGpzb24NCg0Kc3R1ZGVudF9jb2RlID0gIiIiDQp7fCBBTlNXRVJfQ09ERSB8fQ0Ke3wgU0NSQVRDSFBBRF9DT0RFIHx9DQoiIiINCg0Kc3VicHJvY19jb2RlID0gIiIiDQppbXBvcnQgc3lzPGJyPg0KX19zYXZlZF9pbnB1dF9fID0gaW5wdXQNCg0KZGVmIGlucHV0KHByb21wdD0nJyk6DQogICAgdHJ5Og0KICAgICAgICBsaW5lID0gX19zYXZlZF9pbnB1dF9fKCkNCiAgICBleGNlcHQgRU9GRXJyb3I6DQogICAgICAgIHByaW50KHByb21wdCwgZW5kID0gJycpDQogICAgICAgIHN5cy5zdGRlcnIuZmx1c2goKQ0KICAgICAgICBzeXMuc3Rkb3V0LmZsdXNoKCkNCiAgICAgICAgc3lzLmV4aXQoNDIpDQogICAgcHJpbnQocHJvbXB0LCBlbmQ9JycpDQogICAgcHJpbnQobGluZSkNCiAgICByZXR1cm4gbGluZQ0KDQoiIiINCg0Kc3VicHJvY19jb2RlICs9IHN0dWRlbnRfY29kZQ0KDQpkZWYgY2hlY2tfc3ludGF4KCk6DQogICAgdHJ5Og0KICAgICAgICBhc3QucGFyc2Uoc3R1ZGVudF9jb2RlKQ0KICAgICAgICByZXR1cm4gJycNCiAgICBleGNlcHQgU3ludGF4RXJyb3I6DQogICAgICAgIGNhdGNoZXIgPSBpby5TdHJpbmdJTygpDQogICAgICAgIHRyYWNlYmFjay5wcmludF9leGMobGltaXQ9MCwgZmlsZT1jYXRjaGVyKQ0KICAgICAgICByZXR1cm4gY2F0Y2hlci5nZXR2YWx1ZSgpDQoNCnN0ZG91dCA9ICcnDQpzdGRlcnIgPSBjaGVja19zeW50YXgoKQ0KaWYgc3RkZXJyID09ICcnOiAgIyBObyBzeW50YXggZXJyb3JzDQogICAgcHJvZ3JhbV9jb2RlID0gc3VicHJvY19jb2RlDQogICAgd2l0aCBvcGVuKCdwcm9nLnB5JywgJ3cnKSBhcyBvdXRmaWxlOg0KICAgICAgICBvdXRmaWxlLndyaXRlKHByb2dyYW1fY29kZSkNCiAgICBwcm9jID0gc3VicHJvY2Vzcy5Qb3Blbihbc3lzLmV4ZWN1dGFibGUsICdwcm9nLnB5J10sIHN0ZG91dD1zdWJwcm9jZXNzLlBJUEUsIHN0ZGVycj1zdWJwcm9jZXNzLlBJUEUsIHRleHQ9VHJ1ZSkNCiAgICB0cnk6DQogICAgICAgIHN0ZG91dCwgc3RkZXJyID0gcHJvYy5jb21tdW5pY2F0ZSh0aW1lb3V0PTMpDQogICAgICAgIHJldHVybmNvZGUgPSBwcm9jLnJldHVybmNvZGUNCiAgICBleGNlcHQgc3VicHJvY2Vzcy5UaW1lb3V0RXhwaXJlZDoNCiAgICAgICAgcHJvYy5raWxsKCkNCiAgICAgICAgc3Rkb3V0LCBzdGRlcnIgPSBwcm9jLmNvbW11bmljYXRlKCkNCiAgICAgICAgcmV0dXJuY29kZSA9IDEzDQplbHNlOg0KICAgIHJldHVybmNvZGUgPSAxICMgU3ludGF4IGVycm9ycw0KDQpvdXRwdXQgPSB7DQogICAgJ3JldHVybmNvZGUnOiByZXR1cm5jb2RlLA0KICAgICdzdGRvdXQnIDogc3Rkb3V0LA0KICAgICdzdGRlcnInIDogc3RkZXJyLA0KICAgICdmaWxlcycgIDogW10sDQp9DQoNCnByaW50KGpzb24uZHVtcHMob3V0cHV0KSk8L2NvZGU+DQo8L3ByZT4NCjxwPkxpc3RlZCBiZWxvdyBpcyB0aGUgZW1iZWRkZWQgUHl0aG9uIGNvZGUgZnJvbSA8Y29kZT5zdWJwcm9jX2NvZGU8L2NvZGU+OjwvcD4NCjxwcmUgY2xhc3M9Imxhbmd1YWdlLXB5dGhvbiIgZGF0YS1hY2UtaGlnaGxpZ2h0LWNvZGU9IiI+PGNvZGU+aW1wb3J0IHN5cw0KX19zYXZlZF9pbnB1dF9fID0gaW5wdXQNCg0KZGVmIGlucHV0KHByb21wdD0nJyk6DQogICAgdHJ5Og0KICAgICAgICBsaW5lID0gX19zYXZlZF9pbnB1dF9fKCkNCiAgICBleGNlcHQgRU9GRXJyb3I6DQogICAgICAgIHByaW50KHByb21wdCwgZW5kID0gJycpDQogICAgICAgIHN5cy5zdGRlcnIuZmx1c2goKQ0KICAgICAgICBzeXMuc3Rkb3V0LmZsdXNoKCkNCiAgICAgICAgc3lzLmV4aXQoNDIpDQogICAgcHJpbnQocHJvbXB0LCBlbmQ9JycpDQogICAgcHJpbnQobGluZSkNCiAgICByZXR1cm4gbGluZTwvY29kZT4NCjwvcHJlPg0KPGg0PlF1ZXN0aW9uIFNwZWNpZmljYXRpb248L2g0Pg0KPHA+V3JpdGUgYSBmdW5jdGlvbiBnZXRfaW50KGxvdywgaGlnaCkmbmJzcDt0aGF0IGFza3MNCiAgICB0aGUgdXNlciB0byBlbnRlciBhbiBpbnRlZ2VyIGluIHRoZSByYW5nZSBsb3cgdG8gaGlnaCBpbmNsdXNpdmUuIElmIGFuDQogICAgb3V0LW9mLWJvdW5kcyBhbnN3ZXIgaXMgZW50ZXJlZCwgdGhlIHVzZXIgaXMgZ2l2ZW4gYW4gZXJyb3IgbWVzc2FnZSBhbmQNCiAgICByZXByb21wdGVkLiBZb3UgbWF5IGFzc3VtZSB0aGF0IG9ubHkgaW50cyZuYnNwO2FyZSBlbnRlcmVkICh0byBzaW1wbGlmeSwgc28gd2UgZG9uJ3QgaGF2ZSB0byBkZWFsIHdpdGggZXhjZXB0aW9ucykuPC9wPg0KPHA+PGVtPkluIHRoaXMgZXhhbXBsZSwgdGhlIGFuc3dlciBib3ggaGFzIGJlZW4gcHJlbG9hZGVkIHdpdGggYSBjb3JyZWN0IGFuc3dlcg0KICAgICAgICB0byB0aGUgcXVlc3Rpb24sIHRoZSBzY3JhdGNocGFkIGhhcyBiZWVuIHJlbG9hZGVkIHdpdGggdGhlIGZpcnN0IHRlc3QNCiAgICAgICAgLS0gdG8gc2VlIGl0IGluIGFjdGlvbiBjbGljayBSdW4uPC9lbT48YnI+PC9wPjxlbT48L2VtPg0KPHA+PC9wPl1dPjwvdGV4dD4KICAgIDwvcXVlc3Rpb250ZXh0PgogICAgPGdlbmVyYWxmZWVkYmFjayBmb3JtYXQ9Imh0bWwiPgogICAgICA8dGV4dD48L3RleHQ+CiAgICA8L2dlbmVyYWxmZWVkYmFjaz4KICAgIDxkZWZhdWx0Z3JhZGU+MTwvZGVmYXVsdGdyYWRlPgogICAgPHBlbmFsdHk+MDwvcGVuYWx0eT4KICAgIDxoaWRkZW4+MDwvaGlkZGVuPgogICAgPGlkbnVtYmVyPjwvaWRudW1iZXI+CiAgICA8Y29kZXJ1bm5lcnR5cGU+cHl0aG9uM193X2lucHV0PC9jb2RlcnVubmVydHlwZT4KICAgIDxwcm90b3R5cGV0eXBlPjA8L3Byb3RvdHlwZXR5cGU+CiAgICA8YWxsb3Jub3RoaW5nPjE8L2FsbG9ybm90aGluZz4KICAgIDxwZW5hbHR5cmVnaW1lPjEwLCAyMCwgLi4uPC9wZW5hbHR5cmVnaW1lPgogICAgPHByZWNoZWNrPjA8L3ByZWNoZWNrPgogICAgPGhpZGVjaGVjaz4wPC9oaWRlY2hlY2s+CiAgICA8c2hvd3NvdXJjZT4wPC9zaG93c291cmNlPgogICAgPGFuc3dlcmJveGxpbmVzPjk8L2Fuc3dlcmJveGxpbmVzPgogICAgPGFuc3dlcmJveGNvbHVtbnM+PC9hbnN3ZXJib3hjb2x1bW5zPgogICAgPGFuc3dlcnByZWxvYWQ+PCFbQ0RBVEFbeyJhbnN3ZXJfY29kZSI6WyJkZWYgZ2V0X2ludChsb3csIGhpZ2gpOlxuICAgICcnJ0FzayB0aGUgdXNlciBmb3IgYW4gaW50IGluIHRoZSBnaXZlbiByYW5nZScnJ1xuICAgIHByb21wdCA9IGZcIkVudGVyIGFuIGludGVnZXIgaW4gdGhlIHJhbmdlIHtsb3d9IHRvIHtoaWdofSBpbmNsdXNpdmU6IFwiXG4gICAgbiA9IGludChpbnB1dChwcm9tcHQpKVxuICAgIHdoaWxlIG4gPCBsb3cgb3IgbiA+IGhpZ2g6XG4gICAgICAgIHByaW50KFwiU29ycnksIHRoYXQncyBub3QgaW4gdGhlIHJlcXVpcmVkIHJhbmdlXCIpXG4gICAgICAgIG4gPSBpbnQoaW5wdXQocHJvbXB0KSlcbiAgICByZXR1cm4gbiJdLCJ0ZXN0X2NvZGUiOlsibiA9IGdldF9pbnQoMywgNylcbnByaW50KGZcIllvdSBnYXZlIG1lIHtufSFcIikiXSwic2hvd19oaWRlIjpbIiJdLCJwcmVmaXhfYW5zIjpbIjEiXX1dXT48L2Fuc3dlcnByZWxvYWQ+CiAgICA8Z2xvYmFsZXh0cmE+PCFbQ0RBVEFbaW1wb3J0IHN5cywgaW8sIHN1YnByb2Nlc3MsIGFzdCwgdHJhY2ViYWNrLCBqc29uDQpNQVhfT1VUUFVUX0NIQVJTID0gMzAwMDANCg0Kc3R1ZGVudF9jb2RlID0gIiIiDQp7fCBBTlNXRVJfQ09ERSB8fQ0Ke3wgU0NSQVRDSFBBRF9DT0RFIHx9DQoiIiINCg0Kc3VicHJvY19jb2RlID0gIiIiDQppbXBvcnQgc3lzDQpNQVhfT1VUUFVUX0NIQVJTID0gMzAwMDANCl9fc2F2ZWRfaW5wdXRfXyA9IGlucHV0DQoNCmRlZiBpbnB1dChwcm9tcHQ9JycpOg0KICAgIHRyeToNCiAgICAgICAgbGluZSA9IF9fc2F2ZWRfaW5wdXRfXygpDQogICAgZXhjZXB0IEVPRkVycm9yOg0KICAgICAgICBwcmludChwcm9tcHQsIGVuZCA9ICcnKQ0KICAgICAgICBzeXMuc3RkZXJyLmZsdXNoKCkNCiAgICAgICAgc3lzLnN0ZG91dC5mbHVzaCgpDQogICAgICAgIHN5cy5leGl0KDQyKQ0KICAgIHByaW50KHByb21wdCwgZW5kPScnKQ0KICAgIHByaW50KGxpbmUpDQogICAgcmV0dXJuIGxpbmUNCg0KX19zYXZlZF9wcmludF9fID0gcHJpbnQNCl9fb3V0cHV0X2NoYXJzX18gPSAwDQoNCmRlZiBwcmludCgqcGFyYW1zLCAqKmtleXBhcmFtcyk6DQogICAgZ2xvYmFsIF9fb3V0cHV0X2NoYXJzX18NCiAgICBmb3IgcGFyYW0gaW4gcGFyYW1zOg0KICAgICAgICB0cnk6DQogICAgICAgICAgICBfX291dHB1dF9jaGFyc19fICs9IGxlbihzdHIocGFyYW0pKQ0KICAgICAgICBleGNlcHQ6DQogICAgICAgICAgICBwYXNzDQogICAgaWYgX19vdXRwdXRfY2hhcnNfXyA+IDIgKiBNQVhfT1VUUFVUX0NIQVJTOg0KICAgICAgICBfX3NhdmVkX3ByaW50X18oIlxcXFxuKioqIEV4Y2Vzc2l2ZSBvdXRwdXQuIEpvYiBhYm9ydGVkICoqKiIsIGZpbGU9c3lzLnN0ZGVycikNCiAgICAgICAgc3lzLmV4aXQoMSkNCiAgICBlbHNlOg0KICAgICAgICBfX3NhdmVkX3ByaW50X18oKnBhcmFtcywgKiprZXlwYXJhbXMpDQoiIiINCg0Kc3VicHJvY19jb2RlICs9IHN0dWRlbnRfY29kZQ0KDQpkZWYgdHJ1bmNhdGVkKHMpOg0KICAgIHJldHVybiBzIGlmIGxlbihzKSA8IE1BWF9PVVRQVVRfQ0hBUlMgZWxzZSBzWzpNQVhfT1VUUFVUX0NIQVJTXSArICcgLi4uICh0cnVuY2F0ZWQpJw0KDQpkZWYgY2hlY2tfc3ludGF4KCk6DQogICAgdHJ5Og0KICAgICAgICBhc3QucGFyc2Uoc3R1ZGVudF9jb2RlKQ0KICAgICAgICByZXR1cm4gJycNCiAgICBleGNlcHQgU3ludGF4RXJyb3I6DQogICAgICAgIGNhdGNoZXIgPSBpby5TdHJpbmdJTygpDQogICAgICAgIHRyYWNlYmFjay5wcmludF9leGMobGltaXQ9MCwgZmlsZT1jYXRjaGVyKQ0KICAgICAgICByZXR1cm4gY2F0Y2hlci5nZXR2YWx1ZSgpDQoNCnN0ZG91dCA9ICcnDQpzdGRlcnIgPSBjaGVja19zeW50YXgoKQ0KaWYgc3RkZXJyID09ICcnOiAgIyBObyBzeW50YXggZXJyb3JzDQogICAgcHJvZ3JhbV9jb2RlID0gc3VicHJvY19jb2RlDQogICAgd2l0aCBvcGVuKCdwcm9nLnB5JywgJ3cnKSBhcyBvdXRmaWxlOg0KICAgICAgICBvdXRmaWxlLndyaXRlKHByb2dyYW1fY29kZSkNCiAgICBwcm9jID0gc3VicHJvY2Vzcy5Qb3Blbihbc3lzLmV4ZWN1dGFibGUsICdwcm9nLnB5J10sIHN0ZG91dD1zdWJwcm9jZXNzLlBJUEUsIHN0ZGVycj1zdWJwcm9jZXNzLlBJUEUsIHRleHQ9VHJ1ZSkNCiAgICB0cnk6DQogICAgICAgIHN0ZG91dCwgc3RkZXJyID0gcHJvYy5jb21tdW5pY2F0ZSh0aW1lb3V0PTMpDQogICAgICAgIHJldHVybmNvZGUgPSBwcm9jLnJldHVybmNvZGUNCiAgICBleGNlcHQgc3VicHJvY2Vzcy5UaW1lb3V0RXhwaXJlZDoNCiAgICAgICAgcHJvYy5raWxsKCkNCiAgICAgICAgc3Rkb3V0LCBzdGRlcnIgPSBwcm9jLmNvbW11bmljYXRlKCkNCiAgICAgICAgcmV0dXJuY29kZSA9IDEzDQoNCg0KZWxzZToNCiAgICByZXR1cm5jb2RlID0gMSAjIFN5bnRheCBlcnJvcnMNCg0Kb3V0cHV0ID0gew0KICAgICdyZXR1cm5jb2RlJzogcmV0dXJuY29kZSwNCiAgICAnc3Rkb3V0JyA6IHRydW5jYXRlZChzdGRvdXQpLA0KICAgICdzdGRlcnInIDogdHJ1bmNhdGVkKHN0ZGVyciksDQogICAgJ2ZpbGVzJyAgOiBbXSwNCn0NCg0KcHJpbnQoanNvbi5kdW1wcyhvdXRwdXQpKV1dPjwvZ2xvYmFsZXh0cmE+CiAgICA8dXNlYWNlPjwvdXNlYWNlPgogICAgPHJlc3VsdGNvbHVtbnM+PC9yZXN1bHRjb2x1bW5zPgogICAgPHRlbXBsYXRlPjwhW0NEQVRBW19fc2F2ZWRfaW5wdXRfXyA9IGlucHV0DQpkZWYgaW5wdXQocHJvbXB0PScnKToNCiAgICBzID0gX19zYXZlZF9pbnB1dF9fKHByb21wdCkNCiAgICBwcmludChzKQ0KICAgIHJldHVybiBzDQoNCnt7IFNUVURFTlRfQU5TV0VSIH19DQpTRVBBUkFUT1IgPSAiIzxhYkAxNzk0MzkxOCNAPiMiDQoNCnslIGZvciBURVNUIGluIFRFU1RDQVNFUyAlfQ0Ke3sgVEVTVC50ZXN0Y29kZSB9fQ0KeyUgaWYgbm90IGxvb3AubGFzdCAlfQ0KcHJpbnQoU0VQQVJBVE9SKQ0KeyUgZW5kaWYgJX0NCnslIGVuZGZvciAlfV1dPjwvdGVtcGxhdGU+CiAgICA8aXNjb21iaW5hdG9ydGVtcGxhdGU+PC9pc2NvbWJpbmF0b3J0ZW1wbGF0ZT4KICAgIDxhbGxvd211bHRpcGxlc3RkaW5zPjwvYWxsb3dtdWx0aXBsZXN0ZGlucz4KICAgIDxhbnN3ZXI+PCFbQ0RBVEFbeyJhbnN3ZXJfY29kZSI6WyJkZWYgZ2V0X2ludChsb3csIGhpZ2gpOlxuICAgIHByb21wdCA9IGZcIkVudGVyIGFuIGludGVnZXIgaW4gdGhlIHJhbmdlIHtsb3d9IHRvIHtoaWdofSBpbmNsdXNpdmU6IFwiXG4gICAgbiA9IGludChpbnB1dChwcm9tcHQpKVxuICAgIHdoaWxlIG4gPCBsb3cgb3IgbiA+IGhpZ2g6XG4gICAgICAgIHByaW50KFwiU29ycnksIHRoYXQncyBub3QgaW4gdGhlIHJlcXVpcmVkIHJhbmdlXCIpXG4gICAgICAgIG4gPSBpbnQoaW5wdXQocHJvbXB0KSlcbiAgICByZXR1cm4gblxuICAgICJdLCJ0ZXN0X2NvZGUiOlsiIl0sInNob3dfaGlkZSI6WyIiXSwicHJlZml4X2FucyI6WyIxIl19XV0+PC9hbnN3ZXI+CiAgICA8dmFsaWRhdGVvbnNhdmU+MTwvdmFsaWRhdGVvbnNhdmU+CiAgICA8dGVzdHNwbGl0dGVycmU+PC90ZXN0c3BsaXR0ZXJyZT4KICAgIDxsYW5ndWFnZT48L2xhbmd1YWdlPgogICAgPGFjZWxhbmc+PC9hY2VsYW5nPgogICAgPHNhbmRib3g+PC9zYW5kYm94PgogICAgPGdyYWRlcj48L2dyYWRlcj4KICAgIDxjcHV0aW1lbGltaXRzZWNzPjwvY3B1dGltZWxpbWl0c2Vjcz4KICAgIDxtZW1saW1pdG1iPjwvbWVtbGltaXRtYj4KICAgIDxzYW5kYm94cGFyYW1zPjwvc2FuZGJveHBhcmFtcz4KICAgIDx0ZW1wbGF0ZXBhcmFtcz48L3RlbXBsYXRlcGFyYW1zPgogICAgPGhvaXN0dGVtcGxhdGVwYXJhbXM+MTwvaG9pc3R0ZW1wbGF0ZXBhcmFtcz4KICAgIDxleHRyYWN0Y29kZWZyb21qc29uPjE8L2V4dHJhY3Rjb2RlZnJvbWpzb24+CiAgICA8dGVtcGxhdGVwYXJhbXNsYW5nPk5vbmU8L3RlbXBsYXRlcGFyYW1zbGFuZz4KICAgIDx0ZW1wbGF0ZXBhcmFtc2V2YWxwZXJ0cnk+MDwvdGVtcGxhdGVwYXJhbXNldmFscGVydHJ5PgogICAgPHRlbXBsYXRlcGFyYW1zZXZhbGQ+e308L3RlbXBsYXRlcGFyYW1zZXZhbGQ+CiAgICA8dHdpZ2FsbD4wPC90d2lnYWxsPgogICAgPHVpcGx1Z2luPnNjcmF0Y2hwYWQ8L3VpcGx1Z2luPgogICAgPHVpcGFyYW1ldGVycz48IVtDREFUQVt7DQogICJ3cmFwcGVyX3NyYyI6ICJnbG9iYWxleHRyYSIsDQogICJvdXRwdXRfZGlzcGxheV9tb2RlIjogImpzb24iDQp9XV0+PC91aXBhcmFtZXRlcnM+CiAgICA8YXR0YWNobWVudHM+MDwvYXR0YWNobWVudHM+CiAgICA8YXR0YWNobWVudHNyZXF1aXJlZD4wPC9hdHRhY2htZW50c3JlcXVpcmVkPgogICAgPG1heGZpbGVzaXplPjEwMjQwPC9tYXhmaWxlc2l6ZT4KICAgIDxmaWxlbmFtZXNyZWdleD48L2ZpbGVuYW1lc3JlZ2V4PgogICAgPGZpbGVuYW1lc2V4cGxhaW4+PC9maWxlbmFtZXNleHBsYWluPgogICAgPGRpc3BsYXlmZWVkYmFjaz4xPC9kaXNwbGF5ZmVlZGJhY2s+CiAgICA8Z2l2ZXVwYWxsb3dlZD4wPC9naXZldXBhbGxvd2VkPgogICAgPHByb3RvdHlwZWV4dHJhPjwvcHJvdG90eXBlZXh0cmE+CiAgICA8dGVzdGNhc2VzPgogICAgICA8dGVzdGNhc2UgdGVzdHR5cGU9IjAiIHVzZWFzZXhhbXBsZT0iMSIgaGlkZXJlc3RpZmZhaWw9IjAiIG1hcms9IjEuMDAwMDAwMCIgPgogICAgICA8dGVzdGNvZGU+CiAgICAgICAgICAgICAgICA8dGV4dD48IVtDREFUQVtuID0gZ2V0X2ludCgzLCA3KQpwcmludChmIllvdSBnYXZlIG1lIHtufSEiKV1dPjwvdGV4dD4KICAgICAgPC90ZXN0Y29kZT4KICAgICAgPHN0ZGluPgogICAgICAgICAgICAgICAgPHRleHQ+Mgo4CjAKNTwvdGV4dD4KICAgICAgPC9zdGRpbj4KICAgICAgPGV4cGVjdGVkPgogICAgICAgICAgICAgICAgPHRleHQ+RW50ZXIgYW4gaW50ZWdlciBpbiB0aGUgcmFuZ2UgMyB0byA3IGluY2x1c2l2ZTogMgpTb3JyeSwgdGhhdCdzIG5vdCBpbiB0aGUgcmVxdWlyZWQgcmFuZ2UKRW50ZXIgYW4gaW50ZWdlciBpbiB0aGUgcmFuZ2UgMyB0byA3IGluY2x1c2l2ZTogOApTb3JyeSwgdGhhdCdzIG5vdCBpbiB0aGUgcmVxdWlyZWQgcmFuZ2UKRW50ZXIgYW4gaW50ZWdlciBpbiB0aGUgcmFuZ2UgMyB0byA3IGluY2x1c2l2ZTogMApTb3JyeSwgdGhhdCdzIG5vdCBpbiB0aGUgcmVxdWlyZWQgcmFuZ2UKRW50ZXIgYW4gaW50ZWdlciBpbiB0aGUgcmFuZ2UgMyB0byA3IGluY2x1c2l2ZTogNQpZb3UgZ2F2ZSBtZSA1IQo8L3RleHQ+CiAgICAgIDwvZXhwZWN0ZWQ+CiAgICAgIDxleHRyYT4KICAgICAgICAgICAgICAgIDx0ZXh0PjwvdGV4dD4KICAgICAgPC9leHRyYT4KICAgICAgPGRpc3BsYXk+CiAgICAgICAgICAgICAgICA8dGV4dD5TSE9XPC90ZXh0PgogICAgICA8L2Rpc3BsYXk+CiAgICA8L3Rlc3RjYXNlPgogICAgICA8dGVzdGNhc2UgdGVzdHR5cGU9IjAiIHVzZWFzZXhhbXBsZT0iMCIgaGlkZXJlc3RpZmZhaWw9IjAiIG1hcms9IjEuMDAwMDAwMCIgPgogICAgICA8dGVzdGNvZGU+CiAgICAgICAgICAgICAgICA8dGV4dD48IVtDREFUQVtuID0gZ2V0X2ludCgxMDAsIDIwMCkKcHJpbnQoZiJZb3UgZ2F2ZSBtZSB7bn0hIildXT48L3RleHQ+CiAgICAgIDwvdGVzdGNvZGU+CiAgICAgIDxzdGRpbj4KICAgICAgICAgICAgICAgIDx0ZXh0Pjk5CjIwMQoyMDA8L3RleHQ+CiAgICAgIDwvc3RkaW4+CiAgICAgIDxleHBlY3RlZD4KICAgICAgICAgICAgICAgIDx0ZXh0PkVudGVyIGFuIGludGVnZXIgaW4gdGhlIHJhbmdlIDEwMCB0byAyMDAgaW5jbHVzaXZlOiA5OQpTb3JyeSwgdGhhdCdzIG5vdCBpbiB0aGUgcmVxdWlyZWQgcmFuZ2UKRW50ZXIgYW4gaW50ZWdlciBpbiB0aGUgcmFuZ2UgMTAwIHRvIDIwMCBpbmNsdXNpdmU6IDIwMQpTb3JyeSwgdGhhdCdzIG5vdCBpbiB0aGUgcmVxdWlyZWQgcmFuZ2UKRW50ZXIgYW4gaW50ZWdlciBpbiB0aGUgcmFuZ2UgMTAwIHRvIDIwMCBpbmNsdXNpdmU6IDIwMApZb3UgZ2F2ZSBtZSAyMDAhPC90ZXh0PgogICAgICA8L2V4cGVjdGVkPgogICAgICA8ZXh0cmE+CiAgICAgICAgICAgICAgICA8dGV4dD48L3RleHQ+CiAgICAgIDwvZXh0cmE+CiAgICAgIDxkaXNwbGF5PgogICAgICAgICAgICAgICAgPHRleHQ+U0hPVzwvdGV4dD4KICAgICAgPC9kaXNwbGF5PgogICAgPC90ZXN0Y2FzZT4KICAgIDwvdGVzdGNhc2VzPgogIDwvcXVlc3Rpb24+Cgo8L3F1aXo+</file>
    </questiontext>
    <generalfeedback format="html">
      <text></text>
    </generalfeedback>
    <defaultgrade>1</defaultgrade>
    <penalty>0</penalty>
    <hidden>0</hidden>
    <idnumber></idnumber>
    <coderunnertype>python3_w_input</coderunnertype>
    <prototypetype>0</prototypetype>
    <allornothing>1</allornothing>
    <penaltyregime>10, 20, ...</penaltyregime>
    <precheck>0</precheck>
    <hidecheck>0</hidecheck>
    <showsource>0</showsource>
    <answerboxlines>9</answerboxlines>
    <answerboxcolumns></answerboxcolumns>
    <answerpreload><![CDATA[{"answer_code":["def get_int(low, high):\n    '''Ask the user for an int in the given range'''\n    prompt = f\"Enter an integer in the range {low} to {high} inclusive: \"\n    n = int(input(prompt))\n    while n < low or n > high:\n        print(\"Sorry, that's not in the required range\")\n        n = int(input(prompt))\n    return n"],"test_code":["n = get_int(3, 7)\nprint(f\"You gave me {n}!\")"],"show_hide":["1"],"prefix_ans":["1"]}]]></answerpreload>
    <globalextra><![CDATA[import sys, io, subprocess, ast, traceback, json, locale

locale.setlocale(locale.LC_ALL, "C.UTF-8")
MAX_OUTPUT_CHARS = 30000

student_code = """
{| ANSWER_CODE |}
{| SCRATCHPAD_CODE |}
"""

subproc_code = """
import sys
MAX_OUTPUT_CHARS = 30000
__saved_input__ = input

def input(prompt=''):
    try:
        line = __saved_input__()
    except EOFError:
        print(prompt, end = '')
        sys.stderr.flush()
        sys.stdout.flush()
        sys.exit(42)
    print(prompt, end='')
    print(line)
    return line

__saved_print__ = print
__output_chars__ = 0

def print(*params, **keyparams):
    global __output_chars__
    for param in params:
        try:
            __output_chars__ += len(str(param))
        except:
            pass
    if __output_chars__ > 2 * MAX_OUTPUT_CHARS:
        __saved_print__("\\\\n*** Excessive output. Job aborted ***", file=sys.stderr)
        sys.exit(1)
    else:
        __saved_print__(*params, **keyparams)
"""

subproc_code += student_code


def truncated(s):
    return s if len(s) < MAX_OUTPUT_CHARS else s[:MAX_OUTPUT_CHARS] + " ... (truncated)"


def check_syntax():
    try:
        ast.parse(student_code)
        return ""
    except SyntaxError:
        catcher = io.StringIO()
        traceback.print_exc(limit=0, file=catcher)
        return catcher.getvalue()


stdout = ""
stderr = check_syntax()
if stderr == "":  # No syntax errors
    program_code = subproc_code
    with open("prog.py", "w", encoding="utf-8") as outfile:
        outfile.write(program_code)
    proc = subprocess.Popen(
        [sys.executable, "prog.py"],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
    )
    try:
        stdout, stderr = proc.communicate(timeout=3)
        returncode = proc.returncode
    except subprocess.TimeoutExpired:
        proc.kill()
        stdout, stderr = proc.communicate()
        returncode = 13


else:
    returncode = 1  # Syntax errors

output = {
    "returncode": returncode,
    "stdout": truncated(stdout),
    "stderr": truncated(stderr),
    "files": [],
}

print(json.dumps(output))
]]></globalextra>
    <useace></useace>
    <resultcolumns></resultcolumns>
    <template><![CDATA[__saved_input__ = input
def input(prompt=''):
    s = __saved_input__(prompt)
    print(s)
    return s

{{ STUDENT_ANSWER }}
SEPARATOR = "#<ab@17943918#@>#"

{% for TEST in TESTCASES %}
{{ TEST.testcode }}
{% if not loop.last %}
print(SEPARATOR)
{% endif %}
{% endfor %}]]></template>
    <iscombinatortemplate></iscombinatortemplate>
    <allowmultiplestdins></allowmultiplestdins>
    <answer><![CDATA[{"answer_code":["def get_int(low, high):\n    prompt = f\"Enter an integer in the range {low} to {high} inclusive: \"\n    n = int(input(prompt))\n    while n < low or n > high:\n        print(\"Sorry, that's not in the required range\")\n        n = int(input(prompt))\n    return n\n    "],"test_code":[""],"show_hide":["1"],"prefix_ans":["1"]}]]></answer>
    <validateonsave>1</validateonsave>
    <testsplitterre></testsplitterre>
    <language></language>
    <acelang></acelang>
    <sandbox></sandbox>
    <grader></grader>
    <cputimelimitsecs></cputimelimitsecs>
    <memlimitmb></memlimitmb>
    <sandboxparams></sandboxparams>
    <templateparams></templateparams>
    <hoisttemplateparams>1</hoisttemplateparams>
    <extractcodefromjson>1</extractcodefromjson>
    <templateparamslang>None</templateparamslang>
    <templateparamsevalpertry>0</templateparamsevalpertry>
    <templateparamsevald>{}</templateparamsevald>
    <twigall>0</twigall>
    <uiplugin>scratchpad</uiplugin>
    <uiparameters><![CDATA[{
  "wrapper_src": "globalextra",
  "output_display_mode": "json",
  "escape": true
}]]></uiparameters>
    <attachments>0</attachments>
    <attachmentsrequired>0</attachmentsrequired>
    <maxfilesize>10240</maxfilesize>
    <filenamesregex></filenamesregex>
    <filenamesexplain></filenamesexplain>
    <displayfeedback>1</displayfeedback>
    <giveupallowed>0</giveupallowed>
    <prototypeextra></prototypeextra>
    <testcases>
      <testcase testtype="0" useasexample="1" hiderestiffail="0" mark="1.0000000" >
      <testcode>
                <text><![CDATA[n = get_int(3, 7)
print(f"You gave me {n}!")]]></text>
      </testcode>
      <stdin>
                <text>2
8
0
5</text>
      </stdin>
      <expected>
                <text>Enter an integer in the range 3 to 7 inclusive: 2
Sorry, that's not in the required range
Enter an integer in the range 3 to 7 inclusive: 8
Sorry, that's not in the required range
Enter an integer in the range 3 to 7 inclusive: 0
Sorry, that's not in the required range
Enter an integer in the range 3 to 7 inclusive: 5
You gave me 5!
</text>
      </expected>
      <extra>
                <text></text>
      </extra>
      <display>
                <text>SHOW</text>
      </display>
    </testcase>
      <testcase testtype="0" useasexample="0" hiderestiffail="0" mark="1.0000000" >
      <testcode>
                <text><![CDATA[n = get_int(100, 200)
print(f"You gave me {n}!")]]></text>
      </testcode>
      <stdin>
                <text>99
201
200</text>
      </stdin>
      <expected>
                <text>Enter an integer in the range 100 to 200 inclusive: 99
Sorry, that's not in the required range
Enter an integer in the range 100 to 200 inclusive: 201
Sorry, that's not in the required range
Enter an integer in the range 100 to 200 inclusive: 200
You gave me 200!</text>
      </expected>
      <extra>
                <text></text>
      </extra>
      <display>
                <text>SHOW</text>
      </display>
    </testcase>
    </testcases>
  </question>

</quiz>