{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1217a056",
   "metadata": {},
   "source": [
    "**Run the following cell before doing anything else** and then click the blue bar to the left of the cell to hide it, if it isn't already. Do **not** edit it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5602c569",
   "metadata": {
    "deletable": false,
    "editable": false,
    "init_cell": true,
    "jupyter": {
     "source_hidden": true
    },
    "tags": [
     "hide-input",
     "init_cell",
     "tutorial-setup"
    ]
   },
   "outputs": [],
   "source": [
    "from IPython import get_ipython\n",
    "from IPython.display import HTML, Javascript, clear_output, display\n",
    "import hashlib\n",
    "import hmac\n",
    "import html\n",
    "import json\n",
    "import re\n",
    "\n",
    "\n",
    "_TUTORIAL_CHECK_ORDER = [\n",
    "    \"1.1.1\",\n",
    "    \"2.1.1\",\n",
    "    \"2.3.1\",\n",
    "    \"3.1.1\",\n",
    "    \"3.1.2\",\n",
    "    \"3.1.3\",\n",
    "    \"3.1.4\",\n",
    "    \"3.1.5\",\n",
    "    \"3.1.6\",\n",
    "    \"3.1.7\",\n",
    "    \"3.1.8\",\n",
    "    \"3.1.9\",\n",
    "    \"3.1.10\",\n",
    "    \"3.1.11\",\n",
    "    \"3.1.12\",\n",
    "    \"3.2.1\",\n",
    "    \"3.2.2\",\n",
    "    \"3.2.3\",\n",
    "    \"4.1.1\",\n",
    "    \"4.3.1\",\n",
    "    \"4.4.1\",\n",
    "    \"4.5.1\",\n",
    "    \"4.5.2\",\n",
    "    \"5.0.1\",\n",
    "    \"5.1.1\",\n",
    "    \"5.1.2\",\n",
    "    \"5.2.1\",\n",
    "    \"5.3.1\",\n",
    "    \"5.3.2\",\n",
    "]\n",
    "\n",
    "_TUTORIAL_EXACT_CHECKS = {\n",
    "    \"3.1.1\": (\n",
    "        \"4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a\",\n",
    "        \"Enter only the value Python printed after 2 + 2, without the >>> prompt.\",\n",
    "    ),\n",
    "    \"3.1.3\": (\n",
    "        \"6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b\",\n",
    "        \"Enter only the value Python printed after 10 % 3.\",\n",
    "    ),\n",
    "    \"3.1.4\": (\n",
    "        \"4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce\",\n",
    "        \"Enter only the value Python printed after 13 // 4.\",\n",
    "    ),\n",
    "    \"3.1.6\": (\n",
    "        \"64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c\",\n",
    "        \"Enter only the exact output from running print(\\\"Hello world\\\").\",\n",
    "    ),\n",
    "    \"3.1.7\": (\n",
    "        \"3cbc87c7681f34db4617feaa2c8801931bc5e42d8d0f560e756dd4cd92885f18\",\n",
    "        \"Enter only the value Python printed after (10 * 10) > 99.\",\n",
    "    ),\n",
    "    \"3.1.8\": (\n",
    "        \"60a33e6cf5151f2d52eddae9685cfa270426aa89d8dbc7dfb854606f1d1a40fe\",\n",
    "        \"Enter only the value Python printed after \\\"t\\\" < \\\"s\\\".\",\n",
    "    ),\n",
    "    \"3.1.9\": (\n",
    "        \"3cbc87c7681f34db4617feaa2c8801931bc5e42d8d0f560e756dd4cd92885f18\",\n",
    "        \"Enter only the value Python printed after student_count > 0.\",\n",
    "    ),\n",
    "    \"3.1.10\": (\n",
    "        \"60a33e6cf5151f2d52eddae9685cfa270426aa89d8dbc7dfb854606f1d1a40fe\",\n",
    "        \"Enter only the value Python printed after student_count == 3.\",\n",
    "    ),\n",
    "    \"3.2.1\": (\n",
    "        \"4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a\",\n",
    "        \"Enter only the value shown by the IDLE Shell, without its prompt.\",\n",
    "    ),\n",
    "    \"4.5.1\": (\n",
    "        \"004f8ccec592795b5c04e05f80ad75f84b7c6a31d2133496cf060533230b4c87\",\n",
    "        \"Paste the three labelled lines printed by the current thebasics.py file.\",\n",
    "    ),\n",
    "    \"5.0.1\": (\n",
    "        \"cca40ce915c36fbc1e61631dfac52ed0a70a8dab59512a7a2b7feba18a91b11c\",\n",
    "        \"Paste only the final two lines printed after an unsupported version.\",\n",
    "    ),\n",
    "    \"5.1.1\": (\n",
    "        \"785f3ec7eb32f30b90cd0fcf3657d388b5ff4297f2f9716ff66e9b69c05ddd09\",\n",
    "        \"Enter only the result count shown before enabling either search option.\",\n",
    "    ),\n",
    "    \"5.1.2\": (\n",
    "        \"6f4b6612125fb3a0daecd2799dfd6c9c299424fd920f9b308110a2c1fbd8f443\",\n",
    "        \"Enter only the result count with Match Case and Match Whole Word enabled.\",\n",
    "    ),\n",
    "    \"5.2.1\": (\n",
    "        \"0894dec0445b1d72d0e465340cbba816907d3609c4d1c00a16ccc0033cb40701\",\n",
    "        \"Paste the four numbered Python 3.10 changelog lines in order.\",\n",
    "    ),\n",
    "}\n",
    "\n",
    "_TUTORIAL_OS_CHECKS = {\n",
    "    \"2.1.1\": \"python\",\n",
    "    \"4.1.1\": \"vscode\",\n",
    "}\n",
    "_TUTORIAL_PROGRESS_IDS = {\n",
    "    \"2.2.1\": \"2.3.1\",\n",
    "    \"2.2.2\": \"2.3.1\",\n",
    "    \"2.2.3\": \"2.3.1\",\n",
    "}\n",
    "_TUTORIAL_CHECK_BRANCHES = {\n",
    "    \"2.2.1\": {\"software\": \"python\", \"os\": \"windows\"},\n",
    "    \"2.2.2\": {\"software\": \"python\", \"os\": \"macos\"},\n",
    "    \"2.2.3\": {\"software\": \"python\", \"os\": \"linux\"},\n",
    "}\n",
    "_TUTORIAL_VERSION_CHECKS = {\"2.2.3\", \"2.3.1\", \"4.3.1\"}\n",
    "_TUTORIAL_TEXT_CHECKS = {\n",
    "    \"1.1.1\", \"2.2.1\", \"2.2.2\", \"3.1.5\", \"3.1.11\", \"3.1.12\", \"4.5.2\", \"5.3.1\"\n",
    "}\n",
    "_TUTORIAL_CONFIRM_CHECKS = {\n",
    "    \"3.1.2\": \"yes\",\n",
    "    \"4.4.1\": \"microsoft\",\n",
    "}\n",
    "_TUTORIAL_OPTIONAL_NOTES = {\"6.1.1\", \"6.2.1\", \"6.3.1\"}\n",
    "\n",
    "_TUTORIAL_SUCCESS_MESSAGES = {\n",
    "    \"1.1.1\": (\"Got it.\", \"Let's get started!\"),\n",
    "    \"2.2.1\": (\"Great!\", \"Let's explore the Python installation.\"),\n",
    "    \"2.2.2\": (\"Great!\", \"Let's explore the Python installation.\"),\n",
    "    \"2.2.3\": (\"Great!\", \"Let's explore the Python installation.\"),\n",
    "    \"2.3.1\": (\"Great!\", \"Let's explore the Python installation.\"),\n",
    "    \"3.1.1\": (\"Correct!\", \"Python evaluated the expression successfully.\"),\n",
    "    \"3.1.2\": (\"All right...\", \"let's dive into it then.\"),\n",
    "    \"3.1.3\": (\"Correct!\", \"\"),\n",
    "    \"3.1.4\": (\"Correct!\", \"\"),\n",
    "    \"3.1.5\": (\"Notes recorded.\", \"Ask your tutor to verify your answer.\"),\n",
    "    \"3.1.6\": (\"Correct!\", \"\"),\n",
    "    \"3.1.7\": (\"Correct!\", \"\"),\n",
    "    \"3.1.8\": (\"Correct!\", \"\"),\n",
    "    \"3.1.9\": (\"Correct!\", \"Now, we can use this variable throughout our work.\"),\n",
    "    \"3.1.10\": (\"Correct!\", \"\"),\n",
    "    \"3.1.11\": (\"Notes recorded.\", \"Again, verify your answer with your tutor.\"),\n",
    "    \"3.1.12\": (\"Notes recorded.\", \"Your tutor will discuss this challenge at the end of the tutorial.\"),\n",
    "    \"3.2.1\": (\"Correct!\", \"That's right—we're in an interactive shell again!\"),\n",
    "    \"3.2.2\": (\"Correct!\", \"Well done, you've written and executed a Python program!\"),\n",
    "    \"3.2.3\": (\"Correct!\", \"We can use this variable in our shell after we have run the file.\"),\n",
    "    \"4.3.1\": (\"Noted.\", \"VS Code is updated very frequently, so there are no automatic checks on this cell.\"),\n",
    "    \"4.4.1\": (\"That's right.\", \"Extensions can be built by anyone, from large corporations like Microsoft to individual developers.\"),\n",
    "    \"4.5.1\": (\"Correct!\", \"The command shell ran your Python file successfully.\"),\n",
    "    \"4.5.2\": (\"Notes recorded.\", \"Now let's explore some other functionality in VS Code.\"),\n",
    "    \"5.0.1\": (\"Correct!\", \"The program handled unsupported input clearly.\"),\n",
    "    \"5.1.1\": (\"Correct!\", \"\"),\n",
    "    \"5.1.2\": (\"Correct!\", \"\"),\n",
    "    \"5.2.1\": (\"Correct!\", \"\"),\n",
    "    \"5.3.1\": (\"Noted.\", \"Did you mean for this to happen?\"),\n",
    "    \"5.3.2\": (\"Correct!\", \"Well done, you have completed the core part of this tutorial!\"),\n",
    "}\n",
    "\n",
    "_previous_completed = set(globals().get(\"_TUTORIAL_COMPLETED\", set()))\n",
    "_TUTORIAL_COMPLETED = set()\n",
    "for _check_id in _TUTORIAL_CHECK_ORDER:\n",
    "    if _check_id not in _previous_completed:\n",
    "        break\n",
    "    _TUTORIAL_COMPLETED.add(_check_id)\n",
    "_TUTORIAL_COMPLETED.update(_previous_completed & _TUTORIAL_OPTIONAL_NOTES)\n",
    "\n",
    "_TUTORIAL_NAME = globals().get(\"_TUTORIAL_NAME\")\n",
    "_TUTORIAL_SELECTIONS = globals().get(\n",
    "    \"_TUTORIAL_SELECTIONS\", {\"python\": None, \"vscode\": None}\n",
    ")\n",
    "\n",
    "\n",
    "def _tutorial_progress_id(check_id):\n",
    "    return _TUTORIAL_PROGRESS_IDS.get(check_id, check_id)\n",
    "\n",
    "\n",
    "def _tutorial_reset_progress():\n",
    "    global _TUTORIAL_NAME, _TUTORIAL_SELECTIONS\n",
    "\n",
    "    _TUTORIAL_COMPLETED.clear()\n",
    "    _TUTORIAL_NAME = None\n",
    "    _TUTORIAL_SELECTIONS = {\"python\": None, \"vscode\": None}\n",
    "\n",
    "def _tutorial_normalize(value):\n",
    "    return \"\\n\".join(line.rstrip() for line in value.strip().splitlines())\n",
    "\n",
    "\n",
    "def _tutorial_digest(value):\n",
    "    return hashlib.sha256(value.encode(\"utf-8\")).hexdigest()\n",
    "\n",
    "\n",
    "def _tutorial_message(kind, title, message):\n",
    "    colours = {\n",
    "        \"correct\": (\"#166534\", \"#dcfce7\", \"#86efac\"),\n",
    "        \"incorrect\": (\"#991b1b\", \"#fef2f2\", \"#fca5a5\"),\n",
    "    }\n",
    "    text, background, border = colours[kind]\n",
    "    display(HTML(\n",
    "        f'<div style=\"margin:8px 0;padding:10px 12px;border-left:4px solid {border};'\n",
    "        f'background:{background};color:{text}\">'\n",
    "        f'<strong>{html.escape(title)}</strong> {html.escape(message)}</div>'\n",
    "    ))\n",
    "\n",
    "\n",
    "def _tutorial_check(line, cell):\n",
    "    global _TUTORIAL_NAME\n",
    "\n",
    "    clear_output(wait=True)\n",
    "    check_id = line.strip()\n",
    "    progress_id = _tutorial_progress_id(check_id)\n",
    "    answer = _tutorial_normalize(cell)\n",
    "    known_checks = set(_TUTORIAL_CHECK_ORDER) | _TUTORIAL_OPTIONAL_NOTES | set(_TUTORIAL_PROGRESS_IDS)\n",
    "\n",
    "    if check_id not in known_checks:\n",
    "        _tutorial_message(\"incorrect\", \"This check could not run.\", \"Please ask your tutor for help.\")\n",
    "        return\n",
    "\n",
    "    placeholders = (\n",
    "        \"PASTE\", \"WRITE NOTES HERE\", \"WRITE NAMES HERE\",\n",
    "        \"ENTER VERSION HERE\", \"TYPE WINDOWS\", \"TYPE YES HERE\",\n",
    "        \"TYPE OKAY HERE\", \"TYPE PUBLISHER HERE\",\n",
    "        \"ENTER COUNT HERE\",\n",
    "    )\n",
    "    if not answer or any(placeholder in answer.upper() for placeholder in placeholders):\n",
    "        _tutorial_message(\"incorrect\", \"No answer yet.\", \"Replace the placeholder, then run the cell again.\")\n",
    "        return\n",
    "\n",
    "    if progress_id in _TUTORIAL_CHECK_ORDER:\n",
    "        position = _TUTORIAL_CHECK_ORDER.index(progress_id)\n",
    "        missing = [\n",
    "            earlier for earlier in _TUTORIAL_CHECK_ORDER[:position]\n",
    "            if earlier not in _TUTORIAL_COMPLETED\n",
    "        ]\n",
    "        if missing:\n",
    "            _tutorial_message(\"incorrect\", \"Complete the previous step first.\", \"Return to the last visible check above.\")\n",
    "            return\n",
    "\n",
    "    correct = False\n",
    "    hint = \"Check your answer carefully and try again.\"\n",
    "    completion_details = {}\n",
    "\n",
    "    if check_id in _TUTORIAL_EXACT_CHECKS:\n",
    "        expected_digest, hint = _TUTORIAL_EXACT_CHECKS[check_id]\n",
    "        correct = hmac.compare_digest(_tutorial_digest(answer), expected_digest)\n",
    "    elif check_id == \"5.3.2\":\n",
    "        report_match = re.search(\n",
    "            r\"(?ms)^Noteworthy changes for Python 3\\.14:.*?^End of report$\",\n",
    "            answer,\n",
    "        )\n",
    "        expected_digest = \"2e7a485aa0004b46843663055792072eb0f7dcedc65864787d7c5fa8794fd045\"\n",
    "        correct = report_match is not None and hmac.compare_digest(\n",
    "            _tutorial_digest(report_match.group(0)), expected_digest\n",
    "        )\n",
    "        hint = (\n",
    "            \"Paste the output from 'Noteworthy changes for Python 3.14:' \"\n",
    "            \"through 'End of report'. Check that all four changes are numbered.\"\n",
    "        )\n",
    "    elif check_id in _TUTORIAL_OS_CHECKS:\n",
    "        selected_os = answer.casefold()\n",
    "        correct = selected_os in {\"windows\", \"macos\", \"linux\"}\n",
    "        hint = \"Type exactly Windows, macOS, or Linux.\"\n",
    "        if correct:\n",
    "            software = _TUTORIAL_OS_CHECKS[check_id]\n",
    "            _TUTORIAL_SELECTIONS[software] = selected_os\n",
    "            completion_details = {\"software\": software, \"os\": selected_os}\n",
    "    elif check_id in _TUTORIAL_VERSION_CHECKS:\n",
    "        correct = re.search(r\"\\d+(?:\\.\\d+)*\", answer) is not None\n",
    "        hint = \"Enter the installed version, including at least one number.\"\n",
    "    elif check_id in _TUTORIAL_TEXT_CHECKS or check_id in _TUTORIAL_OPTIONAL_NOTES:\n",
    "        correct = bool(answer)\n",
    "        hint = \"Write something before running the cell.\"\n",
    "    elif check_id in _TUTORIAL_CONFIRM_CHECKS:\n",
    "        expected = _TUTORIAL_CONFIRM_CHECKS[check_id]\n",
    "        correct = answer.casefold() == expected\n",
    "        hint = f\"Type {expected}.\"\n",
    "    elif check_id == \"3.2.2\":\n",
    "        match = re.fullmatch(r\"(.+) is ready to program\", answer)\n",
    "        hint = \"Copy the complete line, including the name and the words 'is ready to program'.\"\n",
    "        if match is not None:\n",
    "            correct = True\n",
    "            _TUTORIAL_NAME = match.group(1)\n",
    "    elif check_id == \"3.2.3\":\n",
    "        correct = _TUTORIAL_NAME is not None and answer == _TUTORIAL_NAME\n",
    "        hint = \"This should be the same name printed by the program in the previous section.\"\n",
    "\n",
    "    if not correct:\n",
    "        _tutorial_message(\"incorrect\", \"Not quite.\", hint)\n",
    "        return\n",
    "\n",
    "    already_completed = progress_id in _TUTORIAL_COMPLETED\n",
    "    if progress_id in _TUTORIAL_CHECK_ORDER and not already_completed:\n",
    "        position = _TUTORIAL_CHECK_ORDER.index(progress_id)\n",
    "        for later_id in _TUTORIAL_CHECK_ORDER[position + 1:]:\n",
    "            _TUTORIAL_COMPLETED.discard(later_id)\n",
    "        completion_details[\"resetFollowing\"] = True\n",
    "\n",
    "    _TUTORIAL_COMPLETED.add(progress_id)\n",
    "\n",
    "    if check_id in _TUTORIAL_OPTIONAL_NOTES:\n",
    "        _tutorial_message(\"correct\", \"Notes recorded.\", \"You can continue with any bonus task.\")\n",
    "        return\n",
    "\n",
    "    if check_id in _TUTORIAL_OS_CHECKS:\n",
    "        software_name = \"Python\" if _TUTORIAL_OS_CHECKS[check_id] == \"python\" else \"VS Code\"\n",
    "        display_os = {\"windows\": \"Windows\", \"macos\": \"macOS\", \"linux\": \"Linux\"}[\n",
    "            _TUTORIAL_SELECTIONS[_TUTORIAL_OS_CHECKS[check_id]]\n",
    "        ]\n",
    "        title, message = \"Choice recorded.\", f\"Showing the {display_os} instructions for {software_name}.\"\n",
    "    else:\n",
    "        title, message = _TUTORIAL_SUCCESS_MESSAGES.get(check_id, _TUTORIAL_SUCCESS_MESSAGES[progress_id])\n",
    "\n",
    "    _tutorial_message(\"correct\", title, message)\n",
    "    display(Javascript(\n",
    "        \"window.__tutorialProgress && window.__tutorialProgress.complete(\"\n",
    "        + json.dumps(check_id)\n",
    "        + \", \"\n",
    "        + json.dumps(completion_details)\n",
    "        + \");\"\n",
    "    ))\n",
    "\n",
    "\n",
    "_tutorial_shell = get_ipython()\n",
    "if _tutorial_shell is None:\n",
    "    raise RuntimeError(\"Run this cell with a Python Jupyter kernel.\")\n",
    "_tutorial_shell.register_magic_function(_tutorial_check, \"cell\", \"check\")\n",
    "_tutorial_message(\"correct\", \"Setup complete.\", \"The tutorial checks are ready.\")\n",
    "\n",
    "_tutorial_progress_javascript = r\"\"\"\n",
    "(() => {\n",
    "  const checkOrder = __CHECK_ORDER__;\n",
    "  const progressIds = __PROGRESS_IDS__;\n",
    "  const checkBranches = __CHECK_BRANCHES__;\n",
    "  const optionalNotes = __OPTIONAL_NOTES__;\n",
    "  const completedFromKernel = __COMPLETED__;\n",
    "  const selectionsFromKernel = __SELECTIONS__;\n",
    "  const hiddenClass = \"tutorial-progress-hidden\";\n",
    "  const styleId = \"tutorial-progress-style\";\n",
    "  const starterAnswers = {\n",
    "    \"1.1.1\": \"WRITE NAMES HERE\",\n",
    "    \"2.1.1\": \"TYPE WINDOWS, MACOS, OR LINUX HERE\",\n",
    "    \"2.2.1\": \"WRITE NOTES HERE\",\n",
    "    \"2.2.2\": \"WRITE NOTES HERE\",\n",
    "    \"2.2.3\": \"ENTER VERSION HERE\",\n",
    "    \"3.1.1\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.2\": \"TYPE YES HERE (IF YOU DARE)\",\n",
    "    \"3.1.3\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.4\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.5\": \"WRITE NOTES HERE\",\n",
    "    \"3.1.6\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.7\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.8\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.9\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.10\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.1.11\": \"WRITE NOTES HERE\",\n",
    "    \"3.1.12\": \"WRITE NOTES HERE\",\n",
    "    \"3.2.1\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.2.2\": \"PASTE OUTPUT HERE\",\n",
    "    \"3.2.3\": \"PASTE OUTPUT HERE\",\n",
    "    \"4.1.1\": \"TYPE WINDOWS, MACOS, OR LINUX HERE\",\n",
    "    \"4.3.1\": \"ENTER VERSION HERE\",\n",
    "    \"4.4.1\": \"TYPE PUBLISHER HERE\",\n",
    "    \"4.5.1\": \"PASTE OUTPUT HERE\",\n",
    "    \"4.5.2\": \"WRITE NOTES HERE\",\n",
    "    \"5.0.1\": \"PASTE OUTPUT HERE\",\n",
    "    \"5.1.1\": \"ENTER COUNT HERE\",\n",
    "    \"5.1.2\": \"ENTER COUNT HERE\",\n",
    "    \"5.2.1\": \"PASTE OUTPUT HERE\",\n",
    "    \"5.3.1\": \"WRITE NOTES HERE\",\n",
    "    \"5.3.2\": \"PASTE OUTPUT HERE\",\n",
    "    \"6.1.1\": \"WRITE NOTES HERE\",\n",
    "    \"6.2.1\": \"WRITE NOTES HERE\",\n",
    "    \"6.3.1\": \"WRITE NOTES HERE\",\n",
    "  };\n",
    "\n",
    "  if (!document.getElementById(styleId)) {\n",
    "    const style = document.createElement(\"style\");\n",
    "    style.id = styleId;\n",
    "    style.textContent = `.${hiddenClass} { display: none !important; }`;\n",
    "    document.head.appendChild(style);\n",
    "  }\n",
    "\n",
    "  const previous = window.__tutorialProgress;\n",
    "  if (previous && previous.observer) previous.observer.disconnect();\n",
    "\n",
    "  const state = {\n",
    "    completed: new Set(completedFromKernel),\n",
    "    selections: { ...selectionsFromKernel },\n",
    "    observer: null,\n",
    "    scheduled: false,\n",
    "  };\n",
    "\n",
    "  function progressId(id) {\n",
    "    return progressIds[id] || id;\n",
    "  }\n",
    "\n",
    "  function visibleNotebook() {\n",
    "    const scriptNotebook = document.currentScript &&\n",
    "      document.currentScript.closest(\".jp-Notebook, #notebook-container\");\n",
    "    if (scriptNotebook) return scriptNotebook;\n",
    "    const candidates = [...document.querySelectorAll(\".jp-Notebook, #notebook-container\")];\n",
    "    return candidates.find((node) => node.offsetParent !== null) || candidates[0] || null;\n",
    "  }\n",
    "\n",
    "  function currentNotebookPanel() {\n",
    "    const apps = [\n",
    "      window.jupyterapp,\n",
    "      window.jupyterlab,\n",
    "      window.jupyterLab,\n",
    "      window.jupyterFrontEnd,\n",
    "      window.jupyterApp,\n",
    "    ];\n",
    "    for (const app of apps) {\n",
    "      const widget = app && app.shell && app.shell.currentWidget;\n",
    "      if (widget && widget.content && widget.content.model && widget.context) return widget;\n",
    "    }\n",
    "    return null;\n",
    "  }\n",
    "\n",
    "  state.notebook = visibleNotebook();\n",
    "\n",
    "  if (!state.notebook) {\n",
    "    const warning = document.createElement(\"div\");\n",
    "    warning.style.cssText = \"margin:8px 0;padding:10px 12px;border-left:4px solid #f59e0b;background:#fffbeb;color:#92400e;font-family:system-ui,sans-serif\";\n",
    "    warning.textContent = \"The checks are ready, but this notebook frontend does not allow automatic section reveal. The checks will still mark answers, but all sections may remain visible.\";\n",
    "    document.body.appendChild(warning);\n",
    "    return;\n",
    "  }\n",
    "\n",
    "  function cells() {\n",
    "    const selector = state.notebook.id === \"notebook-container\"\n",
    "      ? \":scope > .cell\"\n",
    "      : \".jp-Notebook-cell\";\n",
    "    return [...state.notebook.querySelectorAll(selector)].filter(\n",
    "      (cell) => !cell.closest(\".jp-Notebook\") || cell.closest(\".jp-Notebook\") === state.notebook\n",
    "    );\n",
    "  }\n",
    "\n",
    "  function source(cell) {\n",
    "    const classicEditor = cell.querySelector(\".CodeMirror\");\n",
    "    if (classicEditor && classicEditor.CodeMirror) return classicEditor.CodeMirror.getValue();\n",
    "    const modernEditor = cell.querySelector(\".cm-content\");\n",
    "    if (modernEditor) return modernEditor.innerText || modernEditor.textContent || \"\";\n",
    "    const input = cell.querySelector(\".input_area, .jp-InputArea-editor\");\n",
    "    return input ? (input.innerText || input.textContent || \"\") : \"\";\n",
    "  }\n",
    "\n",
    "  function checkId(cell) {\n",
    "    const match = source(cell).match(/^%%check\\s+([a-z0-9_.-]+)/m);\n",
    "    return match ? match[1] : null;\n",
    "  }\n",
    "\n",
    "  function renderedMarker(cell) {\n",
    "    return cell.querySelector(\"[data-tutorial-section]\");\n",
    "  }\n",
    "\n",
    "  function explicitSectionNumber(cell) {\n",
    "    const sectionMarker = renderedMarker(cell);\n",
    "    if (sectionMarker) return Number(sectionMarker.dataset.tutorialSection);\n",
    "    const markerMatch = source(cell).match(/data-tutorial-section=[\\\"'](\\d+)[\\\"']/);\n",
    "    if (markerMatch) return Number(markerMatch[1]);\n",
    "    const id = checkId(cell);\n",
    "    const progress = id ? progressId(id) : null;\n",
    "    const checkIndex = progress ? checkOrder.indexOf(progress) : -1;\n",
    "    if (checkIndex >= 0) return checkIndex;\n",
    "    if (id && optionalNotes.includes(id)) return checkOrder.length;\n",
    "    return null;\n",
    "  }\n",
    "\n",
    "  function sectionNumber(cell, notebookCells) {\n",
    "    const ownSection = explicitSectionNumber(cell);\n",
    "    if (ownSection !== null) return ownSection;\n",
    "    const index = notebookCells.indexOf(cell);\n",
    "    for (let cursor = index - 1; cursor >= 0; cursor -= 1) {\n",
    "      const inheritedSection = explicitSectionNumber(notebookCells[cursor]);\n",
    "      if (inheritedSection !== null) return inheritedSection;\n",
    "    }\n",
    "    return 0;\n",
    "  }\n",
    "\n",
    "  function branch(cell) {\n",
    "    const sectionMarker = renderedMarker(cell);\n",
    "    if (sectionMarker && sectionMarker.dataset.tutorialOs) {\n",
    "      return {\n",
    "        software: sectionMarker.dataset.tutorialSoftware,\n",
    "        os: sectionMarker.dataset.tutorialOs,\n",
    "      };\n",
    "    }\n",
    "    const id = checkId(cell);\n",
    "    if (id && checkBranches[id]) return checkBranches[id];\n",
    "    const cellSource = source(cell);\n",
    "    const software = cellSource.match(/data-tutorial-software=[\\\"']([^\\\"']+)[\\\"']/);\n",
    "    const os = cellSource.match(/data-tutorial-os=[\\\"']([^\\\"']+)[\\\"']/);\n",
    "    return software && os ? { software: software[1], os: os[1] } : null;\n",
    "  }\n",
    "\n",
    "  function refresh() {\n",
    "    state.scheduled = false;\n",
    "    let unlockedSection = 0;\n",
    "    for (const id of checkOrder) {\n",
    "      if (!state.completed.has(id)) break;\n",
    "      unlockedSection += 1;\n",
    "    }\n",
    "    const notebookCells = cells();\n",
    "    for (const cell of notebookCells) {\n",
    "      const requiredBranch = branch(cell);\n",
    "      const wrongBranch = requiredBranch &&\n",
    "        state.selections[requiredBranch.software] !== requiredBranch.os;\n",
    "      const locked = sectionNumber(cell, notebookCells) > unlockedSection;\n",
    "      cell.classList.toggle(hiddenClass, Boolean(locked || wrongBranch));\n",
    "    }\n",
    "    bindResetButtons();\n",
    "    window.dispatchEvent(new Event(\"resize\"));\n",
    "  }\n",
    "\n",
    "  function scheduleRefresh() {\n",
    "    if (state.scheduled) return;\n",
    "    state.scheduled = true;\n",
    "    requestAnimationFrame(refresh);\n",
    "  }\n",
    "\n",
    "  state.complete = (id, details = {}) => {\n",
    "    const progress = progressId(id);\n",
    "    if (!checkOrder.includes(progress)) return;\n",
    "    const position = checkOrder.indexOf(progress);\n",
    "    if (details.resetFollowing) {\n",
    "      for (const laterId of checkOrder.slice(position + 1)) state.completed.delete(laterId);\n",
    "    }\n",
    "    state.completed.add(progress);\n",
    "    if (details.software && details.os) state.selections[details.software] = details.os;\n",
    "    refresh();\n",
    "  };\n",
    "\n",
    "\n",
    "  function starterSource(id) {\n",
    "    return `%%check ${id}\\n${starterAnswers[id]}`;\n",
    "  }\n",
    "\n",
    "  function modelSource(cell) {\n",
    "    if (cell.sharedModel && cell.sharedModel.getSource) return cell.sharedModel.getSource();\n",
    "    if (cell.value && typeof cell.value.text === \"string\") return cell.value.text;\n",
    "    return \"\";\n",
    "  }\n",
    "\n",
    "  function clearDomOutput(cellNode) {\n",
    "    for (const output of cellNode.querySelectorAll(\".output, .output_wrapper, .jp-OutputArea, .jp-Cell-outputArea\")) {\n",
    "      output.replaceChildren();\n",
    "    }\n",
    "  }\n",
    "\n",
    "  function resetDomCheckCells() {\n",
    "    let resetCount = 0;\n",
    "    for (const cellNode of cells()) {\n",
    "      const id = checkId(cellNode);\n",
    "      if (!id || !starterAnswers[id]) continue;\n",
    "      const sourceText = starterSource(id);\n",
    "      const classicEditor = cellNode.querySelector(\".CodeMirror\");\n",
    "      if (classicEditor && classicEditor.CodeMirror) {\n",
    "        classicEditor.CodeMirror.setValue(sourceText);\n",
    "        clearDomOutput(cellNode);\n",
    "        resetCount += 1;\n",
    "      }\n",
    "    }\n",
    "    return resetCount;\n",
    "  }\n",
    "\n",
    "  async function resetNotebookCells() {\n",
    "    const classicNotebook = window.Jupyter && window.Jupyter.notebook;\n",
    "    if (classicNotebook && classicNotebook.get_cells) {\n",
    "      for (const cell of classicNotebook.get_cells()) {\n",
    "        const match = cell.get_text().match(/^%%check\\s+([a-z0-9_.-]+)/m);\n",
    "        if (!match || !starterAnswers[match[1]]) continue;\n",
    "        cell.set_text(starterSource(match[1]));\n",
    "        if (cell.clear_output) cell.clear_output();\n",
    "        if (cell.set_input_prompt) cell.set_input_prompt(null);\n",
    "      }\n",
    "      classicNotebook.set_dirty(true);\n",
    "      await classicNotebook.save_notebook();\n",
    "      return;\n",
    "    }\n",
    "\n",
    "    const panel = currentNotebookPanel();\n",
    "    const notebookModel = panel && panel.content && panel.content.model;\n",
    "    if (notebookModel && notebookModel.cells) {\n",
    "      for (let index = 0; index < notebookModel.cells.length; index += 1) {\n",
    "        const cell = notebookModel.cells.get(index);\n",
    "        const match = modelSource(cell).match(/^%%check\\s+([a-z0-9_.-]+)/m);\n",
    "        if (!match || !starterAnswers[match[1]]) continue;\n",
    "        if (cell.sharedModel && cell.sharedModel.setSource) {\n",
    "          cell.sharedModel.setSource(starterSource(match[1]));\n",
    "        } else if (cell.value && typeof cell.value.text === \"string\") {\n",
    "          cell.value.text = starterSource(match[1]);\n",
    "        }\n",
    "        if (cell.outputs && cell.outputs.clear) cell.outputs.clear();\n",
    "        if (\"executionCount\" in cell) cell.executionCount = null;\n",
    "      }\n",
    "      await panel.context.save();\n",
    "      return;\n",
    "    }\n",
    "\n",
    "    if (resetDomCheckCells() > 0) return;\n",
    "\n",
    "    throw new Error(\"This notebook frontend does not expose a writable notebook model.\");\n",
    "  }\n",
    "\n",
    "  async function resetKernelProgress() {\n",
    "    const code = \"_tutorial_reset_progress()\";\n",
    "    try {\n",
    "      const classicKernel = window.Jupyter && window.Jupyter.notebook && window.Jupyter.notebook.kernel;\n",
    "      if (classicKernel && classicKernel.execute) {\n",
    "        classicKernel.execute(code, {}, { silent: true, store_history: false });\n",
    "        return true;\n",
    "      }\n",
    "\n",
    "      const panel = currentNotebookPanel();\n",
    "      const kernel = panel && panel.sessionContext && panel.sessionContext.session &&\n",
    "        panel.sessionContext.session.kernel;\n",
    "      if (kernel && kernel.requestExecute) {\n",
    "        const future = kernel.requestExecute({ code, silent: true, store_history: false });\n",
    "        await future.done;\n",
    "        return true;\n",
    "      }\n",
    "    } catch (error) {\n",
    "      console.error(\"Could not reset tutorial kernel state\", error);\n",
    "    }\n",
    "    return false;\n",
    "  }\n",
    "\n",
    "  async function resetProgress(button) {\n",
    "    const confirmed = window.confirm(\n",
    "      \"Reset all tutorial progress? Every answer and check result will be cleared.\"\n",
    "    );\n",
    "    if (!confirmed) return;\n",
    "\n",
    "    button.disabled = true;\n",
    "    button.textContent = \"Resetting…\";\n",
    "    try {\n",
    "      await resetNotebookCells();\n",
    "      const kernelWasReset = await resetKernelProgress();\n",
    "      state.completed.clear();\n",
    "      state.selections = { python: null, vscode: null };\n",
    "      refresh();\n",
    "      state.notebook.scrollIntoView({ behavior: \"smooth\", block: \"start\" });\n",
    "      button.disabled = false;\n",
    "      button.textContent = \"Reset all tutorial progress\";\n",
    "      if (kernelWasReset) {\n",
    "        window.alert(\"Tutorial progress has been reset.\");\n",
    "      } else {\n",
    "        window.alert(\n",
    "          \"Answers were reset. Restart the kernel before beginning again to clear its saved progress too.\"\n",
    "        );\n",
    "      }\n",
    "    } catch (error) {\n",
    "      console.error(\"Could not reset tutorial progress\", error);\n",
    "      window.alert(`The tutorial could not be reset: ${error.message}`);\n",
    "      button.disabled = false;\n",
    "      button.textContent = \"Reset all tutorial progress\";\n",
    "    }\n",
    "  }\n",
    "\n",
    "  function bindResetButtons() {\n",
    "    for (const button of state.notebook.querySelectorAll(\"[data-tutorial-reset]\")) {\n",
    "      if (button.dataset.tutorialResetBound) continue;\n",
    "      button.dataset.tutorialResetBound = \"true\";\n",
    "      button.addEventListener(\"click\", () => resetProgress(button));\n",
    "    }\n",
    "  }\n",
    "\n",
    "  state.observer = new MutationObserver(scheduleRefresh);\n",
    "  state.observer.observe(state.notebook, { childList: true, subtree: true });\n",
    "  window.__tutorialProgress = state;\n",
    "  refresh();\n",
    "  setTimeout(refresh, 100);\n",
    "  setTimeout(refresh, 500);\n",
    "  setTimeout(refresh, 1500);\n",
    "})();\n",
    "\"\"\".replace(\"__CHECK_ORDER__\", json.dumps(_TUTORIAL_CHECK_ORDER)).replace(\n",
    "    \"__PROGRESS_IDS__\", json.dumps(_TUTORIAL_PROGRESS_IDS)\n",
    ").replace(\n",
    "    \"__CHECK_BRANCHES__\", json.dumps(_TUTORIAL_CHECK_BRANCHES)\n",
    ").replace(\n",
    "    \"__OPTIONAL_NOTES__\", json.dumps(sorted(_TUTORIAL_OPTIONAL_NOTES))\n",
    ").replace(\n",
    "    \"__COMPLETED__\", json.dumps(sorted(_TUTORIAL_COMPLETED))\n",
    ").replace(\n",
    "    \"__SELECTIONS__\", json.dumps(_TUTORIAL_SELECTIONS)\n",
    ")\n",
    "\n",
    "display(Javascript(_tutorial_progress_javascript))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24b39b44",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"0\" hidden></span>\n",
    "\n",
    "# Tutorial 1: The Tools of the Trade\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "Week 2 | Author: Rayo Verweij (<code>rayo.verweij@ed.ac.uk</code>)\n",
    "</div>\n",
    "\n",
    "Welcome to your first IP tutorial! While the weekly lectures have started to introduce you to basic programming concepts, these tutorials are where you will be **putting them into practice**, preparing you for both the course assignments as well as real-life software engineering.\n",
    "\n",
    "So far, in the lectures, you have worked within the controlled environment of a Jupyter notebook. Today, however, it's time to get into the weeds and **set up a complete Python development environment on your own laptop**. Using this, you'll practice some of the concepts we've seen so far, such as variables and conditionals, as well as learn some tips and tricks around efficient coding.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8239012",
   "metadata": {},
   "source": [
    "## 1 Introductions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6edbbeb1",
   "metadata": {},
   "source": [
    "First, find yourself a partner! Try and find someone at about the **same skill level** and with the **same operating system** as you, so you can work through issues together. If you're joining forces with someone you don't already know, introduce yourselves, why you joined Informatics, and what (if any) programming experience you already have.\n",
    "\n",
    "Throughout this tutorial, you will both work on your own laptops—both of you should leave this tutorial with a fully working Python and VS Code setup. You only need to fill out one version of this tutorial sheet, however.\n",
    "\n",
    "**But what if I already have Python and VS Code installed on my system?** Going through this tutorial step-by-step will ensure that you have all the necessary tools, and might get you to explore aspects of your Python and/or VS Code installations that you have not seen before. If you are done early, there are some bonus tasks at the end of the tutorial including researching other code editors or customising your VS Code setup.\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "<b>ℹ️ Checking your work</b>\n",
    "\n",
    "This tutorial uses interactive cells to allow you to check your work as you go along. In the cell below, replace the text `WRITE NAMES HERE` with your names, and run the cell using the ▶️ button or by pressing Ctrl+Enter while in the cell and the next section of the tutorial will appear.\n",
    "\n",
    "Leave each cell's `%%check` line in place; this is how the notebook identifies individual cells.\n",
    "\n",
    "While this cell will accept any text input, some of the later ones will only accept correct answers. If you get a cell wrong, use the hint provided to find out where you went wrong or ask your tutor to help you out!\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7832d5f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 1.1.1\n",
    "WRITE NAMES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "69f05f61",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"1\" hidden></span>\n",
    "\n",
    "## 2 Installing Python"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8b83840",
   "metadata": {},
   "source": [
    "What does it mean to 'install' a programming language?\n",
    "\n",
    "Downloading and installing Python actually installs a number of programs. The most important one is called the **Python interpreter**.\n",
    "\n",
    "There are hundreds of programming languages out there, but your operating system (Windows, macOS, or Linux) only 'understands' a few, and Python is _not_ one of them. The Python interpreter, then, is a program that allows you to run Python code by _interpreting_ it, that is, translating each line to code that your OS _does_ understand.\n",
    "\n",
    "In addition to the interpreter, the Python installation comes with a few additional tools, such as a text editor and some documentation, which we will all explore together.\n",
    "\n",
    "In this course we use **Python 3**, the latest major version of the language. Python 3.0 was released in 2008 and corrected several design problems in Python 2. Because converting older programs took time, Python 2 remained in use for many years. While official support for Python 2 ended in 2020, you may still find references to it online, so be careful to check when getting example code off the internet.\n",
    "\n",
    "Alright, with that out of the way, let's get going!\n",
    "\n",
    "<div class=\"alert alert-info\">\n",
    "<b>ℹ️ Working with text-based installers</b>\n",
    "\n",
    "Some Python installers ask questions in a terminal window rather than through a graphical user interface. Type <code>y</code> for <code>yes</code> or <code>n</code> for <code>no</code>, then press Enter.\n",
    "\n",
    "A capital letter shows the default choice. For example, <code>[y/N]</code> means <code>no</code> is the default, so pressing Enter without typing anything chooses no.\n",
    "</div>\n",
    "\n",
    "### 2.1 Choose your installation instructions\n",
    "\n",
    "Which operating system are you using? Type `Windows`, `macOS`, or `Linux` below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "998b23a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 2.1.1\n",
    "TYPE WINDOWS, MACOS, OR LINUX HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "72c0bf10",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"2\" data-tutorial-software=\"python\" data-tutorial-os=\"windows\" hidden></span>\n",
    "\n",
    "### 2.2 Windows installation\n",
    "\n",
    "1. Go to https://www.python.org/downloads/.\n",
    "2. Press the **Download Python install manager** button to start the download.\n",
    "3. Open the downloaded file and press **Install Python**.\n",
    "4. A terminal window will open that will prompt several questions. Some or all of these might appear, depending on whether or not you have installed Python on your machine before.\n",
    "    - If you get the message *The global shortcuts directory is not configured*, it will ask you to \"add the commands directory to your PATH\". Answer `y`.\n",
    "    - If you get the message *You do not have the latest Python runtime*, it will ask you to \"install CPython now\". Again, answer `y`.\n",
    "    - At the end, you will be asked to \"view online help\". Your answer here does not matter--answering yes will simply open a webpage.\n",
    "    - If you get any other messages that you do not understand, or somehow get stuck, let your tutor know as soon as possible!\n",
    "5. Open the **Windows Start menu**. You should now have a folder called *Python* and a shortcut to the *Python install manager*.\n",
    "\n",
    "The Python folder in your Start menu should include five items (with *x* depending on the version of your Python installation; 3.14 as of July 2026):\n",
    "\n",
    "- IDLE (Python 3.1x)\n",
    "- Python 3.1x\n",
    "- PyDoc (Python 3.1x)\n",
    "- Python 3.1x Manuals\n",
    "- Python 3.1x Online Documentation\n",
    "\n",
    "Have a look at the **manuals** and **online documentation** options first. Can you find out the difference between the two?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d5b6d7c",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 2.2.1\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce281998",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"2\" data-tutorial-software=\"python\" data-tutorial-os=\"macos\" hidden></span>\n",
    "\n",
    "### 2.2 macOS installation\n",
    "1. Go to https://www.python.org/downloads/\n",
    "2. Press the **Download Python 3.14.x** button at the top of the page.\n",
    "3. Open the downloaded `.pkg` file by double-clicking on it.\n",
    "4. Follow the installer prompts. Agree to any prompts it gives you.\n",
    "5. When the installation is finished, hit Close in the installer.\n",
    "    - If macOS prompts you to move the Python installer to the bin, you may do so.\n",
    "6. After installation, Finder should automatically open in a folder called Python 3.14.\n",
    "    - If not, open Finder, navigate to the Applications folder and this folder should be inside there.\n",
    "7. In this folder, there is a file called **Install Certificates.command**. This program installs some necessary files that allow Python to securely connect to websites, which you might need later.\n",
    "    - Double-click the file to run it.\n",
    "\t- When `[Process Completed]` appears on the screen, you can close this terminal window.\n",
    "\n",
    "Before moving on, let's explore some other files in this folder. Your installation should include:\n",
    "- ReadMe.rtf\n",
    "- License.rtf\n",
    "- Python Documentation.html\n",
    "\n",
    "What is the purpose of each file?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1fed951d",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 2.2.2\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a7aa7d31",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"2\" data-tutorial-software=\"python\" data-tutorial-os=\"linux\" hidden></span>\n",
    "\n",
    "### 2.2 Linux installation\n",
    "\n",
    "There are too many small differences between Linux distributions for us to provide comprehensive installation instructions for each; on top of that, many already include Python 3 by default.\n",
    "\n",
    "If you want to check whether you already have it installed:\n",
    "1. Open your application menu.\n",
    "2. Search for **Terminal** and open it.\n",
    "3. Type the following and press Enter:\n",
    "\n",
    "```bash\n",
    "python3 --version\n",
    "```\n",
    "\n",
    "If this prints a Python 3 version, you already have it. If not, go to your distributions software centre (App Manager, Software Manager, etc.) and search for Python 3.\n",
    "\n",
    "**Regardless** of whether you already have Python installed, for this tutorial, you'll need a text editing app called **IDLE 3**. You can find this in your distribution's software centre as well.\n",
    "\n",
    "Ask your tutor if you need any help!\n",
    "\n",
    "When you are ready, enter the Python version you found in the check cell below to continue.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3e123b6",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 2.2.3\n",
    "ENTER VERSION HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "43110af0",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"3\" hidden></span>\n",
    "\n",
    "## 3 Exploring Our Python Installation"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a45cdd5",
   "metadata": {},
   "source": [
    "### 3.1 REPL\n",
    "Let's try out our fresh new Python installation, shall we?\n",
    "\n",
    "On Windows, open the program that is simply called `Python 3.1x`.\n",
    "\n",
    "On macOS or Linux, find a program called the **Terminal** and open it. In this terminal, type the command `python3` and press Enter.\n",
    "\n",
    "Regardless of your machine, you will now have a window with a `>>>` prompt. At this prompt, type `2 + 2` and press Enter.\n",
    "\n",
    "What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c3ca18a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.1\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "228b6730",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"4\" hidden></span>\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>🥳 Course complete!!</b>\n",
    "\n",
    "Congratulations! You have written an expression in Python and executed it. That's it for us—you have now been introduced to programming.\n",
    "</div>\n",
    "\n",
    "What, you want to learn more? Are you sure?\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "812bb9cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.2\n",
    "TYPE YES HERE (IF YOU DARE)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8d6a858b",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"5\" hidden></span>\n",
    "\n",
    "We are now using the **Python interpreter**! Remember, your computer does not understand Python by itself, but the interpreter does!\n",
    "\n",
    "The Python interpreter has different **modes**. We are currently using it in **interactive mode**, providing us with a **shell**. The shell, recognised by its `>>>` prompt, allows us to send one command at a time to the interpreter and see the result immediately.\n",
    "\n",
    "Python's interactive shell follows a cycle called a **REPL**: _Read, Evaluate, Print, Loop_. It _reads_ what you enter, asks the interpreter to _evaluate_ (execute) it, _prints_ a result when there is one, and then _loops_ around, returning to the prompt.\n",
    "\n",
    "To recap:\n",
    "- The interactive shell allows us to send commands to the interpreter;\n",
    "- The interpreter executes the command and returns a result to the shell;\n",
    "- The shell displays the result and then asks for new input;\n",
    "\n",
    "...in a cycle known as REPL.\n",
    "\n",
    "Let's try it out. Type `10 % 3` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "74525478",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.3\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ba4723b",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"6\" hidden></span>\n",
    "\n",
    "Now type `13 // 4` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0d7637a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.4\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e05ed34",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"7\" hidden></span>\n",
    "\n",
    "Do you remember what the `//` and `%` operators do? Explain both in your own words."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4740488f",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.5\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b191d279",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"8\" hidden></span>\n",
    "\n",
    "Now type `print(\"Hello world\")` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a4dd8e22",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.6\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acc89e36",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"9\" hidden></span>\n",
    "\n",
    "Type `(10 * 10) > 99` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7360eafa",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.7\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd1f8304",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"10\" hidden></span>\n",
    "\n",
    "Type `\"t\" < \"s\"` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "873eb84a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.8\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c4204fc",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"11\" hidden></span>\n",
    "\n",
    "The interactive shell keeps the names you assign until it is restarted or closed.\n",
    "\n",
    "Type `student_count = 2` and press Enter. You should not get any output. Now, type `student_count > 0` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "08dab0ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.9\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b5e20f8",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"12\" hidden></span>\n",
    "\n",
    "Finally, type `student_count == 3` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f75248ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.10\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "652b9af7",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"13\" hidden></span>\n",
    "\n",
    "In your own words again, what is the difference between `=` and `==`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e483dcf8",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.11\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "531e1328",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"14\" hidden></span>\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "<b>Challenge: REPLication</b>\n",
    "\n",
    "The interactive shell can also accept a multi-line statement. Look at this <code>if</code> statement:\n",
    "</div>\n",
    "\n",
    "```python\n",
    "if 2 > 4:\n",
    "    print(\"Huh?\")\n",
    "else:\n",
    "    print(\"That's what I thought\")\n",
    "```\n",
    "\n",
    "<div class=\"alert alert-success\">\n",
    "Enter the prompt, pressing Enter after each line. What prompts appear as you go? How do you get the shell to execute the entire statement when you have entered each line?\n",
    "\n",
    "If you figure it out, add your notes below; if you get an error message and cannot solve it, simply copy in the error message. Your tutor will discuss this challenge at the end of the tutorial.\n",
    "</div>\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e8a4fe59",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.1.12\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0df59de",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"15\" hidden></span>\n",
    "\n",
    "### 3.2 IDLE\n",
    "An interactive shell is convenient for small experiments, but having to execute each statement one by one will get tiring quickly. For a longer program, it is easier to save code in a **file** and ask the interpreter to execute it all at once.\n",
    "\n",
    "For this, we'll need a text editor. Fortunately, our Python install has provided one for us: IDLE.\n",
    "\n",
    "IDLE stands for **Integrated Development and Learning Environment**. On Linux it might be called IDLE3. Close the interactive shell and open IDLE instead.\n",
    "\n",
    "You should get a window like this:\n",
    "\n",
    "![IDLE.png](IDLE.png)\n",
    "\n",
    "*The IDLE Shell with Python 3.14.6 on Windows 11.*\n",
    "\n",
    "Type `2 + 2` and press Enter. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd1da2a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.2.1\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "49d266cf",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"16\" hidden></span>\n",
    "\n",
    "As it turns out, IDLE actually has two main window types:\n",
    "\n",
    "- its own **Shell**, where the interpreter runs code interactively and displays output using a REPL; and\n",
    "- the **Editor**, where we can write and save Python source files.\n",
    "\n",
    "We've already explored interactive work, so let's create a file instead. A Python source file normally ends in `.py`.\n",
    "\n",
    "1. In IDLE, choose **File > New File**.\n",
    "2. Type this program:\n",
    "\n",
    "```python\n",
    "name = \"Sam\"\n",
    "ready = True\n",
    "\n",
    "if ready:\n",
    "    print(name, \"is ready to program\")\n",
    "else:\n",
    "    print(name, \"needs another minute\")\n",
    "```\n",
    "\n",
    "3. Change `Sam` to one of your names (or don't, if one of you happens to be called Sam, and would like to be the protagonist of this program).\n",
    "4. Save the file as `idle_ready.py` in a folder you can find again.\n",
    "5. Run it using **Run > Run Module**.\n",
    "\n",
    "The IDLE Shell appears again and displays the program's output. What does it display?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d4e0b70d",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.2.2\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08d386b1",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"17\" hidden></span>\n",
    "\n",
    "When we were using the interactive shell, we saw that when we assigned a variable, we could use that variable name throughout the rest of the session.\n",
    "\n",
    "As it turns out, the same is true for **names created in files** that are run in the IDLE Shell session!\n",
    "\n",
    "Directly in the IDLE Shell, run `print(name)`. What output do you get?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0a891b8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 3.2.3\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45308bf1",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"18\" hidden></span>\n",
    "\n",
    "## 4 Visual Studio Code"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fcdc452a",
   "metadata": {},
   "source": [
    "We can now run Python source files and IDLE gives us an editor for creating those files.\n",
    "\n",
    "However, IDLE is intentionally simple and can become limiting in projects with many files, different languages, or several collaborators. Therefore, in this course we will instead use a more capable code editor. While there are many to choose from, here we will install **Visual Studio Code**.\n",
    "\n",
    "VS Code is made by Microsoft and works on Windows, macOS, and Linux. It is popular because it is free, is based on an open-source project, and strikes a good balance between having many features and being relatively light-weight, in particular because of its **extension system**. Using extensions means not only that the functionality of VS Code can easily be extended, but also that anyone using it can tweak the editor to their own liking, and install only the programming language support that they need.\n",
    "\n",
    "Let's get going!\n",
    "\n",
    "### 4.1 Choose your installation instructions\n",
    "\n",
    "Which operating system are you using? Type `Windows`, `macOS`, or `Linux` below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ed9e11b",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 4.1.1\n",
    "TYPE WINDOWS, MACOS, OR LINUX HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e768583",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"19\" data-tutorial-software=\"vscode\" data-tutorial-os=\"windows\" hidden></span>\n",
    "\n",
    "### 4.2 Windows installation\n",
    "\n",
    "1. Go to https://code.visualstudio.com/download and choose the Windows download.\n",
    "2. Run the installer.\n",
    "3. On the \"Select Additional Tasks\" page, select **each** option under \"Other\":\n",
    "    - Add \"Open with Code\" action to Windows Explorer file context menu\n",
    "    - Add \"Open with Code\" action to Windows Explorer directory context menu\n",
    "    - Register Code as an editor for supported file types\n",
    "    - Add to PATH (requires restart)\n",
    "4. Click `Install` and launch VS Code when installation finishes."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b78cd74c",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"19\" data-tutorial-software=\"vscode\" data-tutorial-os=\"macos\" hidden></span>\n",
    "\n",
    "### 4.2 macOS installation\n",
    "1. Go to https://code.visualstudio.com/download and choose the macOS download.\n",
    "2. Open the downloaded `.dmg` file.\n",
    "3. Drag **Visual Studio Code.app** into the **Applications** folder.\n",
    "4. Open VS Code from the Applications folder.\n",
    "5. If macOS asks whether you want to open an app downloaded from the internet, say yes.\n",
    "\n",
    "Congratulations, you have installed VS Code! There is one more step we're going to take and that is to install Terminal support for VS Code. Just like you were able to run Python from the Terminal using the `python3` command, VS Code lets you run the app from the Terminal using the `code` command! While we will not use it in this tutorial yet, it will be a useful shortcut for the future.\n",
    "\n",
    "6. Open VS Code\n",
    "7. Open the Command Palette with `Cmd+Shift+P` - this is an interface in VS Code that allows you to change all sorts of settings\n",
    "8. Search for **Shell Command: Install `code` command in PATH** and click on it to run it.\n",
    "\n",
    "That's you set!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37bb9815",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"19\" data-tutorial-software=\"vscode\" data-tutorial-os=\"linux\" hidden></span>\n",
    "\n",
    "### 4.2 Linux installation\n",
    "\n",
    "1. Go to https://code.visualstudio.com/download\n",
    "2. Choose the package for your distribution:\n",
    "    - `.deb` for Debian, Ubuntu, and related distributions;\n",
    "    - `.rpm` for Fedora, Red Hat, openSUSE, and related distributions.\n",
    "3. Install the downloaded package with your distribution's graphical software installer or software centre.\n",
    "4. Launch VS Code from your application menu."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "705ea7aa",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"19\" hidden></span>\n",
    "\n",
    "### 4.3 Check your VS Code version\n",
    "\n",
    "Open **Help > About** (or **Code > About Visual Studio Code** on macOS) and enter the installed VS Code version below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44147a82",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 4.3.1\n",
    "ENTER VERSION HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "476b08d3",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"20\" hidden></span>\n",
    "\n",
    "### 4.4 Adding Python support to VS Code\n",
    "Technically, we can now use VS Code for editing our `.py` files. However, by default, VS Code does not have any Python-specific features. Installing the official **Python extension** adds integration with the Python interpreter so we can run our files directly in VS Code like we did in IDLE. It also adds some other useful features, such as autocomplete and error checking.\n",
    "\n",
    "Install Python support now:\n",
    "\n",
    "1. Open the Extensions sidebar. Its icon looks like four small blocks on the left-hand side of the editor. You can also use `Ctrl+Shift+X` on Windows/Linux or `Cmd+Shift+X` on macOS.\n",
    "2. Search for **Python**.\n",
    "3. Open the extension named **Python**.\n",
    "4. Select **Install**.\n",
    "\n",
    "The Python extension will install several related extensions, such as **Pylance** and **Python Debugger** automatically. You don't need to worry about those for now.\n",
    "\n",
    "Once you're ready, type the name of the **publisher** of the extension below to confirm the installation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1940ef3",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 4.4.1\n",
    "TYPE PUBLISHER HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e194a2c",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"21\" hidden></span>\n",
    "\n",
    "### 4.5 Writing and running Python files in VS Code\n",
    "Writing Python in VS Code works much like it does in IDLE: create a `.py` source file, save it, and ask the Python interpreter to execute it.\n",
    "\n",
    "One convenient aspect of VS Code is that it can **open an entire folder**, making it easy to work with several related files. Let's create a working folder for this course.\n",
    "\n",
    "1. Create an `Intro to Programming` folder somewhere easy to find, such as your Documents folder.\n",
    "2. Inside it, create another folder called `tutorial-1`.\n",
    "\n",
    "Then, in VS Code:\n",
    "\n",
    "3. Choose **File > Open Folder...** and open your `tutorial-1` folder.\n",
    "4. Create a new file named `thebasics.py`.\n",
    "5. Add this code:\n",
    "\n",
    "```python\n",
    "course = \"Introduction to Programming\"\n",
    "language = \"Python\"\n",
    "week = 2\n",
    "\n",
    "print(\"Course:\", course)\n",
    "print(\"Language:\", language)\n",
    "print(\"Week:\", week)\n",
    "```\n",
    "\n",
    "6. Save the file using **File > Save** or `Ctrl/Cmd+S`.\n",
    "    - If you'd like, you can also make VS Code save all your changes automatically by turning on **File > Auto Save**.\n",
    "7. Now, to run the file, press **Run > Run Without Debugging**. \n",
    "\n",
    "If it wasn't already open, VS Code will automatically reveal its integrated **terminal**. The terminal is where the Python program is run and output is displayed. You can always show or hide it using **View > Terminal** (near the bottom of the list).\n",
    "\n",
    "What does the program output? Paste the three lines below, without the command or prompt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cad9b5f2",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 4.5.1\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71a0c4e8",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"22\" hidden></span>\n",
    "\n",
    "#### Alternative ways of running Python files\n",
    "In the terminal, you have access to your operating system's **command shell**. This is a bit like the Python interactive shell, except it lets you send commands directly to your operating system, rather than to the Python interpreter. \n",
    "\n",
    "From the command shell, we can actually **start the interactive Python shell** by simply running the command `python` (Windows) or `python3` (macOS/Linux).\n",
    "\n",
    "If you're on macOS or Linux—this is exactly what you've already done when you used the Terminal app to access the Python interpreter!\n",
    "\n",
    "1. In the terminal, run the command `python` or `python3`.\n",
    "2. Try out some Python expressions in the interactive shell.\n",
    "3. When you're finished, press `Ctrl/Cmd+D` or write `exit()` and hit Enter to go back to the command shell.\n",
    "\n",
    "We can also run Python files directly from the command shell by running `python <filename>` or `python3 <filename>`.\n",
    "\n",
    "4. In the terminal, run `python thebasics.py` or `python3 thebasics.py`. \n",
    "5. Verify that your output is the same as you pasted in check 4.5.1.\n",
    "\n",
    "Finally, in the top-right of the VS Code editor window, the Python extension also adds a small triangular **Run Python File** button when you're working in Python source files.\n",
    "\n",
    "6. With `thebasics.py` open, select the ▶️ button.\n",
    "7. Once again, confirm that VS Code runs the active file in the terminal and displays the same output as above.\n",
    "\n",
    "We have now seen **four ways** of running Python in VS Code:\n",
    "- Run > Run Without Debugging\n",
    "- The integrated 'Run Python File' button\n",
    "- Running a file from the command shell using the `python <filename>` or `python3 <filename>` command\n",
    "- Opening the Python interactive shell using the `python` or `python3` command to launch a REPL\n",
    "\n",
    "Whichever way you choose to run your code is **up to you**. Which one do you think is the most convenient? And why?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0be142cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 4.5.2\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "82e5bcfe",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"23\" hidden></span>\n",
    "\n",
    "## 5 Editing efficiently\n",
    "Great—we've got the basics down. Before wrapping up, let's explore VS Code features that help us navigate and edit larger files efficiently. For this, we'll use a pre-written file.\n",
    "\n",
    "1. Download [python_version_changes.py](python_version_changes.py).\n",
    "2. Move it into your `tutorial-1` folder. That folder should now contain both `thebasics.py` and `python_version_changes.py`.\n",
    "3. Open `python_version_changes.py` in VS Code and take a look inside. What do you expect it to do?\n",
    "4. Run it several times and, when asked, give input of your choice. Were your predictions correct?\n",
    "\n",
    "What two lines are printed to the terminal when you give the program unsupported input?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65f0ab29",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 5.0.1\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ad88c37",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"24\" hidden></span>\n",
    "\n",
    "### 5.1 Searching across a folder\n",
    "When we're working with multiple files, it's easy to get lost. Thankfully, VS Code has some powerful search functionality built in.\n",
    "\n",
    "1. Open the **Search** sidebar using the magnifying-glass icon on the left side of the screen, or use `Ctrl+Shift+F` on Windows/Linux or `Cmd+Shift+F` on macOS.\n",
    "2. Search the entire `tutorial-1` folder for the word `Python`.\n",
    "\n",
    "Across the two files, how many results does VS Code find?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f381b92c",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 5.1.1\n",
    "ENTER COUNT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f26a4b1",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"25\" hidden></span>\n",
    "\n",
    "By default, searching for a string of text matches that string _anywhere_, even as part of larger words. For example, take a look at line 49 in the `python_version_changes.py` file. Here, the string `Python` is highlighted as part of the term `CPython`.\n",
    "\n",
    "What if we don't want this? The textbox where we entered our search query has several buttons that allow us to refine our search.\n",
    "\n",
    "1. In the textbox, toggle on the **Match Case** button (`Aa`).\n",
    "2. Next, also toggle on the **Match Whole Word** button (`ab`).\n",
    "\n",
    "How many results does VS Code find now?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f772c9a3",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 5.1.2\n",
    "ENTER COUNT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd42fe19",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"26\" hidden></span>\n",
    "\n",
    "### 5.2 Multi-line editing\n",
    "Each changelog contains four consecutive output lines beginning with `Change:`. That's a bit unnecessary—let's replace those four prefixes with `1.`, `2.`, `3.`, and `4.` according to each line's position.\n",
    "\n",
    "Updating every single word is going to take time, however, and we cannot simply search and replace the word \"change\" because we want to replace it with different numbers in different locations. Thankfully, VS Code allows us to **edit multiple lines at the same time**.\n",
    "\n",
    "1. Copy these four lines from here:\n",
    "\n",
    "```text\n",
    "1.\n",
    "2.\n",
    "3.\n",
    "4.\n",
    "```\n",
    "\n",
    "2. In the Python 3.8 block, select `Change:` on the first output line (line 19). \n",
    "3. While the text is selected, hold `Alt` on Windows/Linux or `Option` on macOS while selecting `Change:` on each of the next three lines.\n",
    "\n",
    "You should now have four selections with four blinking cursors after each colon, across lines 19 to 22.\n",
    "\n",
    "4. Paste, using either `Ctrl/Cmd+V` or the right-click menu.\n",
    "\n",
    "VS Code should distribute the four copied lines across the four selections. If you accidentally mis-select, for example by missing the colon or going too far ahead, you can click any selection while holding `Alt` or `Option` to remove it from the multi-select.\n",
    "\n",
    "5. Do the same for each version to get some practise in.\n",
    "6. Save and run the file, then enter `3.10`.\n",
    "\n",
    "Paste the four numbered changelog lines for Python 3.10 below to verify your work."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c916e37a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 5.2.1\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c5948e2",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"27\" hidden></span>\n",
    "\n",
    "### 5.3 Change All Occurrences and Rename Symbol\n",
    "Great, our file is looking better now. There is one final change we're going to make.\n",
    "\n",
    "When programming, it is important to **clearly name your variables**, to the point where it has become a running joke amongst programmers that _naming things_ is one of the hardest parts of the job.\n",
    "\n",
    "On line 11, we declare a variable named `version`, but this is not a particularly clear name. Is it the version of Python we're working with? The version that the user wants to receive the changelog of?\n",
    "\n",
    "_(Okay, this is a bit of a contrived example. But you get the point. Or you don't, in which case, please ask your tutor!)_\n",
    "\n",
    "Let's change it to the more descriptive `requested_version`.\n",
    "\n",
    "1. Select the `version` variable on line 11 and right-click.\n",
    "\n",
    "The VS Code right-click menu has many functions, but today we'll look at two **Change All Occurrences** and **Rename Symbol**, both in the middle of the menu.\n",
    "\n",
    "_Change All Occurrences_ sounds good. We want to change all occurrences of this variable, after all!\n",
    "\n",
    "2. Press _Change All Occurrences_, type the new name `requested_version`, and click somewhere else in the file to exit multi-cursor mode.\n",
    "\n",
    "What happens?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2b07d45",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 5.3.1\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd8a310e",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"28\" hidden></span>\n",
    "\n",
    "Whoops. Turns out, that meant change all occurrences of the _text_, not of the _variable_.\n",
    "\n",
    "1. Press `Ctrl/Cmd+Z` to undo your edit.\n",
    "\n",
    "**Change All Occurrences** works like the search sidebar, in that it selects matching text so that you can edit every selected occurrence together.\n",
    "\n",
    "However, **Rename Symbol** understands Python code and only changes references to one variable without changing the same text inside comments or strings. Let's try it out instead.\n",
    "\n",
    "2. Right-click any use of the variable `version` (it can be, but does not have to be the first one, on line 11).\n",
    "3. Choose **Rename Symbol**.\n",
    "4. Rename it to `requested_version` and press Enter.\n",
    "\n",
    "Now, every reference to that variable should change, while text such as `Python version explorer` should remain unchanged.\n",
    "\n",
    "5. Save the file and run it once to confirm it still works.\n",
    "\n",
    "What output do you get now when you ask for the changelog of version `3.14`? Paste the output from `Noteworthy changes for Python 3.14:` through `End of report` below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f9d1a76",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 5.3.2\n",
    "PASTE OUTPUT HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d36abf6",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"29\" hidden></span>\n",
    "\n",
    "## 6 Bonus Tasks\n",
    "\n",
    "Well done, that was the core part of the tutorial! At the end of this tutorial, your tutor will lead a group discussion on the challenges that you completed. If there's still a lot of time left, take a look at the bonus tasks below and choose the one you find most interesting to work on.\n",
    "\n",
    "\n",
    "### 6.1 Write a decision program\n",
    "\n",
    "Create a file named `charger_need.py`.\n",
    "\n",
    "Write a program that decides whether someone should **bring their laptop charger to the library** based on how much battery their laptop has left and how long they expect to remain in the library.\n",
    "\n",
    "You will need at least:\n",
    "\n",
    "- two variables that take user input;\n",
    "- one boolean expression;\n",
    "- one `if` / `else` statement.\n",
    "\n",
    "Test your code thoroughly. Can you account for different types of user input? Refer to `python_version_changes.py` as well as the lecture material if you need help. Use the space below to write any notes for the group discussion at the end of the session."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6279d4a0",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 6.1.1\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7ccb789",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"29\" hidden></span>\n",
    "\n",
    "### 6.2 Customise VS Code\n",
    "\n",
    "VS Code extensions don't just add new functionality—they can also change the **appearance** of the editor itself! Find and install a theme of your liking.\n",
    "\n",
    "Some useful websites:\n",
    "- [VS Code Theme Documentation](https://code.visualstudio.com/docs/configure/themes)\n",
    "- [A visual overview of popular VS Code themes](https://vscodethemes.com/)\n",
    "\n",
    "Use the note pad to record the name of the theme you installed, why you chose it, and whether it made code easier or harder to read."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d425bf8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 6.2.1\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df88462e",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"29\" hidden></span>\n",
    "\n",
    "### 6.3 Compare code editors\n",
    "\n",
    "While we are using VS Code in this tutorial, there are several other options available, from simple text editors to fully-fledged **IDEs**, or _Integrated Development Environments_. For example:\n",
    "\n",
    "- PyCharm\n",
    "- Sublime Text\n",
    "- VSCodium\n",
    "- Notepad++\n",
    "- Vim\n",
    "\n",
    "Have you worked with any of these before? If so, how did they compare to VS Code? Which is your favourite?\n",
    "\n",
    "If not, pick one to research. Find out:\n",
    "\n",
    "- which organisation or community maintains it;\n",
    "- whether it is free, open source, commercial, or a mixture;\n",
    "- what kind of programmer it seems aimed at;\n",
    "- how its functionality differs from VS Code.\n",
    "\n",
    "Add your notes below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8926cb2c",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%check 6.3.1\n",
    "WRITE NOTES HERE"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50f548e0",
   "metadata": {},
   "source": [
    "<span class=\"tutorial-section-marker\" data-tutorial-section=\"29\" hidden></span>\n",
    "\n",
    "## 7 Summary\n",
    "\n",
    "Well done, you. You've installed the tools we will use in these tutorials, ran Python programs in IDLE and VS Code, and became familiar with the features of both tools.\n",
    "\n",
    "Don't feel overwhelmed by the massive number of features in VS Code—I certainly don't know all of them, nor does anyone have to. First and foremost, you need to know how to edit and run files, which you do now. We've also looked at some useful features to allow you to do so _efficiently_. Over time, as you become more familiar with the editor, you will find out more. In particular, in CriSP, you will learn how to set up version control tools later this semester, which we'll use in later tutorials in this course as well.\n",
    "\n",
    "For now, let's recap some of the **key terms** we've seen:\n",
    "\n",
    "<dl>\n",
    "\t<dt><b>Python interpreter</b></dt>\n",
    "\t<dd>The program that reads and executes Python code.</dd>\n",
    "\t<dt><b>Python source file</b></dt>\n",
    "\t<dd>A text file containing Python code, normally with a <code>.py</code> filename extension.</dd>\n",
    "\t<dt><b>Code editor</b></dt>\n",
    "\t<dd>A program for creating and editing source files, such as IDLE or VS Code.</dd>\n",
    "\t<dt><b>Extension</b></dt>\n",
    "\t<dd>An add-on that gives an editor extra features, such as Python support in VS Code.</dd>\n",
    "    <dt><b>Terminal</b></dt>\n",
    "\t<dd>A window or panel for text input and output; it commonly hosts a command shell, and can be both its own app or a part of another app (such as VS Code).</dd>\n",
    "\t<dt><b>Command shell</b></dt>\n",
    "\t<dd>A program that interprets commands to the operating system, such as starting other programs. Examples include PowerShell (on Windows), zsh (on macOS), or bash (on Linux).</dd>\n",
    "\t<dt><b>Python interactive shell</b></dt>\n",
    "\t<dd>An interface, recognised by the <code>&gt;&gt;&gt;</code> prompt, for sending commands directly to the Python interpreter. Opened by running <code>python</code> (on Windows) or <code>python3</code> in a command shell, or directly by opening the Python interpreter program or the IDLE Shell.</dd>\n",
    "\t<dt><b>REPL</b></dt>\n",
    "\t<dd>The Read–Evaluate–Print Loop followed by an interactive shell.</dd>\n",
    "</dl>\n",
    "\n",
    "Don't worry about learning all these by heart—they will not be examined in this course. The language will start to come to you naturally as you advance :)\n",
    "\n",
    "---\n",
    "\n",
    "### Start over\n",
    "\n",
    "Use this button to erase every answer and begin the tutorial again.\n",
    "\n",
    "<button type=\"button\" data-tutorial-reset style=\"padding:8px 14px;border:1px solid #b91c1c;border-radius:6px;background:#dc2626;color:white;font-weight:600;cursor:pointer\">Reset all tutorial progress</button>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
