{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "l9-00",
   "metadata": {},
   "source": [
    "# L9 In-Class Activity: Take Apart Two Apps from the Command Line\n",
    "\n",
    "### E190BO — Fall 2026\n",
    "\n",
    "In the video, you watched Hyperschedule get taken apart one layer at a time. Today you will do it yourself using this notebook.\n",
    "\n",
    "- **Toolbox (about 5 min).** Short demos of every tool you'll need: `curl`, pipes, headers, status codes, and `jq`. Run them and read what they print.\n",
    "- **Part 1 — Hyperschedule (about 22 min).** The same API from the video. **You write every command**: each question's code cell starts empty. Check your answers against the **checkpoint key**.\n",
    "- **Part 2 — Wordle (about 25 min).** A new app, and this time no one is giving you the URLs. Find them with your browser's devtools, then take the app apart with the same tools. It ends with the same diagram as the video, filled in for Wordle.\n",
    "\n",
    "**Work in teams of 2–3.** Everyone runs this notebook in their own codespace and types every command. Don't move on until everyone on your team has the output. Your team shares one paper worksheet.\n",
    "\n",
    "Aim to finish Part 1 by **10:05**. If you're not done by then, move on to Part 2 anyway; that's where the sleuthing is."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-01",
   "metadata": {},
   "source": [
    "## How this notebook runs shell commands\n",
    "\n",
    "Every code cell here starts with **`%%bash`**. That first line tells Jupyter to run the rest of the cell in **bash**, the same shell as your Codespace terminal. Anything that works in these cells works in the terminal too (**Terminal → New Terminal**, then paste everything except the `%%bash` line).\n",
    "\n",
    "The Toolbox cells below are filled in. After that, each code cell holds only `%%bash` and a comment: replace the comment with your command. (Lines starting with `#` are comments; bash ignores them.) **Keep the `%%bash` line.** Without it, Jupyter reads your command as Python and reports a `SyntaxError`.\n",
    "\n",
    "Two differences from a terminal:\n",
    "\n",
    "- **Each cell starts a fresh shell.** A variable you set in one cell (`X=5`) is gone by the next one. The exception is `%env`, which sets a variable for every cell. We use it once, just below.\n",
    "- You may see `!curl …` in other notebooks. **Don't use it here.** Jupyter rewrites `{…}` and `$name` in `!` lines before bash ever sees them, and that breaks most `jq` commands."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-02",
   "metadata": {},
   "source": [
    "## Setup — run this once\n",
    "\n",
    "`$B` is shorthand for Hyperschedule's API, just like in the video. `%env` makes it available in every cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-03",
   "metadata": {},
   "outputs": [],
   "source": [
    "%env B=https://banana.hyperschedule.io"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t00",
   "metadata": {},
   "source": [
    "---\n",
    "# Toolbox\n",
    "\n",
    "Run each demo and read what it prints. The demos use the **course website** and a small **made-up file**, so none of them answers a question in Part 1 or Part 2.\n",
    "\n",
    "Use this section as a reference whenever you need a pattern."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t01",
   "metadata": {},
   "source": [
    "### `curl` fetches a URL\n",
    "\n",
    "`curl` prints whatever the server sends back: here, the course home page, which is HTML. `-s` (silent) hides the progress meter.\n",
    "\n",
    "The `|` (a **pipe**) sends one command's output into the next command instead of to the screen. `head -n 5` keeps only the first five lines."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t02",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "curl -s https://course.aiprototypes.org/ | head -n 5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t03",
   "metadata": {},
   "source": [
    "### Save it and measure it\n",
    "\n",
    "`>` saves the output to a file instead of printing it, and `wc -c` counts the file's bytes.\n",
    "\n",
    "The last line gets the same number straight from `curl`: `-o /dev/null` throws the body away, and `-w` writes out a fact about the transfer, here its size."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t04",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "curl -s https://course.aiprototypes.org/ > home.html\n",
    "wc -c home.html\n",
    "curl -s -o /dev/null -w '%{size_download} bytes\\n' https://course.aiprototypes.org/"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t05",
   "metadata": {},
   "source": [
    "### Headers\n",
    "\n",
    "Before the body, a server sends **headers**: a status line (`HTTP/2 200`), then `name: value` lines about the response. `-D -` prints the headers, and `-o /dev/null` throws the body away.\n",
    "\n",
    "These are the headers for the notebook you downloaded at the start of class. Find its type (`content-type`), its size in bytes (`content-length`), how long it may be cached (`cache-control`), and who served it (`server`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t06",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "curl -sS -D - -o /dev/null https://course.aiprototypes.org/resources/files/eng190bo-fa26-lecture-9-activity-skeleton.ipynb"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t07",
   "metadata": {},
   "source": [
    "`grep` keeps only the lines that match. `-i` ignores upper and lower case, and `^` means \"at the start of a line,\" so `'^server'` finds the `server:` header and nothing else."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t08",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "curl -sS -D - -o /dev/null https://course.aiprototypes.org/ | grep -i '^server'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t09",
   "metadata": {},
   "source": [
    "### Status codes\n",
    "\n",
    "`-w '%{http_code}'` prints just the status code, as in the first line.\n",
    "\n",
    "To see the body **and** the code, leave out `-o /dev/null` and use `-w '\\n[%{http_code}]\\n'`, which puts the code on its own line after the body. The home page is long, so the second line keeps only its last two lines: the end of the HTML, then the code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t10",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "curl -s -o /dev/null -w '%{http_code}\\n' https://course.aiprototypes.org/\n",
    "curl -s -w '\\n[%{http_code}]\\n' https://course.aiprototypes.org/ | tail -n 2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t11",
   "metadata": {},
   "source": [
    "### `jq` reads JSON\n",
    "\n",
    "Most APIs answer in **JSON**, and `jq` is a small language for pulling pieces out of it. To practice, this cell writes a made-up library catalog to `books.json` (everything between `<<'EOF'` and `EOF` goes into the file). Then `jq .` pretty-prints it; `.` means \"the whole thing.\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t12",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "cat > books.json <<'EOF'\n",
    "[\n",
    "  {\"title\": \"A Wizard of Earthsea\", \"author\": {\"first\": \"Ursula\", \"last\": \"Le Guin\"}, \"pages\": 183, \"copies\": 3, \"checkedOut\": 3},\n",
    "  {\"title\": \"The Dispossessed\", \"author\": {\"first\": \"Ursula\", \"last\": \"Le Guin\"}, \"pages\": 387, \"copies\": 2, \"checkedOut\": 1},\n",
    "  {\"title\": \"Kindred\", \"author\": {\"first\": \"Octavia\", \"last\": \"Butler\"}, \"pages\": 264, \"copies\": 4, \"checkedOut\": 4},\n",
    "  {\"title\": \"Exhalation\", \"author\": {\"first\": \"Ted\", \"last\": \"Chiang\"}, \"pages\": 350, \"copies\": 2, \"checkedOut\": 0}\n",
    "]\n",
    "EOF\n",
    "jq . books.json"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t13",
   "metadata": {},
   "source": [
    "`length` counts the items in a list. `.[0]` is the first item (counting starts at 0). A dot path walks into it: `.[0].author.last` is the first book's author's last name. Separate paths with commas to print several at once."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-t14",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "jq length books.json\n",
    "jq '.[0]' books.json\n",
    "jq '.[0].title, .[0].author.last' books.json"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-t23",
   "metadata": {},
   "source": [
    "### Cheat sheet\n",
    "\n",
    "| Command | Does |\n",
    "|---|---|\n",
    "| `curl -s URL` | print the response body |\n",
    "| `curl -s URL \\| jq .` | …as pretty-printed JSON |\n",
    "| `curl -s URL > file.json` | save the body to a file instead of printing it |\n",
    "| `jq length file.json` | how many items are in the list? |\n",
    "| `jq '.[0].title' file.json` | one field of the first item |\n",
    "| `jq '.[] \\| select(.a == \"x\") \\| .title' file.json` | a field of every item that passes a test |\n",
    "| `jq '[.[] \\| select(TEST)] \\| length' file.json` | how many items pass a test |\n",
    "| `jq -c '.[] \\| {title, half: (.pages / 2)}' file.json` | pick and compute fields, one line per item |\n",
    "| `curl -sS -D - -o /dev/null URL` | headers only (the status is on the first line) |\n",
    "| `curl -s -o /dev/null -w '%{http_code}\\n' URL` | just the status code |\n",
    "| `curl -s -w '\\n[%{http_code}]\\n' URL` | the body, then the status code |\n",
    "| `curl -s -o /dev/null -w '%{size_download}\\n' URL` | how many bytes came back |\n",
    "| `… \\| grep -i '^word'` | keep only the lines that start with *word* |\n",
    "| `… \\| head -n 5` | keep only the first five lines |\n",
    "| `date -d '2026-09-30 - 7 days' +%F` | date arithmetic |\n",
    "| `for x in A B C; do …; done` | run a command once for each value |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-04",
   "metadata": {},
   "source": [
    "---\n",
    "# Part 1 — Hyperschedule\n",
    "\n",
    "Same API, same diagram as the video. Every question matches a layer you saw."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-05",
   "metadata": {},
   "source": [
    "## The API server: talk to it\n",
    "\n",
    "### 1.1 What term is it?\n",
    "\n",
    "Ask the API for the current term. The route is `/v4/term/current`, so the URL is `$B/v4/term/current`. This is the first request from the video."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-06",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-07",
   "metadata": {},
   "source": [
    "Which term and year does Hyperschedule think it is? What format is the response in?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-08",
   "metadata": {},
   "source": [
    "### 1.2 How many sections?\n",
    "\n",
    "`$B/v4/sections` returns every section this term, as one list. Count them.\n",
    "\n",
    "Then **save** the whole list to a file named `sections.json`. It's about 2.5 MB, so from here on read the file with `jq` rather than downloading it over and over. That's faster for you and politer to the server."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-09",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-10",
   "metadata": {},
   "source": [
    "How many sections are offered this term?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-11",
   "metadata": {},
   "source": [
    "### 1.3 One section up close\n",
    "\n",
    "Print the **first** section in `sections.json`, so you can see every field."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-12",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-13",
   "metadata": {},
   "source": [
    "Now print **only** three things about that section: its course title, how many seats are filled, and how many there are in total. Find the field names in the output above. The title is inside `course`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-14",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-15",
   "metadata": {},
   "source": [
    "Title, seats filled, seats total:\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-16",
   "metadata": {},
   "source": [
    "### 1.4 Find this class\n",
    "\n",
    "How many sections are in the **ENGR** department? The department is at `.course.code.department`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-17",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-18",
   "metadata": {},
   "source": [
    "Now find **ENGR 190BO**, this class, and print its title and seat counts.\n",
    "\n",
    "Hints: combine tests with `and`. The course number is `.course.code.courseNumber`, and it's stored as a number (`190`, not `\"190\"`). The `BO` is stored separately, in `.course.code.suffix`. Build a small object to print, as in the cheat sheet."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-19",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-20",
   "metadata": {},
   "source": [
    "How many ENGR sections are there? Is there still room in ENGR 190BO?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-27",
   "metadata": {},
   "source": [
    "## The network\n",
    "\n",
    "### 1.5 How much did the browser download?\n",
    "\n",
    "How many bytes does `$B/v4/sections` send back? The Toolbox shows two ways: `curl`'s `-w '%{size_download}'`, or `wc -c` on the file you saved."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-28",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-29",
   "metadata": {},
   "source": [
    "How big is it? Hyperschedule's page downloads this whole list **once** when it opens. So when you type in the search box, which machine does the searching? When would this design be a bad idea?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-30",
   "metadata": {},
   "source": [
    "### 1.6 Two hostnames, two companies\n",
    "\n",
    "Ask who serves `https://hyperschedule.io` (its `server:` header). Then ask the same about the API, `$B/v4/term/current`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-31",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-32",
   "metadata": {},
   "source": [
    "Who serves each one? Which hostname delivers the app's *files* and which delivers its *data*?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-36",
   "metadata": {},
   "source": [
    "## Make it fail: four status codes\n",
    "\n",
    "Get Hyperschedule's API to return each of **200, 404, 401, and 400**. Here are its routes, from [the source](https://github.com/hyperschedule/hyperschedule/tree/d41a5e52e72398ba504ceddb5d179a9ff85fe601/backend/src/routes/v4):\n",
    "\n",
    "| Route | What it's for |\n",
    "|---|---|\n",
    "| `GET /v4/term/current` | the current term |\n",
    "| `GET /v4/sections/{term}` | every section in one term, e.g. `FA2026` |\n",
    "| `GET /v4/user/` | *your* account and saved schedules |\n",
    "| `GET /v4/calendar/{userId}/{scheduleId}` | a calendar feed for one saved schedule |\n",
    "\n",
    "### 1.7 Four codes\n",
    "\n",
    "Write one `curl` line per code. Use `-w '\\n[%{http_code}]\\n'` so you see the body **and** the code. The 200 is the easy one: it's your request from 1.1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-37",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-38",
   "metadata": {},
   "source": [
    "Which URL gave each code? Read the **400** body: what is it complaining about? Find the line that sent it in [`calendar.ts`](https://github.com/hyperschedule/hyperschedule/blob/d41a5e52e72398ba504ceddb5d179a9ff85fe601/backend/src/routes/v4/calendar.ts#L36). For the 401: what would your browser have sent that `curl` didn't?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-39",
   "metadata": {},
   "source": [
    "**✅ Checkpoint.** Compare your Part 1 answers with the key on the board. Then go on to Part 2."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-40",
   "metadata": {},
   "source": [
    "---\n",
    "# Part 2 — Wordle\n",
    "\n",
    "**Your target:** <https://www.nytimes.com/games/wordle/index.html>\n",
    "\n",
    "This time, nobody gives you the URLs. You have the same tools as in Part 1, plus your browser's devtools. The questions tell you *what* to find, not *how*. Hints are folded up under each question; try without them first.\n",
    "\n",
    "Do **2.1–2.5**. If you finish early, there's more at the end.\n",
    "\n",
    "> **Spoiler warning.** Wordle's page asks for today's puzzle. In the Network tab, **don't click on today's puzzle request** unless you've already played. In this notebook, use **past dates only**."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-41",
   "metadata": {},
   "source": [
    "### 2.1 Find the puzzle\n",
    "\n",
    "Open Wordle with devtools → **Network** open, then press **Play**. The page makes a lot of requests, and most of them are ads and analytics. How many requests did the page make in total? (The count is in the Network tab's bottom bar.) Find the **one** that delivers the puzzle.\n",
    "\n",
    "Then fetch a **past** day's puzzle from this notebook and pretty-print it.\n",
    "\n",
    "<details><summary>Hint 1</summary>\n",
    "\n",
    "Set the Network filter to **Fetch/XHR**, which hides images, scripts, and styles. Then type <code>wordle</code> in the filter box.\n",
    "</details>\n",
    "\n",
    "<details><summary>Hint 2</summary>\n",
    "\n",
    "Look for a <code>.json</code> URL with today's date in it. Keep everything up to the date, and swap the date for an old one, like <code>2026-09-20.json</code>.\n",
    "</details>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-42",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-43",
   "metadata": {},
   "source": [
    "What's the URL pattern? What fields does a puzzle have?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-44",
   "metadata": {},
   "source": [
    "### 2.2 Who grades your guess?\n",
    "\n",
    "Clear the Network tab (🚫). Type a guess and press **Enter**. Watch the Network tab.\n",
    "\n",
    "How many requests did your guess cause? The tiles changed color anyway. So **which machine** decided they were green or yellow, and what did that machine need to know? Point to the evidence in your output from 2.1.\n",
    "\n",
    "This is the video's question: *which machine runs this code?*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-45",
   "metadata": {},
   "source": [
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-46",
   "metadata": {},
   "source": [
    "### 2.3 Where's your game?\n",
    "\n",
    "Open devtools → **Application** → **Local Storage** → `https://www.nytimes.com`. Find the entry that holds your board. *(If you've played today, don't show your screen around.)*\n",
    "\n",
    "The page **also** asked the NYT's server for your game state. Find that request in the Network tab (filter for `state`), copy its URL, and `curl` it here with the status code.\n",
    "\n",
    "<details><summary>Hint</summary>\n",
    "\n",
    "The URL contains <code>svc/games/state</code>. Use <code>curl -s -w '\\n[%{http_code}]\\n' \"URL\"</code>, and keep the double quotes, because the URL has a <code>?</code> in it.\n",
    "</details>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-47",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-48",
   "metadata": {},
   "source": [
    "What's in Local Storage? What did the state request return, and why? Which one survives switching laptops? Which part of Hyperschedule does this remind you of?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-49",
   "metadata": {},
   "source": [
    "### 2.4 Make it fail — twice, differently\n",
    "\n",
    "Get **two 404s** from the puzzle URL whose **bodies look completely different**. What does the difference tell you about how many programs sit between you and the puzzle?\n",
    "\n",
    "<details><summary>Hint</summary>\n",
    "\n",
    "Try a \"date\" that isn't a date at all. Then try a real date far in the future.\n",
    "</details>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-50",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-51",
   "metadata": {},
   "source": [
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-58",
   "metadata": {},
   "source": [
    "### 2.5 Fill in the diagram\n",
    "\n",
    "Same boxes as the video, two apps. The Hyperschedule column is filled in from the video. Fill in Wordle's from what **you** found, and mark each box **[O]** observed (a command or devtools showed it) or **[G]** guessed (inferred)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-59",
   "metadata": {},
   "source": [
    "| Layer | Hyperschedule (from the video) | Wordle (you) | [O] / [G] |\n",
    "|---|---|---|---|\n",
    "| The pixels | React components + CSS | | |\n",
    "| Logic in the browser | search; guest schedule in Local Storage | | |\n",
    "| The network | `hyperschedule.io` → GitHub Pages; `banana.hyperschedule.io` → Cloudflare | | |\n",
    "| The API server | tinyhttp: `/v4/sections`, `/v4/user/` | | |\n",
    "| The database | MongoDB (we read the source) | | |\n",
    "| Below the bottom | the colleges' registrar, polled every 60 s | | |\n",
    "\n",
    "**Last question:** What would it take to make cheating on Wordle impossible? Which boxes would have to change? Why do you think the NYT hasn't bothered?\n",
    "\n",
    "*Your answer:*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-x0",
   "metadata": {},
   "source": [
    "---\n",
    "## If you finish early\n",
    "\n",
    "Four more, in any order. **A** and **B** go deeper into Wordle's data; **C** and **D** practice headers and loops."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-52",
   "metadata": {},
   "source": [
    "### A. Is `id` the puzzle number?\n",
    "\n",
    "Fetch a few **consecutive** past days and print `print_date`, `id`, and `days_since_launch` for each one.\n",
    "\n",
    "<details><summary>Hint</summary>\n",
    "\n",
    "<code>jq -c '{print_date, id, days_since_launch}'</code> prints one compact line per puzzle. Put three <code>curl</code> lines in the cell, or write a <code>for</code> loop.\n",
    "</details>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-53",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-54",
   "metadata": {},
   "source": [
    "Which field counts puzzles? What do you think `id` is? Is that **observed** or **guessed**?\n",
    "\n",
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-55",
   "metadata": {},
   "source": [
    "### B. Wordle #1\n",
    "\n",
    "Use `days_since_launch` to work out the date of the **first** Wordle, then fetch it. `date` can do date arithmetic: `date -d '2026-09-20 - 10 days' +%F`.\n",
    "\n",
    "Compare its fields with a recent puzzle's. What's missing, and what do you think happened?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-56",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-57",
   "metadata": {},
   "source": [
    "**Your answer:**\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-60",
   "metadata": {},
   "source": [
    "### C. Who answers?\n",
    "\n",
    "Compare the headers of the puzzle JSON and the game page (`server`, `cache-control`, and anything that starts with `x-`). Is the page cached? Is the puzzle? Hyperschedule used two hostnames for files and data. Does Wordle?\n",
    "\n",
    "### D. A week in one command\n",
    "\n",
    "Write a `for` loop that prints the puzzle number and editor for each of the last seven days, **not including today**. `date -d \"-3 days\" +%F` gives the date three days ago."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "l9-61",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "# write your command here\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "l9-62",
   "metadata": {},
   "source": [
    "**Your answer:**\n",
    "\n"
   ]
  }
 ],
 "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.9.25"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
