/**
 * An automatically generated file, based on the files in `instructors/`.
 * We need to have the python code in these files made available in the 
 * JS files, so we load them in via a preprocessing step.
 */

var $INSTRUCTOR_MODULES_EXTENDED = {};

$INSTRUCTOR_MODULES_EXTENDED["instructor_append.py"] = "from instructor_utility import *\ndef append_group_on_change():\n    wrong_not_append_to_list()\ndef append_group():\n    missing_append_in_iteration()\n    missing_append_list_initialization()\n    wrong_append_list_initiatization()\n    wrong_not_append_to_list()\n    append_list_wrong_slot()\ndef find_append_in(node):\n    appendList = []\n    calls = node.find_all(\"Call\")\n    for node in calls:\n        if node.func.attr == \"append\":\n            appendList.append(node)\n    return appendList\ndef missing_append_in_iteration():\n    ast = parse_program()\n    for_loops = ast.find_all(\"For\")\n    for loop in for_loops:\n        if len(find_append_in(loop)):\n            return False\n    explain(\"You must construct a list by appending values one at a time to the list.<br><br><i>(app_in_iter)<i></br>\")\n    return True\ndef wrong_not_append_to_list():\n    ast = parse_program()\n    for_loops = ast.find_all(\"For\")\n    for loop in for_loops:\n        append_nodes = find_append_in(loop)\n        for node in append_nodes:\n            listNode = node.func.value\n            if listNode.data_type != \"List\" and listNode.id != \"___\":\n                explain(\"Values can only be appended to a list. The variable <code>{0!s}</code> is either not initialized, not initialized correctly, or is confused with another variable.<br><br><i>(app_not_list)<i></br>\".format(listNode.id))\ndef missing_append_list_initialization():\n    ast = parse_program()\n    for_loops = ast.find_all(\"For\")\n    loop_appends = []\n    for loop in for_loops:\n        loop_appends.extend(find_append_in(loop));\n    assignments = ast.find_all(\"Assign\")\n    for append_call in loop_appends:\n        append_loc = append_call.lineno\n        append_var = append_call.func.value\n        found_init = False\n        for assignment in assignments:\n            if assignment.has(append_var) and assignment.lineno < append_loc:\n                found_init = True\n                break\n        if found_init == False and append_var.id != \"___\":\n            explain(\"The list variable <code>{0!s}</code> must be initialized.<br><br><i>(no_app_list_init)<i></br>\".format(append_var.id))\n            return True\n    return False\n\ndef wrong_append_list_initiatization():\n    ast = parse_program()\n    for_loops = ast.find_all(\"For\")\n    loop_appends = []\n    for loop in for_loops:\n        loop_appends.extend(find_append_in(loop));\n    assignments = ast.find_all(\"Assign\")\n    for append_call in loop_appends:\n        append_loc = append_call.lineno\n        append_var = append_call.func.value\n        init_fail = False\n        for assignment in assignments:\n            if assignment.has(append_var) and assignment.lineno < append_loc:\n                if assignment.value.ast_name == \"List\":\n                    if len(assignment.value.elts) != 0:\n                        init_fail = True\n                else:#or if its not even a list\n                    init_fail = True\n            if init_fail and append_var.id != \"___\":\n                explain(\"The list variable <code>{0!s}</code> is either not initialized correctly or mistaken for another variable. The list you append to should be initialized to an empty list.<br><br><i>(app_list_init)<i></br>\".format(append_var.id))\n                return\ndef append_list_wrong_slot():\n    ast = parse_program()\n    append_calls = find_append_in(ast)\n    for append_call in append_calls:\n        arg = append_call.args[0]\n        caller = append_call.func.value\n        if arg.ast_name == \"Name\":\n            if arg.data_type == \"List\" and caller.id != \"___\":\n                explain(\"You should not append a list (<code>{0!s}</code>) to <code>{1!s}</code>.<br><br><i>(app_list_slot)<i></br>\".format(arg.id, caller.id))"
$INSTRUCTOR_MODULES_EXTENDED["instructor_files.py"] = "from instructor import *\nfrom instructor_utility import *\n\ndef files_not_handled_correctly(*filenames):\n    if filenames and isinstance(filenames[0], int):\n        num_filenames = filenames[0]\n        actual_filenames = False\n    else:\n        num_filenames = len(filenames)\n        actual_filenames = True\n    ast = parse_program()\n    calls = ast.find_all(\"Call\")\n    called_open = []\n    closed = []\n    for a_call in calls:\n        if a_call.func.ast_name == 'Name':\n            if a_call.func.id == 'open':\n                if not a_call.args:\n                    gently(\"You have called the <code>open</code> function without any arguments. It needs a filename.\")\n                    return True\n                called_open.append(a_call)\n            elif a_call.func.id == 'close':\n                explain(\"You have attempted to call <code>close</code> as a function, but it is actually a method of the file object.\")\n                return True\n        elif a_call.func.ast_name == 'Attribute':\n            if a_call.func.attr == 'open':\n                gently(\"You have attempted to call <code>open</code> as a method, but it is actually a built-in function.\")\n                return True\n            elif a_call.func.attr == 'close':\n                closed.append(a_call)\n        \n    if len(called_open) < num_filenames:\n        gently(\"You have not opened all the files you were supposed to.\")\n        return True\n    elif len(called_open) > num_filenames:\n        gently(\"You have opened more files than you were supposed to.\")\n        return True\n    withs = ast.find_all(\"With\")\n    if len(withs) + len(closed) < num_filenames:\n        gently(\"You have not closed all the files you were supposed to.\")\n        return True\n    elif len(withs) + len(closed) > num_filenames:\n        gently(\"You have closed more files than you were supposed to.\")\n        return True\n    if actual_filenames:\n        ensure_literal(*filenames)\n    return False\n"
$INSTRUCTOR_MODULES_EXTENDED["instructor_filter.py"] = "from instructor_utility import *\ndef filter_group():\n    missing_if_in_for()\n    append_not_in_if()\n'''\nName: missing_if_in_for\nPattern:\nmissing\nfor <item> in ___ :\n    if …<item> … :\n\nFeedback: The arrangement of decision and iteration is not correct for the filter pattern.\n\n'''\ndef missing_if_in_for():\n    ast = parse_program()\n    loops = ast.find_all(\"For\")\n    for loop in loops:\n        iter_prop = loop.target\n        ifs = loop.find_all(\"If\")\n        if len(ifs) > 0:\n        	return False\n    explain(\"The arrangement of decision and iteration is not correct for the filter pattern.<br><br><i>(missing_if_in_for)<i></br>\")\n    return True\n'''\nName: append_not_in_if\nPattern:\nmissing\nif … :\n   ___.append(___)\n\nFeedback: Only items satisfying some condition should be appended to the list.\n\n'''\ndef append_not_in_if():\n    ast = parse_program()\n    ifs = ast.find_all(\"If\")\n    for if_block in ifs:\n        calls = if_block.find_all(\"Call\")\n        for node in calls:\n            if node.func.attr == \"append\":\n                return False\n    explain(\"Only items satisfying some condition should be appended to the list.<br><br><i>(app_not_in_if)<i></br>\")\n    return True"
$INSTRUCTOR_MODULES_EXTENDED["instructor_functions.py"] = "from instructor import *\n\nDELTA = 0.001\n\ndef match_signature(name, length, *parameters):\n    ast = parse_program()\n    defs = ast.find_all('FunctionDef')\n    for a_def in defs:\n        if a_def._name == name:\n            found_length = len(a_def.args.args)\n            if found_length < length:\n                gently(\"The function named <code>{}</code> has fewer parameters ({}) than expected ({}).\".format(name, found_length, length))\n            elif found_length > length:\n                gently(\"The function named <code>{}</code> has more parameters ({}) than expected ({}).\".format(name, found_length, length))\n            elif parameters:\n                for parameter, arg in zip(parameters, a_def.args.args):\n                    if arg.id != parameter:\n                        gently(\"Error in definition of <code>{}</code>. Expected a parameter named {}, instead found {}.\".format(name, parameter, arg.id))\n                else:\n                    return a_def\n            else:\n                return a_def\n    else:\n        gently(\"No function named <code>{}</code> was found.\".format(name))\n    return None\n    \ndef output_test(name, *tests):\n    if name in student.data:\n        the_function = student.data[name]\n        if callable(the_function):\n            for test in tests:\n                inp = test[:-1]\n                out = test[-1]\n                tip = \"\"\n                if isinstance(out, tuple):\n                    tip = \"<br><br>\"+out[1]\n                    out = out[0]\n                template = \"Your <code>{}</code> function did not produce the correct printed output.<br>Given arguments: <code>{}</code><br>Expected output: <code>{}</code><br>Actual output: <code>{}</code>\"\n                reset_output()\n                the_function(*inp)\n                test_out = get_output()\n                inputs = ', '.join([\"<code>{}</code>\".format(repr(i)) for i in inp])\n                if isinstance(out, str):\n                    if len(test_out) < 1:\n                        gently(template.format(name, inputs, repr(out), \"<i>No output</i>\", tip))\n                        return None\n                    elif len(test_out) > 1:\n                        gently(template.format(name, inputs, repr(out), \"<i>Too many outputs</i>\", tip))\n                        return None\n                    elif out not in test_out:\n                        gently(template.format(name, inputs, repr(out), repr(test_out[0]), tip))\n                        return None\n                elif out != test_out:\n                    out = '<pre>{}</pre>'.format('\\n'.join(out))\n                    test_out = '<pre>{}</pre>'.format('\\n'.join(test_out))\n                    gently(template.format(name, inputs, out, test_out, tip))\n                    return None\n            else:\n                return the_function\n        else:\n            gently(\"You defined {}, but did not define it as a function.\".format(name))\n            return None\n    else:\n        gently(\"The function <code>{}</code> was not defined.\".format(name))\n        return None\n\n    \ndef unit_test(name, *tests):\n    if name in student.data:\n        the_function = student.data[name]\n        if callable(the_function):\n            for test in tests:\n                inp = test[:-1]\n                out = test[-1]\n                tip = \"\"\n                if isinstance(out, tuple):\n                    tip = \"<br><br>\"+out[1]\n                    out = out[0]\n                message = \"Your <code>{}</code> function did not return the right value.<br>Given arguments: {}<br>Expected return: <code>{}</code><br>Actually returned: <code>{}</code>{}\"\n                test_out = the_function(*inp)\n                inputs = ', '.join([\"<code>{}</code>\".format(repr(i)) for i in inp])\n                message = message.format(name, inputs, repr(out), repr(test_out), tip)\n                if (isinstance(out, float) and \n                    isinstance(test_out, (float, int)) and\n                    abs(out-test_out) < DELTA):\n                    continue\n                elif out != test_out:\n                    gently(message)\n                    return None\n            else:\n                return the_function\n        else:\n            gently(\"You defined {}, but did not define it as a function.\".format(name))\n            return None\n    else:\n        gently(\"The function <code>{}</code> was not defined.\".format(name))\n        return None\n"
$INSTRUCTOR_MODULES_EXTENDED["instructor_histogram.py"] = "from instructor_utility import *\ndef histogram_group():\n    histogram_argument_not_list()\n    histogram_wrong_list()\n    histogram_missing()\n    plot_show_missing()\n'''\nName: histogram_missing\nPattern:\n\nMissing\n   plt.hist(___)\n\nFeedback: The program should display a histogram.\n\n'''\ndef histogram_missing():\n    ast = parse_program()\n    calls = ast.find_all(\"Call\")\n    plotting = False\n    for call in calls:\n        if call.func.attr == \"hist\" and call.func.value.id == \"plt\":\n            plotting = True\n            break\n    if plotting == False:\n        explain(\"The program should display a histogram.<br><br><i>(histo_missing)<i></br>\")\n    return not plotting\n'''\nName: plot_show_missing\nPattern:\nMissing\n   plt.show()\n\nFeedback: The plot must be explicitly shown to appear in the Printer area.\n'''\ndef plot_show_missing():\n    ast = parse_program()\n    calls = ast.find_all(\"Call\")\n    plotting = False\n    for call in calls:\n        if call.func.attr == \"show\" and call.func.value.id == \"plt\":\n            plotting = True\n            break\n    if plotting == False:\n        explain(\"The plot must be explicitly shown to appear in the Printer area.<br><br><i>(plot_show_missing)<i></br>\")\n    return not plotting\n'''\nName: histogram_argument_not_list\nPattern:\n   plt.hist(<argument>)\nWhere type(<argument>) is not \"list\"\n\nFeedback: Making a histogram requires a list; <argument> is not a list.\n\n'''\ndef histogram_argument_not_list():\n    ast = parse_program()\n    calls = ast.find_all(\"Call\")\n    arg_name = \"\"\n    for call in calls:\n        if call.func.attr == \"hist\" and call.func.value.id == \"plt\":\n            arg = call.args[0]\n            if arg != None and not (arg.data_type == \"List\" or arg.ast_name == \"List\"):\n                arg_name = arg.id\n                break\n    if arg_name != \"\":\n        if arg_name == \"___\":\n            explain(\"Making a histogram requires a list; the list is missing.<br><br><i>(hist_arg_not_list_blank)<i></br>\")\n        else:\n            explain(\"Making a histogram requires a list; <code>{0!s}</code> is not a list.<br><br><i>(hist_arg_not_list)<i></br>\".format(arg_name))\n    return arg_name != \"\"\n'''\nName: histogram_wrong_list\nPattern:\n\nfor ___ in ___:\n   <target>.append(___)\nplt.hist(<list>)\n\nwhere name(<target>) != name(<list>)\n\nFeedback: The list created in the iteration is not the list being used to create the histogram.\n\n'''\n\ndef histogram_wrong_list():\n    ast = parse_program()\n    loops = ast.find_all(\"For\")\n    append_targets = []\n    for loop in loops:\n        calls = loop.find_all(\"Call\")\n        for call in calls:\n            if call.func.attr == \"append\":\n                append_targets.append(call.func.value)\n    all_proper_plot = True\n    #should probably actually check for the location of plt.hist\n    calls = ast.find_all(\"Call\")\n    for call in calls:\n        if call.func.attr == \"hist\" and call.func.value.id == \"plt\":\n            arg = call.args[0]\n            proper_plot = False\n            if arg.ast_name == \"Name\":\n                for name in append_targets:\n                    if name.id == arg.id:\n                        proper_plot = True\n                        break\n                if not proper_plot:\n                    all_proper_plot = False\n                    break\n            else:\n                all_proper_plot = False\n                break\n    if not all_proper_plot:\n        explain(\"The list created in the iteration is not the list being used to create the histogram.<br><br><i>(histo_wrong_list)<i></br>\")\n    return not all_proper_plot"
$INSTRUCTOR_MODULES_EXTENDED["instructor_imports.py"] = "from instructor import *\n\ndef ensure_imports(*modules):\n    ast = parse_program()\n    for module in modules:\n        imports= ast.find_all(\"Import\")\n        import_froms = ast.find_all(\"ImportFrom\")\n        if not imports and not import_froms:\n            gently(\"You need to import the <code>{}</code> module!\".format(module))\n            return True\n        success = False\n        if imports:\n            if any(alias._name == module\n                       for i in imports\n                       for alias in i.names):\n                success = True\n        if import_froms:\n            if any(i.module == module for i in import_froms):\n                success = True\n        if not success:\n            gently(\"You need to import the <code>{}</code> module.\".format(module))\n            return True\n    return False"
$INSTRUCTOR_MODULES_EXTENDED["instructor_iteration.py"] = "from instructor import *\ndef iteration_group():\n    list_initialization_misplaced()\n    wrong_target_is_list()\n    wrong_list_repeated_in_for()\n    missing_iterator_initialization()\n    list_not_initialized_on_run()\n    wrong_iterator_not_list()\n    missing_target_slot_empty()\n    missing_for_slot_empty()\n    wrong_target_reassigned()\ndef iteration_group_on_change():\n    wrong_target_is_list()\n    wrong_list_repeated_in_for()\n    wrong_iterator_not_list()\ndef all_for_loops():\n    ast = parse_program()\n    return ast.find_all(\"For\")\n#this conflics with list_repeated_in_for\ndef wrong_target_is_list():\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        iter_prop = loop.target\n        if iter_prop.ast_name == \"Name\" and iter_prop.data_type == \"List\":\n            explain('The variable <code>{0!s}</code> is a list and should not be placed in the iteration variable slot of the \"for\" block<br><br><i>(target_is_list)<i></br>.'.format(iter_prop.id))\n    return False\n#this conflics with list_in_wrong_slot_in_for\ndef wrong_list_repeated_in_for():\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        iter_prop = loop.target\n        list_prop = loop.iter\n        if iter_prop.ast_name == \"Name\" and list_prop.ast_name == \"Name\" and iter_prop.id == list_prop.id and iter_prop.data_type == \"List\":\n            explain('The <code>{0!s}</code> variable can only appear once in the \"for\" block <br><br><i>(list_repeat)<i></br>'.format(list_prop.id))\n    return False\n#this isn't consistent with the pattern you wrote\ndef missing_iterator_initialization():\n    ast = parse_program()\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        list_prop = loop.iter\n        if list_prop.ast_name != \"List\" and (list_prop.data_type != \"List\" or def_use_error(list_prop)):\n            if list_prop.id == \"___\":\n                explain(\"The slot to hold a list in the iteration is empty.<br><br><i>(no_iter_init-blank)<i></br>\".format(list_prop.id))\n            else:\n                explain(\"The variable <code>{0!s}</code> is in the list slot of the iteration but is not a list.<br><br><i>(no_iter_init)<i></br>\".format(list_prop.id))\n            return True\n    return False\n#TODO: We need to cover the different cases for these\ndef wrong_iterator_not_list():\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        list_prop = loop.iter\n        if list_prop.ast_name != \"List\" and list_prop.data_type != \"List\" and list_prop.id != \"___\":\n            if list_prop.ast_name == \"Name\":\n                explain(\"The variable <code>{0!s}</code> has been set to something that is not a list but is placed in the iteration block that must be a list.<br><br><i>(iter_not_list)<i></br>\".format(list_prop.id))\n                return True\n    return False\ndef missing_target_slot_empty():\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        iter_prop = loop.target\n        if iter_prop.id == \"___\":\n            explain(\"You must fill in the empty slot in the iteration.<br><br><i>(target_empty)<i></br>\")\n            return True\n    return False\ndef list_not_initialized_on_run():\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        list_prop = loop.iter\n        if list_prop.data_type == None:\n            explain(\"The list in your for loop has not been initialized<br><br><i>(no_list_init)<i></br>\")\ndef list_initialization_misplaced():\n    for_loops = all_for_loops()\n    for loop in for_loops:\n        list_prop = loop.iter\n        if list_prop.data_type == \"List\" and def_use_error(list_prop):\n            explain(\"Initialization of <code>{0!s}</code> is a list but either in the wrong place or redefined<br><br><i>(list_init_misplaced)<i></br>\".format(list_prop.id))\ndef missing_for_slot_empty():\n    for_loops = all_for_loops()\n    is_missing = False\n    for loop in for_loops:\n        list_prop = loop.iter\n        iter_prop = loop.target\n        if list_prop.ast_name == \"Name\" and list_prop.id == \"___\":\n            is_missing = True\n            break\n        if iter_prop.ast_name == \"Name\" and iter_prop.id == \"___\":\n            is_missing = True\n            break\n    if is_missing:\n        explain(\"You must fill in the empty slot in the iteration.<br><br><i>(for_incomplete)<i></br>\")\ndef wrong_target_reassigned():\n    ast = parse_program()\n    for_loops = all_for_loops()\n    is_reassigned = False\n    iter_props = []\n    for loop in for_loops:\n        iter_props.append(loop.target)\n    assignments = ast.find_all(\"Assign\")\n    off_prop = \"\"\n    for assignment in assignments:\n        left = assignment.targets\n        for iter_prop in iter_props:\n            if left.id == iter_prop.id:\n                off_prop = left.id\n                is_reassigned = True\n                break\n        if is_reassigned:\n            break\n    if is_reassigned:\n        explain(\"The variable <code>{0!s}</code> has been reassigned. The iteration variable shouldn't be reassigned<br><br><i>(target_reassign)<i></br>\".format(off_prop))"
$INSTRUCTOR_MODULES_EXTENDED["instructor_plotting.py"] = "from instructor import *\nfrom instructor_utility import *\n\n\nPLOT_LABEL = {'plot': 'line plot', \n              'hist': 'histogram', \n              'scatter': 'scatter plot'}\ndef prevent_incorrect_plt():\n    ast = parse_program()\n    plts = [n for n in ast.find_all(\"Name\") if n.id == 'plt']\n    if plts and def_use_error(plts[0]):\n        explain(\"You have imported the <code>matplotlib.pyplot</code> module, but you did not rename it to <code>plt</code> using <code>import matplotlib.pyplot as plt</code>.\", 'verifier')\n        return True\n    for name in ['plot', 'hist', 'scatter', 'title', 'xlabel', 'ylabel', 'show']:\n        for n in ast.find_all(\"Name\"):\n            if n.id == name:\n                if def_use_error(n):\n                    explain(\"You have attempt to use the MatPlotLib function named <code>{0}</code>. However, you imported MatPlotLib in a way that does not allow you to use the function directly. I recommend you use <code>plt.{0}</code> instead, after you use <code>import matplotlib.pyplot as plt</code>.\".format(name), 'verifier')\n                    return True\n    return False\n    \ndef ensure_correct_plot(type):\n    for a_plot, label in PLOT_LABEL.items():\n        if type == a_plot:\n            if not function_is_called(type):\n                gently(\"You are not calling the <code>{}</code> function.\".format(type))\n                return True\n        elif function_is_called(a_plot):\n            gently(\"You have called the <code>{}</code> function, which makes a {}.\".format(a_plot, label))\n            return True\n    return False\n\ndef ensure_show():\n    if not function_is_called(\"show\"):\n        gently(\"You have not called <code>show</code> function, which actually creates the graph.\")\n        return True\n    return False\n\ndef compare_data(type, correct, given):\n    if type == 'hist':\n        return correct == given\n    elif not correct:\n        return False\n    elif isinstance(correct[0], list):\n        if len(correct[0]) != len(given):\n            return False\n        for x, y, g in zip(correct[0], correct[1], given):\n            if x != g['x'] or y != g['y']:\n                return False\n        return True\n    elif len(given) != len(correct):\n        return False\n    else:\n        for x, (g, c) in enumerate(zip(given, correct)):\n            if c != g['y'] or x != g['x']:\n                return False\n    return True\n            \n\nGRAPH_TYPES = {'line': 'line plot', \n              'hist': 'histogram', \n              'scatter': 'scatter plot'}\ndef check_for_plot(type, data):\n    '''\n    Returns any errors found for this plot type and data.\n    In other words, if it returns False, the plot was found correctly.\n    '''\n    type_found = False\n    data_found = False\n    for line in get_output():\n        if not isinstance(line, list):\n            continue\n        for a_plot in line:\n            data_found_here = compare_data(type, data, a_plot['data'])\n            if a_plot['type'] == type and data_found_here:\n                return False\n            if a_plot['type'] == type:\n                type_found = True\n            if a_plot['data'] == data_found_here:\n                data_found = True\n    type = GRAPH_TYPES.get(type, type)\n    if type_found and data_found:\n        return (\"You have created a {}, but it does not have the right data. That data appears to have been plotted in another graph.\".format(type))\n    elif type_found:\n        return (\"You have created a {}, but it does not have the right data.\".format(type))\n    elif data_found:\n        return (\"You have plotted the right data, but you appear to have not plotted it as a {}.\".format(type))\n    else:\n        return (\"You have not created a {} with the proper data.\".format(type))"
$INSTRUCTOR_MODULES_EXTENDED["instructor_printing.py"] = "from instructor import *\nfrom instructor_utility import *\n\ndef ensure_prints(count):\n    prints = find_function_calls('print')\n    if not prints:\n        gently(\"You are not using the print function!\")\n        return False\n    elif len(prints) > count:\n        gently(\"You are printing too many times!\")\n        return False\n    elif len(prints) < count:\n        gently(\"You are not printing enough things!\")\n        return False\n    else:\n        for a_print in prints:\n            if not is_top_level(a_print):\n                gently(\"You have a print function that is not at the top level. That is incorrect for this problem!\")\n                return False\n    return prints\n"
$INSTRUCTOR_MODULES_EXTENDED["instructor_upload.py"] = "import re\nfrom instructor import *\n\n# Feedback for author's name\ndef check_author_name_on_header():\n    code = get_program()\n    m_author = re.search('Author: \\\\w+', code)\n    if not m_author:\n        gently(\"You need to add your name to the author field at the top of the file.\")\n        \ndef get_plots(output):\n    # The p[0] is the first plot in a graph/show\n    return [p[0] for p in output if isinstance(p[0],dict)]\n    \ndef find_plot_of_type(plot_list, plot_type):\n    return [p['data'] for p in plot_list if p['type'] == plot_type]\n    \n# Feedback for copying output of the program in the documentation\ndef check_output_on_header(expected_output):\n    code = get_program()\n    expected_output = str(expected_output)\n    between_stars = code.split(\"*****\")[2].strip()\n    between_stars = \"\\\\n\".join([x.strip() for x in between_stars.split(\"\\\\n\")])\n    if 'REPLACE THIS TEXT WITH THE OUTPUT OF THIS PROGRAM' in between_stars:\n        gently(\"In your code, you need to 'REPLACE THIS TEXT WITH THE OUTPUT OF THIS PROGRAM'\")\n    elif not expected_output in between_stars:\n        gently(\"The output you copied between the *****, seems to be incorrect. You may have copied it into the wrong location, or it is incomplete.\")\n\ndef check_print_output(multiple_lines):\n    for line in multiple_lines:\n        if line not in get_output():\n            gently(\"You are not doing the correct calculation\")\n"
$INSTRUCTOR_MODULES_EXTENDED["instructor_utility.py"] = "from instructor import *\n\ndef is_top_level(ast_node):\n    ast = parse_program()\n    for element in ast.body:\n        if element.ast_name == 'Expr':\n            if element.value == ast_node:\n                return True\n        elif element == ast_node:\n            return True\n    return False\n    \ndef no_nested_function_definitions():\n    ast = parse_program()\n    defs = ast.find_all('FunctionDef')\n    for a_def in defs:\n        if not is_top_level(a_def):\n            gently(\"You have defined a function inside of another block. For instance, you may have placed it inside another function definition, or inside of a loop. Do not nest your function definition!\")\n            return False\n    return True\n    \ndef function_prints():\n    ast = parse_program()\n    defs = ast.find_all('FunctionDef')\n    for a_def in defs:\n        all_calls = a_def.find_all('Call')\n        for a_call in all_calls:\n            if a_call.func.ast_name == 'Name':\n                if a_call.func.id == 'print':\n                    return True\n    return False\n\ndef find_function_calls(name):\n    ast = parse_program()\n    all_calls = ast.find_all('Call')\n    calls = []\n    for a_call in all_calls:\n        if a_call.func.ast_name == 'Attribute':\n            if a_call.func.attr == name:\n                calls.append(a_call)\n        elif a_call.func.ast_name == 'Name':\n            if a_call.func.id == name:\n                calls.append(a_call)\n    return calls\n\ndef function_is_called(name):\n    return len(find_function_calls(name))\n    \ndef no_nonlist_nums():\n    pass\n    \ndef only_printing_variables():\n    ast = parse_program()\n    all_calls = ast.find_all('Call')\n    count = 0\n    for a_call in all_calls:\n        if a_call.func.ast_name == 'Name' and a_call.func.id == \"print\":\n            for arg in a_call.args:\n                if arg.ast_name != \"Name\":\n                    return False\n    return True\n\ndef find_prior_initializations(node):\n    if node.ast_name != \"Name\":\n        return None\n    ast = parse_program()\n    assignments = ast.find_all(\"Assign\")\n    cur_line_no = node.lineno\n    all_assignments = []\n    for assignment in assignments:\n        if assignment.has(node):\n            if assignment.lineno < cur_line_no:\n                all_assignments.append(assignment)\n    return all_assignments\n    \ndef prevent_unused_result():\n    ast = parse_program()\n    exprs = ast.find_all('Expr')\n    for expr in exprs:\n        if expr.value.ast_name == \"Call\":\n            a_call = expr.value\n            if a_call.func.ast_name == 'Attribute':\n                if a_call.func.attr == 'append':\n                    pass\n                elif a_call.func.attr in ('replace', 'strip', 'lstrip', 'rstrip'):\n                    gently(\"Remember! You cannot modify a string directly. Instead, you should assign the result back to the string variable.\")\n    \ndef prevent_builtin_usage(function_names):\n    # Prevent direction calls\n    ast = parse_program()\n    all_calls = ast.find_all('Call')\n    for a_call in all_calls:\n        if a_call.func.ast_name == 'Name':\n            if a_call.func.id in function_names:\n                explain(\"You cannot use the builtin function <code>{}</code>.\".format(a_call.func.id))\n                return a_call.func.id\n    # Prevent tricky redeclarations!\n    names = ast.find_all('Name')\n    seen = set()\n    for name in names:\n        if name.id not in seen:\n            if name.ctx == \"Load\" and name.id in function_names:\n                explain(\"You cannot use the builtin function <code>{}</code>. If you are naming a variable, consider a more specific name.\".format(name.id))\n            seen.add(name.id)\n            return name.id\n    return None\n    \ndef prevent_literal(*literals):\n    ast = parse_program()\n    str_values = [s.s for s in ast.find_all(\"Str\")]\n    num_values = [n.n for n in ast.find_all(\"Num\")]\n    for literal in literals:\n        if isinstance(literal, (int, float)):\n            if literal in num_values:\n                explain(\"Do not use the literal value <code>{}</code> in your code.\".format(repr(literal)))\n                return literal\n        elif isinstance(literal, str):\n            if literal in str_values:\n                explain(\"Do not use the literal value <code>{}</code> in your code.\".format(repr(literal)))\n                return literal\n    return False\ndef ensure_literal(*literals):\n    ast = parse_program()\n    str_values = [s.s for s in ast.find_all(\"Str\")]\n    num_values = [n.n for n in ast.find_all(\"Num\")]\n    for literal in literals:\n        if isinstance(literal, (int, float)):\n            if literal not in num_values:\n                explain(\"You need the literal value <code>{}</code> in your code.\".format(repr(literal)))\n                return literal\n        elif isinstance(literal, str):\n            if literal not in str_values:\n                explain(\"You need the literal value <code>{}</code> in your code.\".format(repr(literal)))\n                return literal\n    return False\n    \ndef prevent_advanced_iteration():\n    ast = parse_program()\n    if ast.find_all('While'):\n        explain(\"You should not use a <code>while</code> loop to solve this problem.\")\n    prevent_builtin_usage(['sum', 'map', 'filter', 'reduce', 'len', 'max', 'min',\n                           'max', 'sorted', 'all', 'any', 'getattr', 'setattr',\n                           'eval', 'exec', 'iter'])\n\nCOMPARE_OP_NAMES = {\n    \"==\": \"Eq\", \n    \"<\": \"Lt\", \n    \"<=\": \"Lte\", \n    \">=\": \"Gte\", \n    \">\": \"Gt\", \n    \"!=\": \"NotEq\", \n    \"is\": \"Is\", \n    \"is not\": \"IsNot\", \n    \"in\": \"In_\", \n    \"not in\": \"NotIn\"}\nBOOL_OP_NAMES = {\n    \"and\": \"And\",\n    \"or\": \"Or\"}\nBIN_OP_NAMES = {\n    \"+\": \"Add\",\n    \"-\": \"Sub\",\n    \"*\": \"Mult\",\n    \"/\": \"Div\",\n    \"//\": \"FloorDiv\",\n    \"%\": \"Mod\",\n    \"**\": \"Pow\",\n    \">>\": \"LShift\",\n    \"<<\": \"RShift\",\n    \"|\": \"BitOr\",\n    \"^\": \"BitXor\",\n    \"&\": \"BitAnd\",\n    \"@\": \"MatMult\"}\nUNARY_OP_NAMES = {\n    #\"+=\": \"UAdd\",\n    #\"-=\": \"USub\",\n    \"not\": \"Not\",\n    \"~\": \"Invert\"\n}\ndef ensure_operation(op_name, root=None):\n    if root is None:\n        root = parse_program()\n    result = find_operation(op_name, root)\n    if result == False:\n        gently(\"You are not using the <code>{}</code> operator.\".format(op_name))\n    return result\ndef prevent_operation(op_name, root=None):\n    if root is None:\n        root = parse_program()\n    result = find_operation(op_name, root)\n    if result != False:\n        gently(\"You may not use the <code>{}</code> operator.\".format(op_name))\n    return result\n    \ndef find_operation(op_name, root):    \n    if op_name in COMPARE_OP_NAMES:\n        compares = root.find_all(\"Compare\")\n        for compare in compares:\n            for op in compare.ops:\n                if op == COMPARE_OP_NAMES[op_name]:\n                    return compare\n    elif op_name in BOOL_OP_NAMES:\n        boolops = root.find_all(\"BoolOp\")\n        for boolop in boolops:\n            if boolop.op == BOOL_OP_NAMES[op_name]:\n                return boolop\n    elif op_name in BIN_OP_NAMES:\n        binops = root.find_all(\"BinOp\")\n        for binop in binops:\n            if binop.op == BIN_OP_NAMES[op_name]:\n                return binop\n    elif op_name in UNARY_OP_NAMES:\n        unaryops = root.find_all(\"UnaryOp\")\n        for unaryop in unaryops:\n            if unaryop.op == UNARY_OP_NAMES[op_name]:\n                return unaryop\n    return False\n'''\n    \n    mod.no_nonlist_nums = new Sk.builtin.func(function(source) {\n        Sk.builtin.pyCheckArgs(\"no_nonlist_nums\", arguments, 1, 1);\n        Sk.builtin.pyCheckType(\"source\", \"string\", Sk.builtin.checkString(source));\n        \n        source = source.v;\n        \n        var num_list = getNonListNums(source);\n        \n        var count = 0;\n        for (var i = 0, len = num_list.length; i < len; i = i+1) {\n            if (num_list[i].v != 0 && num_list[i].v != 1) {\n                return Sk.ffi.remapToPy(true);\n            }\n        }\n        return Sk.ffi.remapToPy(false);\n    });\n\n\n    \n    /**\n     * Given source code as a string, return a list of all of the AST elements\n     * that are Num (aka numeric literals) but that are not inside List elements.\n     *\n     * @param {String} source - Python source code.\n     * @returns {Array.number} The list of JavaScript numeric literals that were found.\n     */\n    function getNonListNums(source) {\n        if (!(source in parses)) {\n            var parse = Sk.parse(\"__main__\", source);\n            parses[source] = Sk.astFromParse(parse.cst, \"__main__\", parse.flags);\n        }\n        var ast = parses[source];\n        var visitor = new NodeVisitor();\n        var insideList = false;\n        var nums = [];\n        visitor.visit_List = function(node) {\n            insideList = true;\n            this.generic_visit(node);\n            insideList = false;\n        }\n        visitor.visit_Num = function(node) {\n            if (!insideList) {\n                nums.push(node.n);\n            }\n            this.generic_visit(node);\n        }\n        visitor.visit(ast);\n        return nums;\n    }\n    \n    \n '''"