Java Migration & Polymorphic Fleet
Apologetic question: "The skill was never the language."
Project 6 — Java Migration & Polymorphic Fleet
Chapter: 7 — Shifting Gears: Java and Polymorphism
Due: End of Week 7
Submit: A link to your code — an OnlineGDB project URL or a public GitHub repo URL — with Main.java as the main source file. See Appendix A for the full workflow.
Allowed tools: Everything through Chapter 7, now in Java: classes, fields, methods, constructors, references, garbage collection, String and .equals(), Scanner, arrays, extends, @Override, super, instanceof, static members, toString(), and the enhanced-for loop.
Not yet allowed: Abstract classes and interfaces (Week 8), generics, collections framework (ArrayList etc.).
Estimated time: Normal 6–8 hrs · Medium 8–11 hrs · Hard 11–14 hrs
“For we walk by faith, not by sight.” — 2 Corinthians 5:7
“The languages change. The problem doesn’t.” — every programmer who has switched languages
The Setup
Last week you built the Argument Case File in C++: a base class, subclasses that each defended themselves in their own voice, a container that held them polymorphically, and a destructor that walked the whole thing and freed every byte you had borrowed. You counted the deletes. You ran the sanitizer. You earned it.
This week you rebuild that hierarchy in a language you had never seen on Monday.
That is the whole trick of this project, and it is not a trick at all. You are not learning object-oriented programming again. You are learning a second way to type it. The classes line up. The methods line up. The design decisions — what belongs on the base, which method each subclass overrides, what the collection is typed to — line up exactly, because those decisions were never about C++ in the first place. What changes is punctuation, keywords, and who is responsible for the memory.
So the project has two halves, matching the two halves of Chapter 7:
The migration. Take the Argument hierarchy you shipped in Project 5 and rebuild it in Java. Same classes, same behavior, same real attributions — new dialect. Not a line-by-line translation: a migration. Start from a blank Java file and the design you remember, not from your .cpp file open in the next tab. You will write it faster that way, and you will write it as Java instead of as C++ wearing a costume.
The polymorphic fleet. Then extend it. Your arguments go into an array typed to the base class, get walked with a single enhanced-for loop, and answer in several different voices from one method call. A static counter on the base keeps a running census of how many arguments have ever been constructed. One — exactly one — instanceof check reaches data that only one subclass has. This is Chapter 14 of the sixteen-week book, which had no project of its own; here it is the back half of this one, because in Java the migration and the polymorphism are the same lesson twice.
And you will write a short translation table: five things that changed on the way across, and five that did not. That second list is the point of the week.
If you did not finish Project 5
Read this paragraph and then relax. You can do this project at full credit without a finished Project 5. Section N2 below contains a small, fully specified fallback hierarchy — three subclasses, real sources, exact premise text — that you may use instead of your own. Using it costs you nothing on the rubric and requires no explanation, no email, and no apology. Week 6 is the heaviest week of this course and plenty of people arrive at Week 7 with an unfinished pointer project behind them; that is a scheduling fact, not a verdict on you. Take the fallback, build a clean Java program this week, and go back to the C++ when you have air. Your translation table will then compare your Java against the C++ you would have written — the reps in the exercises and §6.17 of Chapter 6 give you plenty to compare against.
Learning Targets
By completing this project, you will demonstrate that you can:
- Rebuild a working C++ class hierarchy as idiomatic Java, without a line-by-line transliteration.
- Write a Java class with private/protected fields, a constructor, accessors, and an
@Override public String toString(). - Build an inheritance chain with
extends, a correctly placedsuper(...)call, and@Overrideon every overridden method. - Hold objects of several runtime types in an array typed to their superclass, and dispatch through that superclass reference with one enhanced-for loop.
- Use a
staticfield and astaticmethod for state that belongs to the class rather than to any object. - Use
instanceofdeliberately and sparingly, and say in one sentence why the one you kept is legitimate. - Compare
Stringcontents with.equals()and never with==. - Read input with
Scannerin a way that survives an empty input box. - Articulate, in writing, which responsibilities the language took over and which ones stayed yours.
Normal Tier
Goal: One Java file. A migrated Argument hierarchy with three subclasses, a polymorphic roster walked by one loop, a class-level creation counter, one guarded instanceof, and a Scanner lookup — plus a written translation table.
The chapter showed you ArrayList in §7.8. Leave it in the box this week. Arrays and the enhanced-for do everything this project needs, generics are Week 8’s business, and the rubric checks for a plain Argument[].
Required features
N1 — One file, one public class.
Everything ships in Main.java: public class Main holding main, and every other class written without the public modifier below it, in the same file. This is the one-file pattern from §7.1 and §7.17 — code/CaseFileDemo.java is the worked example. It is not a shortcut; it is this book’s submission convention, and it makes your share link a single click for whoever grades it.
N2 — The migrated base class.
Port your Project 5 Argument base to Java. It must have:
- at least two
protectedfields carrying the argument’s identity (a label and a source is the minimum), - a constructor that takes them and assigns them with
this., - a method with a real body that prints the argument’s defense —
defend()is the name this brief will use, - a method that reports how many premises
defend()actually prints —premiseCount()in this brief — returning anint, - a
getLabel()accessor, - and
@Override public String toString()returning one readable line. Build it withString.format(...).
If you skipped or did not finish Project 5, use this fallback hierarchy exactly as written. Every source below is already in this book (§6.16, §6.17, §7.17); do not add attributions of your own unless you can cite a real text.
| Class | Label | Source string | Premises defend() prints |
|---|---|---|---|
Argument (base) | Generic Argument | base-class default - no attribution | 2 — A claim is offered. / A conclusion is drawn from it. |
Cosmological | Cosmological Argument | Aquinas, Summa Theologiae I, Q.2, A.3 (Third Way) | 4 — contingent things need a sufficient cause; the universe is contingent; an infinite regress of contingent causes explains nothing; therefore a necessary being exists |
Moral | Moral Argument | C.S. Lewis, Mere Christianity, Book 1 | 3 — objective moral obligations exist; obligations need a source beyond preference; therefore a transcendent moral standard exists |
Ontological | Ontological Argument | Anselm, Proslogion 2-3; modal form in Plantinga | 4 — a maximally great being is possible; so it exists in some possible world; maximal greatness includes existing in every possible world; therefore it exists in this one |
N3 — Three subclasses.
Three classes that extends your base. Each one must:
- call
super(...)as the first statement of its constructor, - carry
@Overrideon both overridden methods (defend()andpremiseCount()), - and print premises whose count matches what
premiseCount()returns. ApremiseCount()that lies is a wrong answer, not a style issue.
At least one subclass must declare one field of its own that the base does not have, plus a getter for it. (In the fallback, Moral carries a skepticLine — the one-sentence objection a skeptic actually raises — with a getSkepticLine().)
N4 — A static creation counter on the base.
private static int totalCreated;on the base class — one copy for the whole class.- The base constructor increments it and copies the new value into a per-object
idfield, so every argument knows both its own number and the class’s total. public static int getTotalCreated()returns it.maincalls it through the class name, before constructing anything (Argument.getTotalCreated()), prints the result, and prints it again after the roster is built. The first number must be0.
N5 — The polymorphic roster.
An array typed to the base class holding at least four elements: your three subclass objects plus one plain base-class object. Walk it with one enhanced-for loop that calls defend(). One call site, four different behaviors, decided by the object and not by the variable. Walk it again to print each object with System.out.println(" " + a); so your toString() does the work.
N6 — Totals, and the division trap.
Sum premiseCount() across the roster and print the total. Then print the average per argument to two decimal places with printf("%.2f%n", ...). The average must be computed in double arithmetic — see the Hints if yours prints a suspiciously round number.
N7 — Exactly one instanceof.
One guarded instanceof check that reaches a getter only one subclass has, followed by the cast. Either form is fine — if (a instanceof Moral) { Moral m = (Moral) a; ... } or Java 16+‘s if (a instanceof Moral m) { ... }. Directly above it, write a one-line comment saying why this particular check is legitimate and why the rest of your loop does not need one. §7.14’s Coach’s Note is blunt about this: every instanceof is a question you ask at runtime that the object could have answered itself. One is a design decision. Four is a hierarchy with a missing method.
N8 — A Scanner lookup, compared with .equals().
- Construct one
Scanner, prompt for a label, and guard the read within.hasNextLine()so an empty OnlineGDB Stdin box does not throw. - If nothing was typed, fall back to a hard-coded label that is actually in your roster, so the grader pressing Run always sees the feature work.
- Echo the label you are about to look up on the prompt’s line, so your transcript reads correctly whether the grader types it or pre-fills the Stdin box.
- Search the roster in a helper method that returns the matching object or
null, comparing with.equals(). - Print the match (and its
defend()), or a clear not-found message naming the label.
N9 — No == on Strings, anywhere. Search your finished file for == " before you submit. Every hit is a bug (§7.6).
N10 — Compiles clean and runs clean.
Zero errors, zero warnings, and no exception at runtime. In OnlineGDB, choose Java in the language selector and press Run. There are no flags to set — -Wall -Wextra are C++ flags and mean nothing to javac, so if a flags box appears on a Java project, leave it empty (Appendix A). A warning in the build console counts against you even when the program runs anyway.
If you took the GitHub path instead, your grader builds it with every warning switched on, so build it that way yourself first:
javac -Xlint:all Main.java
java Main
N11 — The reflection block and the translation table.
A /* ... */ comment block at the very top of Main.java containing the reflection template from Submission below, followed by your translation table: five things that changed on the way from C++ to Java, and five things that did not. Specific claims only. “Java is easier” earns nothing; “delete current->arg; delete current; in my ~CaseFile had no Java equivalent at all, so the destructor disappeared and nothing replaced it” earns full marks.
Example run
This is the real, unedited output of the reference solution built to this specification — compiled with javac -Xlint:all Main.java (no warnings) and run with Moral Argument in the Stdin box. Your data will differ; the shape should not.
Arguments constructed before the case file is built: 0
[Cosmological Argument] Aquinas, Summa Theologiae I, Q.2, A.3 (Third Way)
1. Contingent things need a sufficient cause.
2. The universe is contingent.
3. An infinite regress of contingent causes explains nothing.
4. Therefore a necessary being exists.
[Moral Argument] C.S. Lewis, Mere Christianity, Book 1
1. Objective moral obligations exist.
2. Obligations need a source beyond preference.
3. Therefore a transcendent moral standard exists.
[Ontological Argument] Anselm, Proslogion 2-3; modal form in Plantinga
1. A maximally great being is possible.
2. So such a being exists in some possible world.
3. Maximal greatness includes existing in every possible world.
4. Therefore a maximally great being exists in this one.
[Generic Argument] base-class default - no attribution
1. A claim is offered.
2. A conclusion is drawn from it.
Case file holds 4 arguments.
Total premises: 13
Average premises per argument: 3.25
Arguments constructed this run: 4
Roster:
#1 Cosmological Argument [Cosmological] - 4 premises
#2 Moral Argument [Moral] - 3 premises
#3 Ontological Argument [Ontological] - 4 premises
#4 Generic Argument [Argument] - 2 premises
Skeptic's line on the Moral argument: "Morality is just evolved preference."
Look up which argument? Moral Argument
Found #2 Moral Argument [Moral] - 3 premises
[Moral Argument] C.S. Lewis, Mere Christianity, Book 1
1. Objective moral obligations exist.
2. Obligations need a source beyond preference.
3. Therefore a transcendent moral standard exists.
Three things in that transcript are worth staring at.
The first line is 0, printed by calling a method through the class name before a single object existed. The last line of the stats block is 4, printed by the same method after the roster was built. One variable, shared by the class (§7.15).
The Roster: block came out of toString() and getClass().getSimpleName(). Slot 4 says [Argument] while the other three say their own subclass names — the object answering the question about itself, through a Argument-typed reference (§7.11).
And the whole defend() block came out of one loop with one method call in it. That is the sentence from §7.12 on the card: the declared type of the variable decides what you may call; the actual type of the object decides which version runs.
Grading rubric — Normal (out of 100)
| Criterion | Points |
|---|---|
Compiles with zero errors and zero warnings, and runs with no exception (the grader builds it with javac -Xlint:all Main.java) | 10 |
One file, one public class Main; every helper class package-private below it | 4 |
Base class migrated: protected fields, constructor with this., getLabel(), and @Override public String toString() | 12 |
Three subclasses: extends, super(...) as the first statement, @Override on both overridden methods | 16 |
| At least one subclass declares its own field plus a getter | 4 |
static creation counter and per-object id; read through the class name before any object exists, and again after | 10 |
| Polymorphic roster: base-typed array of ≥4, one enhanced-for, ≥3 distinct behaviors from one call | 14 |
Totals correct: premise total plus average in double arithmetic, printed with printf("%.2f") | 6 |
Exactly one guarded instanceof reaching a subclass-only getter, with its one-line justification comment | 5 |
Scanner lookup: hasNextLine() guard, .equals() comparison, both the found and not-found paths work | 8 |
No == on Strings; premiseCount() matches the premises actually printed | 3 |
| Reflection comment block (tier, features, what I learned, what I’d change, AI usage) | 3 |
| Translation table: five specific things that changed, five specific things that did not | 5 |
Medium Tier (+up to 25% extra credit)
Finish Normal first, all of it, and confirm it runs. Medium is stacked on top of a complete Normal, not offered instead of it.
M1. A second level in the hierarchy, extending instead of replacing
Add a subclass of one of your subclasses — a two-level chain, so FineTuning extends Teleological extends Argument — the same three-level chain Chapter 6 traces in §6.12 and names as a genuine is-a relationship in §6.18 — or the equivalent in your own data. (§6.18 also warned you that deep hierarchies are usually a mistake. Two levels is the shape this problem actually wants; going to three deliberately, once, is how you find out where the limit is.)
The new class must extend its parent’s behavior rather than replace it: its defend() calls super.defend() first and then prints its own additional premises, and its premiseCount() returns super.premiseCount() + n. Add it to the roster and confirm your totals move by exactly the right amount.
Then write one sentence in your translation table naming a subclass that replaces its parent’s behavior (no super call) and this one that extends it, and say why each choice was right where you made it.
M2. A menu-driven session
Wrap the program in a Scanner loop with a menu:
=== Case File ===
1. Present all arguments
2. Look up an argument by label
3. Roster and statistics
4. Exit
Choice:
Requirements: read every line with in.nextLine() and convert with Integer.parseInt(...) — never nextInt() (§7.5, Bug 12). A non-numeric or out-of-range choice must print a message and re-show the menu instead of crashing; catching the exception is Week 8’s tool, so guard the input by checking the text before you parse it. The loop must exit cleanly on 4 and must also exit cleanly when the input runs out, so the grader with an empty Stdin box still sees a finished program rather than an exception.
M3. Sort the roster by premise count
Sort your Argument[] in place, descending by premiseCount(), using a hand-written selection sort — no library sort, no collections. You are swapping references, not objects; two array slots trade what they point at and nothing gets copied. Print the roster before and after, and add one line to your translation table about what a C++ version of that swap would have had to say about ownership that the Java version does not.
Hard Tier (+up to 25% additional extra credit)
H1. Rebuild the Chain in Java, by hand
Project 5’s other half was a hand-built singly linked list. Rebuild it here as a package-private CaseFile class that owns your arguments:
- a
Nodetype holdingArgument arg;andNode next;— either a plain package-private class in the file, or aprivate static class Nodenested insideCaseFile, add(Argument a)appending at the tail (keep atailreference soadddoes not walk the list),find(String label)returning the matchingArgumentornull, compared with.equals(),remove(String label)handling all three cases — head, middle, and not found — and returning aboolean,size(),presentAll()walking the chain with awhileloop and callingdefend()on each node’s argument.
No LinkedList, no ArrayList, no library collection of any kind. The entire point is to prove you can still do this when nothing is doing it for you. Replace the Normal tier’s array with the chain and confirm the output is identical apart from ordering.
H2. The garbage-collection comparison, in writing
Add a titled section to your translation table with two headings and at least three specific items under each:
What the garbage collector removed. Name the actual C++ code that has no Java counterpart. Your ~CaseFile() destructor and its two-delete loop. virtual ~Argument(). The deleted copy constructor and copy assignment you wrote because the container owned heap memory twice over. Every delete in your main. Quote the C++ if you still have it.
What the garbage collector did not remove. This is the harder and more valuable list. You still write node.next = oldHead. You still walk the chain by following references and still lose the rest of the list if you overwrite next before saving it. You still decide what the collection is typed to. You still choose which methods live on the base. A reference bug in Java is a wrong answer instead of a crash, which is arguably worse. Be specific and be honest.
H3. The flex move
Find one Java feature this chapter did not cover, use it somewhere it genuinely helps, and document it. Strong candidates that stay inside this week’s allowed tools:
- Constructor overloading — two constructors on the same class, one delegating to the other with
this(...). final(§7.16) on a method a subclass must not override, orstatic finalconstants for your headings and field widths.printfwidth and alignment specifiers —%-28sand%5d— to print the roster as a genuinely aligned table.Stringmethods you have not used —trim(),isEmpty(),equalsIgnoreCase(),toUpperCase()— to make the lookup forgiving about case and stray spaces.
Document it in a comment directly above the code: what the feature is, why you chose it here, and what you would have written without it. An undocumented flex earns nothing — the documentation is the deliverable.
Submission
Submit one URL:
- OnlineGDB project link (recommended). Create the project at onlinegdb.com, choose Java as the language, build your solution in
Main.java, and share the link. Appendix A has the exact steps. - GitHub repo link (optional). If you have set up your own local toolchain, push the source to a public repo and submit that URL. You are responsible for it compiling with
javac -Xlint:all Main.javawhen the grader checks it out.
What the linked project must contain
-
Main.java— your complete solution, one public classMain, helper classes package-private below it. -
A reflection comment block at the very top of the file:
/*
* Tier targeted: Normal / Medium / Hard
* Features done: list each feature you completed, by its N/M/H number
* What I learned: one short paragraph (no bullets)
* What I'd change: one sentence
* AI usage: where and how, if any. Be honest.
*/
- The translation table, in the same comment block, directly below the reflection:
* TRANSLATION TABLE
* Five things that changed:
* 1. ...
* 5. ...
* Five things that did NOT change:
* 1. ...
* 5. ...
Each line is one specific, concrete claim about your code. Ten lines total, roughly one sentence each. If you did the Hard tier, H2’s two lists go here as well.
- The program left in a demonstrable state. When the grader presses Run, the features of your targeted tier should exercise themselves. Pre-fill OnlineGDB’s Stdin panel with the input your program expects, and make sure the program still finishes cleanly if that panel is empty — some graders will clear it on purpose to check.
No separate notes file. No screenshots. The grader opens your link, reads the comment block, presses Run, and grades against the rubric.
Coach’s Note — Test your share link in a private browser window before you submit. A link that only opens while you are logged in is a link nobody can grade, and in an asynchronous course that costs you a round trip you cannot afford in Week 7.
Hints
“javac says my class is public but should be in a file named something else.” The public class name and the filename must match exactly, capitalization included. OnlineGDB’s Java file is Main.java, so your public class is Main. Every other class in the file must have no public modifier (§7.1, Bug 1).
“My override never runs.” Three checks, in this order. Is @Override on the method? Add it everywhere you meant to override, recompile, and see which one suddenly fails to compile — that is your typo. Does the parameter list match the base exactly? Did you actually put the subclass object in the array, or did you build a base object by mistake? Print a.getClass().getSimpleName() inside the loop and read what it says (§7.11, §7.21 rung 5).
“constructor Argument in class Argument cannot be applied to given types.” Your subclass constructor is missing super(...), so Java tried to insert a no-argument super() and your base has no such constructor. Make super(label, source); the first statement in every subclass constructor (Bug 5).
“My average prints 3.00 when I expect 3.25.” This is the integer-division trap from §7.4, and it survived the trip from C++. Here is the arithmetic to check yourself against, using the fallback hierarchy exactly as specified in N2:
- Cosmological: 4 premises. Moral: 3. Ontological: 4. Generic base: 2.
- Total = 4 + 3 + 4 + 2 = 13. Roster length = 4.
13 / 4in Java, with both operandsint, is 3 — the remainder is thrown away silently, andprintf("%.2f")dresses it up as3.00.(double) totalPremises / caseFile.lengthis 3.25, which is what your program must print.
If your total is not 13, one of your premiseCount() methods disagrees with the premises its defend() actually prints. If your total is 13 and the average is 3.00, the cast is missing. Two different bugs; the arithmetic tells you which one you have.
“My output has Argument@6d06d69c in it.” You inherited Object’s toString() instead of writing your own. Those hex digits are an identity hash, they change every run, and they mean nothing. Write @Override public String toString() on the base class (§7.9).
“non-static method getTotalCreated() cannot be referenced from a static context.” main is static, so it has no object and no this. The counter getter must itself be static, because it reports class-level state — that is exactly why this feature is in the project (§7.15, Bug 3).
“NoSuchElementException: No line found.” You called nextLine() with nothing in the Stdin box. Guard every read with if (in.hasNextLine()) and keep a sensible default for when there is nothing there (§7.5, Bug 11). Test it both ways before you submit: once with the box filled, once with it empty.
“NullPointerException in my roster loop.” An Argument[] roster = new Argument[4]; starts as four null slots, and calling defend() on an unfilled one throws. Either use the initializer-list form — Argument[] roster = { new Cosmological(), ... }; — or fill every slot before you loop (§7.8, Bug 8).
“My lookup never finds anything even though the label is obviously there.” You compared with ==. In C++ that compared characters; in Java it compares object identity, and a String that came from Scanner is a different object from an identical literal. Use .equals(), and search your whole file for == " while you are at it (§7.6, Bug 13). Trailing whitespace is the other usual suspect — in.nextLine().trim() costs you nothing.
“How long should this take?” Normal 6–8 hours, and it is genuinely a two-session build: one session to get the hierarchy compiling and one to get the roster, the counter, the lookup, and the writing done. Medium 8–11. Hard 11–14, most of it in remove()’s three cases and in writing H2 honestly. If you are past ten hours on the Normal tier, stop adding features and get what you have compiling and submitted. A finished Normal beats an abandoned Hard, every time.
“I want to use ArrayList, it would be so much easier.” It would, and it is Week 8’s. Arrays and the enhanced-for cover everything here, and there is a specific reason to hold off: doing the fixed-size version once is what makes the growable version feel like a gift instead of a default.
What Mastery Looks Like
A great Project 6 reads like Java, not like C++ in a costume. Capital-S String. toString() instead of a printRow() helper. System.out.printf instead of setprecision. .equals() everywhere it belongs. @Override on every override, including the ones the compiler would have accepted without it. No get_label() in snake_case, no half-remembered ->, no comment explaining who owns what memory, because nobody does anymore.
A great Project 6 has one loop that produces several behaviors and no chain of if (a instanceof ...) branches pretending to be polymorphism. The single instanceof you kept has a comment above it that could survive an argument. If you look at your loop and see four instanceof branches, your base class is missing a method — go add it, override it, and delete the branches. That refactor is worth more than the extra-credit points you would have spent the same hour on.
A great Project 6 carries its data honestly. The sources are real texts you could hand someone. The premises are faithful one-line summaries, not paraphrases that drift into things the author never said. If you could not source it, you left it out and used one fewer argument. An empty field beats a plausible-sounding invention, in this course and in the thing this course is imitating.
A great Project 6 has a translation table that says something specific. “The syntax is different” is not an observation; it is a way of not making one. “In C++ I needed virtual ~Argument() or delete through a base pointer would have run only the base destructor and leaked the subclass’s string. In Java that whole category of bug does not exist, because there is no destructor to fail to call” — that is an observation. Write ten of those.
And a great Project 6 is shorter than the C++ it came from. Count the lines. The design is the same size; the plumbing is not. That difference, measured in your own two files, is the most concrete answer this course can give you about what a language actually is.
When You’re Done
- Read
Main.javaaloud, top to bottom. Does it sound like Java? Every place it sounds like C++ is a line to rewrite. - Run the search. Look for
== "in your file. Look for->. Look fordelete. All three should return nothing. - Run the program twice — once with your Stdin box filled, once with it empty. Both must finish without an exception. This is the single most common reason a working project loses points.
- Check your arithmetic against your own output. Add the premise counts by hand and compare with the total your program printed. If they disagree, your
premiseCount()is lying about whatdefend()prints. - Read your ten translation-table lines back. Cross out any that would still be true if you had migrated a completely different program. Replace each one you crossed out with something only true of your code.
- Open the share link in a private window and press Run there. That is what the grader will see.
- Submit.
- Then read Chapter 8. Look at the
defend()on your base class: a placeholder body that exists mostly so the base can be constructed at all. Week 8 hands you the keyword for saying there is no sensible default here out loud, and the final arrives with it.
Coach’s Note — Seven weeks ago you had never written a line of code. Tonight you migrated a class hierarchy between two languages and it worked. That is not a beginner’s move; that is the thing beginners watch other people do and assume they will never be able to do themselves. Whatever hour it is where you are, log what you finished before you close the tab, and pick up in the morning with the next thing already written down.
You are one week from the end of this course. Finish this one clean.