diff --git a/2022/README.md b/2022/README.md
index 03da0a26a558d22e4987287f37fa218e12473c01..5f1626bed0e8ec981748bf12642fcc7a075770e1 100644
--- a/2022/README.md
+++ b/2022/README.md
@@ -2,3 +2,34 @@
 
 ## Day 1
 
+- [The problem](https://adventofcode.com/2022/day/1)
+- [The solution](src/main/java/edu/unl/cse/bohn/year2022/Day1.java)
+
+I like the first few days' problems -- they're simple enough that they make great computational thinking examples for my 100-level students.
+Breaking the problem down into subproblems:
+- Keep track of how many calories an elf is carrying
+- Detect when we've reach the end of the list of items that elf is carrying
+- Convert strings to integers
+- Of the elves considered so far, keep track of the number of calories being carried by the elf who is carrying the most calories (or the three elves who are carrying the most calories)
+- Update that count when we've finished with an elf
+  - For part 1, we must determine whether the most-recent elf is carrying more calories than the maximum among the previous elves
+  - For part 2, we must determine whether the most-recent elf is carrying more calories than any of the previous top-three
+- Produce the result
+  - For part 1, the result is the maximum number of calories being carried by any one elf
+  - For part 2, the result is the sum of the number of calories being carried by the top three
+
+While I wouldn't expect my students to be able to provide solutions in quite so few lines as I did -- we don't teach the Java streams API in CS1 -- they could definitely do this problem.
+The only wrinkle is that a blank line isn't the *only* way to reach the end of an elf's list.
+
+### Refactoring opportunity
+
+Parts 1 & 2 differ only in how many "maximum" elves we're tracking and, consequently, how we perform our update.
+My part 2 solution used a set that can never grow to more than 3 items because we're tracking the top three elves.
+Part 1 can be thought of as a degenerate case of tracking the top "one" elf;
+this suggests that it can be solved with a set that can never grow to more than 1 item.
+Which means we can use the same solution for both parts, parameterized by the top "number" of elves, which becomes the upper limit of the size of the set.
+
+## Day 2
+
+(coming soon)
+
diff --git a/2022/src/main/java/edu/unl/cse/bohn/ImportData.java b/2022/src/main/java/edu/unl/cse/bohn/ImportData.java
deleted file mode 100644
index e472acd7745eaa72bdead83c1254703abbf21534..0000000000000000000000000000000000000000
--- a/2022/src/main/java/edu/unl/cse/bohn/ImportData.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package edu.unl.cse.bohn;
-
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
-
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URLConnection;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Objects;
-
-public class ImportData {
-
-    public static final String FILENAME = "apikeys.json";
-
-    protected final String protocol;
-    protected final String host;
-    protected final String path;
-    protected final String apiKey;
-
-    @SuppressWarnings("unused")
-    public static List<String> readFile(String filename) throws IOException {
-        List<String> data = new LinkedList<>();
-        BufferedReader bufferedReader;
-        bufferedReader = new BufferedReader(new FileReader(filename));
-        while (bufferedReader.ready()) {
-            data.add(bufferedReader.readLine());
-        }
-        return data;
-    }
-
-    public ImportData(String apiKeyName, int year, int day) {
-        String apiKey;
-        protocol = "https";
-        host = "adventofcode.com";
-        path = "/" + year + "/day/" + day + "/input";
-        try {
-            apiKey = getApiKey(apiKeyName);
-        } catch (IOException ioException) {
-            System.err.println("Could not retrieve API key: " + ioException.getMessage());
-            apiKey = null;
-        }
-        this.apiKey = apiKey;
-    }
-
-    protected String getApiKey(String apiKeyName) throws IOException {
-        JSONObject apiKeyJson;
-        try (InputStreamReader inputStreamReader = new InputStreamReader(
-                Objects.requireNonNull(ImportData.class.getClassLoader().getResourceAsStream(FILENAME)))) {
-            apiKeyJson = (JSONObject)new JSONParser().parse(inputStreamReader);
-        } catch (NullPointerException nullPointerException) {
-            FileNotFoundException newException = new FileNotFoundException("File " + FILENAME + " not found.");
-            newException.initCause(nullPointerException);
-            throw newException;
-        } catch (ParseException parseException) {
-            throw new IOException("Error while parsing file " + FILENAME + ".", parseException);
-        }
-        if (!apiKeyJson.containsKey(apiKeyName)) {
-            System.err.println("WARNING! Could not locate API key named " + apiKeyName + " in file " + FILENAME + ".");
-        }
-        String apiKey = apiKeyJson.get(apiKeyName).toString();
-        if (apiKey.equals("")) {
-            System.err.println("WARNING! API key named " + apiKeyName + " in file " + FILENAME + " is blank.");
-        }
-        return apiKey;
-    }
-
-    public List<String> importData() throws IOException {
-        List<String> data = new LinkedList<>();
-        BufferedReader bufferedReader;
-        try {
-            URLConnection connection = new URI(protocol, host, path, null).toURL().openConnection();
-            connection.setRequestProperty("Cookie", apiKey);
-            bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
-        } catch (URISyntaxException | MalformedURLException originalException) {
-            throw new IOException("Could not retrieve usable data from " + host + ".", originalException);
-        }
-        while (bufferedReader.ready()) {
-            data.add(bufferedReader.readLine());
-        }
-        return data;
-    }
-}
diff --git a/2022/src/main/java/edu/unl/cse/bohn/ImportData.java b/2022/src/main/java/edu/unl/cse/bohn/ImportData.java
new file mode 120000
index 0000000000000000000000000000000000000000..c9636cffbf9bae36012fb95ddb8f410ee62e91b2
--- /dev/null
+++ b/2022/src/main/java/edu/unl/cse/bohn/ImportData.java
@@ -0,0 +1 @@
+../../../../../../../../scaffolding/ImportData.java
\ No newline at end of file
diff --git a/2022/src/main/java/edu/unl/cse/bohn/Main.java b/2022/src/main/java/edu/unl/cse/bohn/Main.java
deleted file mode 100644
index 875e4b596eeab33d66f361eb9a25d3ac23ef04c5..0000000000000000000000000000000000000000
--- a/2022/src/main/java/edu/unl/cse/bohn/Main.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package edu.unl.cse.bohn;
-
-import java.lang.reflect.InvocationTargetException;
-import java.util.Calendar;
-import java.util.Scanner;
-
-public class Main {
-    public static final String defaultApiKey = "aoc";
-
-    private static String getUserInput(String prompt, String defaultValue, Scanner scanner) {
-        System.out.print(prompt + " [" + defaultValue + "]: ");
-        String userInput = scanner.nextLine();
-        return userInput.equals("") ? defaultValue : userInput;
-    }
-
-    public static void main(String... arguments) {
-        Scanner scanner = new Scanner(System.in);
-        String apiKey = getUserInput("Enter API key", defaultApiKey, scanner);
-        Calendar calendar = Calendar.getInstance();
-        int year = Integer.parseInt(getUserInput("Enter puzzle year",
-                Integer.toString(calendar.get(Calendar.YEAR)), scanner));
-        int day = Integer.parseInt(getUserInput("Enter puzzle day",
-                Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), scanner));
-        boolean useProductionData = getUserInput("Use sample data (Y/N)?", "Y", scanner).toUpperCase().charAt(0) != 'Y';
-        scanner.close();
-        ImportData dataSource = new ImportData(apiKey, year, day);
-        String className = Main.class.getPackageName() + ".year" + year + ".Day" + day;
-        Puzzle puzzle = null;
-        try {
-            puzzle = (Puzzle)Class.forName(className).getConstructors()[0].newInstance(useProductionData);
-        } catch (ClassNotFoundException classNotFoundException) {
-            System.err.println("Could not find class " + className);
-            System.exit(1);
-        } catch (InstantiationException ignored) {
-            System.err.println(className + " is an abstract class.");
-            System.exit(1);
-        } catch (IllegalAccessException ignored) {
-            System.err.println("The requested constructor for " + className + " is inaccessible.");
-            System.exit(1);
-        } catch (InvocationTargetException invocationTargetException) {
-            System.err.println("The constructor for " + className + " threw an exception.");
-            System.err.println(invocationTargetException.getMessage());
-            Throwable originalException = invocationTargetException.getCause();
-            System.err.println("Caused by: " + originalException);
-            System.exit(1);
-        }
-        puzzle.solvePuzzle(dataSource);
-    }
-}
diff --git a/2022/src/main/java/edu/unl/cse/bohn/Main.java b/2022/src/main/java/edu/unl/cse/bohn/Main.java
new file mode 120000
index 0000000000000000000000000000000000000000..5982251034ccb829a5e08ea5ac2facc966d2b734
--- /dev/null
+++ b/2022/src/main/java/edu/unl/cse/bohn/Main.java
@@ -0,0 +1 @@
+../../../../../../../../scaffolding/Main.java
\ No newline at end of file
diff --git a/2022/src/main/java/edu/unl/cse/bohn/Puzzle.java b/2022/src/main/java/edu/unl/cse/bohn/Puzzle.java
deleted file mode 100644
index 100704cec7d51d3b557a350d2d62254e850e14e4..0000000000000000000000000000000000000000
--- a/2022/src/main/java/edu/unl/cse/bohn/Puzzle.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package edu.unl.cse.bohn;
-
-import java.io.IOException;
-import java.util.List;
-
-public abstract class Puzzle {
-    protected String sampleData = "";
-    protected boolean isProductionReady;
-
-    public Puzzle(boolean isProductionReady) {
-        this.isProductionReady = isProductionReady;
-    }
-
-    public abstract long computePart1(List<String> data);
-    public abstract long computePart2(List<String> data);
-
-    public void solvePuzzle(ImportData dataSource) {
-        List<String> data = null;
-        try {
-            data = isProductionReady ? dataSource.importData() : List.of(sampleData.split(System.lineSeparator()));
-        } catch (IOException ioException) {
-            System.err.println("Could not retrieve data: " + ioException);
-            System.exit(1);
-        }
-        System.out.println("Part 1: " + computePart1(data));
-        System.out.println("Part 2: " + computePart2(data));
-    }
-}
diff --git a/2022/src/main/java/edu/unl/cse/bohn/Puzzle.java b/2022/src/main/java/edu/unl/cse/bohn/Puzzle.java
new file mode 120000
index 0000000000000000000000000000000000000000..1350b61668e54fc9382922c01a572f7f57a7900b
--- /dev/null
+++ b/2022/src/main/java/edu/unl/cse/bohn/Puzzle.java
@@ -0,0 +1 @@
+../../../../../../../../scaffolding/Puzzle.java
\ No newline at end of file
diff --git a/2022/src/main/java/edu/unl/cse/bohn/year2022/Day1.java b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day1.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab8431d44c4c49ac47fde7860fa45000116ef17f
--- /dev/null
+++ b/2022/src/main/java/edu/unl/cse/bohn/year2022/Day1.java
@@ -0,0 +1,87 @@
+package edu.unl.cse.bohn.year2022;
+
+import edu.unl.cse.bohn.Puzzle;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SuppressWarnings({"unused", "CommentedOutCode"})
+public class Day1 extends Puzzle {
+    public Day1(boolean isProductionReady) {
+        super(isProductionReady);
+        sampleData = """                
+                1000
+                2000
+                3000
+                                
+                4000
+                                
+                5000
+                6000
+                                
+                7000
+                8000
+                9000
+                                
+                10000""";
+    }
+
+/*
+    @Override
+    public long computePart1(List<String> data) {
+        long maximumCalorieCount = Long.MIN_VALUE;
+        long currentCalorieCount = 0;
+        for (String datum: data) {
+            Long calories = datum.equals("") ? null : Long.valueOf(datum);
+            if (calories == null) {
+                maximumCalorieCount = Long.max(maximumCalorieCount, currentCalorieCount);
+                currentCalorieCount = 0;    // make it ready for the next elf
+            } else {
+                currentCalorieCount += calories;
+            }
+        }
+        // we still need to compare the last elf's calorie count, because they didn't have a blank line following their last food item
+        maximumCalorieCount = Long.max(maximumCalorieCount, currentCalorieCount);
+        return maximumCalorieCount;
+    }
+*/
+
+    @Override
+    public long computePart1(List<String> data) {
+        return getSumOfMaximumCalorieCounts(data, 1);
+    }
+
+    @Override
+    public long computePart2(List<String> data) {
+        return getSumOfMaximumCalorieCounts(data, 3);
+    }
+
+    private static Long getSumOfMaximumCalorieCounts(List<String> data, int numberOfMaximumCalorieCounts) {
+        Set<Long> maximumCalorieCounts = new HashSet<>();
+        long currentCalorieCount = 0;
+        for (String datum: data) {
+            Long calories = datum.equals("") ? null : Long.valueOf(datum);
+            if (calories == null) {
+                updateMaximumCounts(maximumCalorieCounts, currentCalorieCount, numberOfMaximumCalorieCounts);
+                currentCalorieCount = 0;
+            } else {
+                currentCalorieCount += calories;
+            }
+        }
+        updateMaximumCounts(maximumCalorieCounts, currentCalorieCount, numberOfMaximumCalorieCounts);
+        return maximumCalorieCounts.stream().reduce(0L, Long::sum);
+    }
+
+    private static void updateMaximumCounts(Set<Long> maximumCalorieCounts,
+                                            long currentCalorieCount,
+                                            int numberOfMaximumCalorieCounts) {
+        long calorieCountToAdd = currentCalorieCount;
+        if (maximumCalorieCounts.size() > numberOfMaximumCalorieCounts - 1) {
+            long thirdMaximumCalorieCount = maximumCalorieCounts.stream().min(Long::compareTo).orElseThrow();
+            maximumCalorieCounts.remove(thirdMaximumCalorieCount);
+            calorieCountToAdd = Long.max(thirdMaximumCalorieCount, calorieCountToAdd);
+        }
+        maximumCalorieCounts.add(calorieCountToAdd);
+    }
+}
diff --git a/README.md b/README.md
index 1b9a1d6c2463106cd5970904014876b4cd3b7a59..d5c6768ec25f327a0605c0ea5de029e82353cc1c 100644
--- a/README.md
+++ b/README.md
@@ -2,5 +2,5 @@
 
 My solutions to the [Advent of Code](https://adventofcode.com/) puzzles.
 
-I'm making [notes](2021/README.md) about the 2021 puzzles and my solutions.
+I'm making [notes](2022/README.md) about the 2022 puzzles and my solutions.
 
diff --git a/scaffolding/ImportData.java b/scaffolding/ImportData.java
index e472acd7745eaa72bdead83c1254703abbf21534..c6459ae7c58d3fe8cdd4e984f1b20cd66eda76cb 100644
--- a/scaffolding/ImportData.java
+++ b/scaffolding/ImportData.java
@@ -78,7 +78,7 @@ public class ImportData {
         BufferedReader bufferedReader;
         try {
             URLConnection connection = new URI(protocol, host, path, null).toURL().openConnection();
-            connection.setRequestProperty("Cookie", apiKey);
+            connection.setRequestProperty("Cookie", "session=" + apiKey);
             bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
         } catch (URISyntaxException | MalformedURLException originalException) {
             throw new IOException("Could not retrieve usable data from " + host + ".", originalException);