Working around serde_json bug #464 (serializing pre-epoch mtimes)

You may not know this, but Rust’s serde serialization/deserialization library can panic if you happen to feed it a file modification time prior to the UNIX epoch.

I discovered this when it killed an application I was writing and, in a lapse of reason, reported it on serde_json rather than the Serde core, where the problem code resides. I then went on to file a bug on Rust’s standard library about the API in question being too easy to misuse like this, with the docs not drawing sufficient attention to that hazard.

However, while I’m waiting for them to resolve the problem, I still need to actually get work done, so I cooked up a custom timestamp type that I can #[derive(Serialize, Deserialize)] on instead, because I felt it was simpler, cleaner, more concise code than overriding the default serialization for something like the Rust SystemTime type which serializes to a non-primitive JSON type.

Here’s the code I came up with, in case anyone else needs it:

Posted in Geek Stuff | Leave a comment

Why you should ALWAYS practice defensive programming

Take a look at this Rust snippet for a moment and tell me whether you can find the reason it’s not safe to run.

After all, Rust is a language that makes comfortable safety its claim to fame, so it should be pretty obvious, right?

if direntry.path_is_symlink() {
    return Entry::Symlink {
        path: direntry.path().to_owned(),
        target: read_link(direntry.path()).unwrap()

Surprisingly enough, there are actually two ways this can fail, and both can be insulated against by this change… assuming it’s acceptable for the Symlink variant to store an Option<PathBuf> rather than a PathBuf:

if direntry.path_is_symlink() {
    let target = read_link(direntry.path()).ok();
    if target.is_none() {
        println!("path_is_symlink() but read_link() failed: {}",

    return Entry::Symlink {
        path: direntry.path().to_owned(),
        target: target

(In this case, the error resolution strategy is “surface the error in an e-mail from cron via println! so I can fix it when I wake up and send a ‘best effort’ entry to the index that this code populates”.)

The hint lies within that .unwrap() or, more correctly, in the nature of what’s being unwrapped.

Problem 1: Rust’s ownership model can only protect you from misusing things it can control

The first code snippet is susceptible to a race condition because there’s nothing Rust can do to stop another program on the system from deleting the symlink in between the entry.path_is_symlink() and the read_link(entry.path()).

No matter how much validation you do, paths are inherently weak references to resources you don’t have an exclusive lock on. Either handle potential errors each time you dereference them (ie. every time you feed them to a system call), or, if possible in your situation, open a file handle, which the kernel can impose stronger guarantees on.

In my case, opening a handle to share between the two calls was not possible, because the initial query is done by the ignore crate, but I then have to call read_link myself. (I’ll probably file a feature request for this, since it seems like an odd oversight in ignore‘s metadata support.)

(This is what makes proper use of the access(2) function in the C standard library such a niche thing. File permissions can change between when you check and when you try to take advantage of them, so it’s only really proper to use it as a way to bail out early when, otherwise, you’re at risk of performing some heavy or time-consuming task, only to fail for lack of permissions when it comes time to make use of the results.)

I’ve actually written a more thorough blog post on this approach to looking at types of data.

Problem 2: Programmers are fallible

The entry object comes from a WalkDir iterator from the ignore crate, and, for some reason, in my project, the root of the tree always returns true for entry.path_is_symlink() even though it’s not.

Likewise, my very first test with an EXE parser named goblin panicked, because I threw an EXE at it that the author hadn’t anticipated being possible. (I’ve reported the bug and it has since been fixed.)

No matter how good a programming language is, you and the people who write your dependencies are still using the good old Human Brain, which has been stuck at version 1.0, bugs and all, for at least 25,000 years.

As of this writing, I haven’t yet determined whether the symlink bug is in my code or ignore, but it does present a perfect example of why I wrap each unit of processing in except Exception as err: (Python) or std::panic::catch_unwind(|| { ... }) (Rust) in my projects, even if I feel confident that I’ve handled or prevented each failure case with more specific code.

In short, you want a thorough belt-and-suspenders approach to safety:

  1. Expected Errors: Study up on ways that calls can fail, so you can avoid unnecessarily throwing away progress or giving vague diagnostic information with a coarse-grained recovery strategy. (I actually tripped over just this problem with serde_json in the same project, where it was difficult to diagnose and report a bug because the panic message didn’t contain enough information.)Despite that, this still is one of Rust’s biggest strengths. For example, I never realized that getcwd could fail in over a decade of using it in Python.
  2. Unexpected Errors: Identify your transactional unit of work (eg. a step in a processing pipeline that writes its intermediate products to disk, a single thumbnail in a thumbnailer, a single file in a downloader, etc.) and wrap it up in the most general error handler you can write.

As your knowledge grows, the scope of expected errors will grow (filesystem race conditions being a good example of something people don’t usually learn early on), but you’ll never anticipate everything. (Nor should you. There’s a curve of diminishing returns at play, and you need to balance robustness against programmer time.)

Suppose you want to leave your computer to thumbnail thousands of images overnight. You don’t want to spend weeks perfecting code for a single night of use, but would you rather wake up to find thousands of thumbnails and a handful of error messages in the log, or a few thumbnails and a panic message dating to not long after you fell asleep?

UPDATE: It turns out that the bug is in ignore and I’ve reported it.

Posted in Geek Stuff | Leave a comment

How to Hide Firefox’s New “Saved to Library” Confirmation Popup

…and another quick userChrome.css hack, since I wasn’t able to use the Browser Toolbox to figure it out and had to be told on Bugzilla… Removing the “Saved to Library!” confirmation popup that now appears when you add a bookmark.

(In case, like me, you find it excessive and distracting, having already built a habit of watching the star icon fill in.)

/* Hide "Saved to Library!" bookmark confirmation popup */
#confirmation-hint { display: none !important; }

Thanks to Gingerbread Man on Bugzilla for tracking it down.

Posted in Geek Stuff | 1 Comment

How to Remove The Thumbnail in Firefox’s Bookmark Popup

I run Firefox Developer Edition and, a couple of days ago, they announced a rather head-scratching feature which I received today: In the popup from the bookmarking star, they’ve added a thumbnail for whatever page is visible, right there below said popup.

Given that the distance between the bookmark star and the action buttons does have significance for efficiency with highly practised users, and that, not long ago, they already made the popup taller and thinner by needlessly moving the form field titles from besides their associated fields to above them (introducing whitespace of questionable aesthetic value in the process), I wasn’t going to stand for this… so I cooked up a userChrome.css snippet to get rid of this newest ill-considered style-over-substance change:

/* Remove pointless thumbnail in the Bookmark popup */
#editBookmarkPanelImage, #editBookmarkPanelFaviconContainer {
    display: none !important;

If you want to get started making your own tweaks, here’s how I did it:

  1. Enable the Browser Toolbox
  2. Click Hamburger > Web Developer > Browser Toolbox (or press Ctrl+Alt+Shift+I) (Be mindful of bugs 1437239 and 1120863 if your Firefox has been running for a while.)
  3. Select the “Inspector” tab
  4. Enable “Disable popup auto-hide” in the overflow menu on the right end of the Developer Tools tab bar.
  5. Click the bookmark star
  6. Click the “Pick an element from the page” button in the Developer Tools
  7. Click the unwanted thumbnail
  8. Note that it’s <box id="editBookmarkPanelImage"></box>
  9. Repeat the process with the favicon overlay and note that it’s inside an <html:div id="editBookmarkPanelFaviconContainer">...</html:div>
  10. Turn “Disable popup auto-hide” back off
  11. Write CSS to force those two IDs to display: none !important

Further Resources:

  • /r/FirefoxCSS has a tutorial that also covers live-debugging of userChrome.css tweaks.
  • has a link list with community sites and code repositories if you want to get advice or see how other people accomplished various effects.
Posted in Geek Stuff | 2 Comments

Novel – Nightfall

Since I was re-reading it anyway, I thought I might as well review one of my old sci-fi favourites:

Nightfall by Isaac Asimov and Robert Silverberg.

Originally written in 1941 as a novelette and one of Asimov’s earlier works and expanded into a novel by Asimov and Silverberg in 1990, this is a classic example of sci-fi imaginativeness combined with a nice touch of literary pragmatism.

Beginning with the beautifully well-chosen first sentence “It was a dazzling four-sun afternoon,” the story takes places on the planet Kalgash, where the six suns ensure that there’s never less than one sun in the sky. As such, the people have evolved with darkness as one of their deepest instinctual fears.

Ironically, it was written at the prompting of Asimov’s editor, in disagreement with the following Ralph Waldo Emerson quote:

If the stars should appear one night in a thousand years, how would men believe and adore, and preserve for many generations the remembrance of the city of God!

Now, before I get into the plot, I should explain what I mean by “literary pragmatism”. The book begins with a foreword which can be summed up as follows: This is an alien world and these people aren’t human… but the languages and physical forms of the characters are irrelevant, so we wrote them as humans to save effort and reduce the load on your memory. Feel free to imagine more alien appearances and words if you want.

To be honest, I wish more sci-fi authors did that. Prioritize the details that are important to telling the story. If there are details that are dear to you but irrelevant, write another book in the same setting or include some supplementary artwork or an appendix.

When it comes to the narrative itself, Nightfall does something else that I don’t see enough of, but which is nothing new for Asimov (For example, he also did it in Foundation): The first few chapters introduce several different groups of characters, each interesting enough that many authors would (and have) let the whole book revolve around them… and then we watch as the narrative slowly leads them to meet.

In this case, different professionals following small pieces of evidence (a psychologist, an archaeologist, and an astrophysicist) which will lead them to the same horrible truth: That, in less than a year, a quirk in their orbital system will bring about the first bout of darkness in two millennia, and their civilization will tear itself apart.

It’s a concept with a ton of potential, but there are two things which really make it satisfying to me:

First, despite the rough details sounding like yet another take on the spate of post-apocalyptic survival shows and other media that have become popular lately, this doesn’t pump the character drama to the detriment of the story. (And, yes, I’m aware that’s neither a recent thing nor an objective sign of bad writing. Poul Anderson’s Tau Zero was written in 1970 and nominated for the Hugo award, but, to me, it read like a soap opera about boring characters set in a context that should have been interesting.)

Second, the convergent narrative really makes the story. Rather than getting bogged down in showing a long build-up as a single character or set of characters plays detective, the reader is treated to the best parts of multiple different ways of arriving at the same conclusion… each with its own pleasant sprinkling of flavor text.

Finally, despite it feeling very contemporary to the 1940s in style, it still remains engaging, with characters I enjoy reading about and enjoyable world-building details, such as talk of the “Beklimot culture” which was being researched at the site where evidence of prior civilization is revealed. With Asimov’s skill at writing engaging characters and effectively managing reader expectations, even the heavy character interaction meant to drag out the build-up to the eclipse still avoids the “dull soap opera” feel I got from Tau Zero.

The story is broken down into three parts: Twilight (the build-up to the realization, months before the eclipse), Nightfall (the day of the eclipse), and Daybreak (the aftermath)… and I agree with the general consensus that Daybreak, which wasn’t part of the original novelette, is the weakest part. While Twilight and Nightfall are tightly written and punchy, Daybreak feels like it doesn’t quite know what kind of pacing it wants to follow, and comes across very much like a modern post-apocalyptic survival TV series.

Beyond that, the ending has a sense to it that the author shouldn’t have set out to portray Daybreak, because there wasn’t really a good way to live up to the standard set by the first two parts within the constraints given.

That said, it’s still an excellent story and I’d certainly give the first two parts a 5 out of 5 rating. Maybe a 4.8 for the story as a whole.

Finally, after having read so much fanfiction and other electronic fiction recently, the feeling of re-reading that inherently sub-optimal ending made me realize something: There’s nothing quite like the sense of completion you get from finishing a print novel. With a computer screen, or an eReader, the end is just a milestone like any other, marked by nothing unique except the removal of the “Next” button, which could also merely signify an incomplete work. …but with a book, you’ve felt the balance of pages under left and right hands slowly change for hours. Finally, you reach the last page, you read the last word, and then you close the back cover… and contemplate.

Posted in Reviews | Leave a comment

A Blueprint for Creating FLOSS-Safe Replacements for BWCC.DLL Stock Icons

TL;DR: Here’s a detailed description that should be sufficient to design knock-offs of the most iconic of Borland OWL’s stock icons for use Windows 3.1 hobby projects intended to be compiled with non-Borland compilers.

In the name making my planned retro-hobbyist programming projects both as easy as possible for me to write and as authentic-feeling as legally possible, I’ve been trying to collect period resources and tooling. However, I still want them to be open-source things that can be built using only legally free tooling.

(For example, while I intend to offer an older version of InnoSetup as the primary means of installation, “InstallShield” is a trademark and “setup is preparing the InstallShield wizard” was an iconic part of the Windows 9x era, so I took advantage of an opportunity to cheaply acquire a still-sealed New Old Stock copy of InstallShield Express 2.01 so users can choose between freedom and authenticity.)

This presents a problem when it comes to the stock icons from Borland’s BWCC.DLL which everyone remembers from the 16-bit Windows era. They’re an essential part of my childhood nostalgia, but I want people to be able to legally build and distribute my retro-projects using only OpenWatcom C/C++ or Free Pascal.

As such, I’ve decided to put together a description of said icons, suitable for designing from-scratch replacements which capture the same aesthetic and, in some cases, improve on the originals.

Here are the icons that I consider to be worth re-creating, in order from most to least desirable:

  1. OK/Yes (It’s used in the most places and has a very nice aesthetic.)
  2. Cancel (Probably the most used after OK/Cancel, also has a very nice aesthetic.)
  3. Help (It fits with the aesthetic of the other three.)
  4. Abort (I remember encountering this and it’s aged reasonably well for what it is. That said, it’s certainly a more complex thing to describe and draw than the “No” icon.)
  5. No (The iconography feels less elegant and it’s only strictly necessary if you need to have Cancel and No in the same dialog, given that the checkmark already does double duty as OK/Yes and the X for “Cancel” would really do better as “No”.)

Given that BWCCMessageBox takes the same arguments as MessageBox from the 16-bit Windows API, the following other icons also exist, but I don’t consider them iconic enough to justify the effort to put together detailed descriptions without some sign that they’ll actually see use:

  • Retry (A yellow slot machine where the handle pulls and the wheels take on different positions when the mouse button is held down.)
  • Ignore (A black-on-white speed limit sign where the numbers change from 55 to when the mouse button is held.)
  • MB_ICONINFORMATION / MB_ICONASTERISK (Either a blue lowercase, serif “i” in a speech balloon or a large, yellow, 3D, rounded exclamation mark with dithered shading, depending on context.)
  • MB_ICONQUESTION (A blue question mark in a speech balloon or possibly something else depending on context.)
  • MB_ICONSTOP / MB_ICONERROR / MB_ICONHAND (A white X inside a red circle or, if my memory is correct, a white hand inside a red stop-sign octagon depending on context.)

(I’m unsure whether the “depending on context” is a matter of which GUI widgets they’re requested for or which version of Borland OWL they were build against.)

That said, if you’re in a creative mood, feel free to try to come up with your own replacements that one-up Borland’s originals in sticking to a consistent aesthetic.

Release Considerations

First, in order to make it clear that you were working from these descriptions, please reference this post when you share your icons. This is for your benefit, since it will reassure potential users as to the legality of your icons if you re-create the Borland aesthetic too well.

Second, as the original icons were embedded within  BWCC.DLL, users of these icons are likely to also want to embed them in their own code. For them to do this, you need to release them under a license that won’t conflict with whatever license they choose.

I advise either the MIT or Creative Commons Attribution 4.0 license or both (both would be best). Given the following concerns, that would be most in line with the spirit of creating a free replacement for proprietary resources:

  1. The proprietary versions aren’t sold anymore… so people who don’t want to GPL can’t just buy the paid originals instead.
  2. The only people who target Windows 3.1 anymore are hobbyists and you’re unlikely to see anyone who cares so much about authenticity that they’ll either pay you or change their mind about how they want to license their creation.
  3. Retro City Rampage for DOS and Windows 3.1 is a personal programming challenge that got offered as a bonus to buyers of the modern copy because the tools to legally offer such a thing were free for commercial projects. The same is likely to be true for anything your license choice affects.

That said, if you choose to use a copyleft license, bear in mind that choosing something like the GPL or CC-BY-SA rather than the MPL 2.0 will likely result in people bundling a period-inappropriate folder full of unpacked .ico files with their application (possibly with a bundle of token alternative icons) rather than a .dll and no other change.

Copyleft licenses only extend to derivative works and a program isn’t legally a derivative work of your icons if the program works perfectly well without them and they can be trivially swapped out. (That’s why game engine re-creations like ScummVM are legal and why it’s legal to put GPLed stuff and closed-source freeware on the same shovelware CD.)

Icon Specs

Common Characteristics

  • Icon Size: Either 23px or 26px
  • Color Palette: Default EGA 16-color palette
  • Shading: Flat, using a three-color scheme: An EGA low-intensity color for the body, its high-intensity counterpart for the lit portions of the edge, and black for the portions of the edge in shadow.
  • Border: 1px, with the diagonal portions using a stairstep pattern which makes them appear heavier.
  • Lighting: Lit from above and to the left.
  • Drop Shadow: 2px down and to the right of the icon, in the low-intensity counterpart to the standard Windows button background color… but not to be drawn as part of the icon itself. (It moves independently when the button is pressed down to give the illusion that the icon is floating over the button, so it may be OWL generating it at runtime using the icon’s transparency mask.)
  • Aesthetic: The icons which best embody the desired aesthetic evoke a sense of being pixel-art recreations of calligraphy done with an extra-broad italic nib. (Example)

OK/Yes Icon

The icon used for stock OK and Yes buttons is a green checkmark, with an outline almost identical to the Liberation Serif glyph for the U+2714 HEAVY CHECK MARK codepoint. The original icon is 23px wide by 23px tall.

For easy reference, the EGA greens are #00AA00 and #55FF55 according to Wikipedia.

The hook of the checkmark is perfectly vertical, but with a slight curve on the top-left corner and a larger, shallower curve on the bottom-left corner.

The tail of the checkmark runs at a perfect 45° angle toward the top-right, with the top edge being perfectly straight 45° line, while the bottom edge appears to have a nick in it about 2/3rds of the way up, as it transitions from the width at the bottom to the width at the top.

The hook appears to be one pixel thicker than the tail and the tail ends in a perfectly vertical line, giving the “calligraphy pen with an extra-wide italic nib” effect.

The line appears to range from 3 to 4 pixels thick.

Cancel Icon

The Cancel icon is a red X similar to the Liberation Serif glyph for the U+2718 HEAVY BALLOT X codepoint but with the ends of the strokes being straight, rather than mimicking the output of a marker with a crenellated tip. The original icon is 20px wide by 23px tall.

For easy reference, the EGA reds are #AA0000 and #FF5555 according to Wikipedia.

It takes the form of two perpendicular strokes, running diagonally at approximately 45°.

The stroke from the top-left to the bottom-right curves upward very slightly over its length, and the stroke from the bottom-left to the top-right curves downward very slightly over its length.

Both strokes have square ends on the right side and are slightly curved on their upper corners on their left ends. Both strokes are approximately 4 pixels thick and have the same “calligraphy pen with an extra-wide italic nib” feel to them as with the checkmark.

Help Icon

The help icon is a cyan question mark. The original icon is 15px wide by 26px tall.

For easy reference, the EGA cyans are #00AAAA and #55FFFF according to Wikipedia.

Unlike the other two icons, it appears to have been drawn with a fine-pointed calligraphy brush, rather than a calligraphy pen, being composed of a round dot and a line with a rounded top end and a tail at the bottom end of the curl, characteristic of moving such a calligraphy brush off to the side as it is being lifted.

It gives the impression that its vertical centre line leans somewhere between 5° and 10° right of centre, and the shape of the question mark’s hook gives the impression that this might have been accomplished by taking a more ordinary question mark’s outline and pulling the right-hand edge of the question mark one part rightward and two or three parts upward.

When viewed without magnification, the tail at the bottom of the primary stroke appears to exit at roughly 45° down and to the left, but closer inspection reveals that this impression is partly due to the shadow and the icon actually extends the mid-point of the stroke’s bottom end straight rightward, and then curves the opposing edge of the stroke outward to meet it.

No Icon

The icon for stock No buttons is the ISO 3864-1 prohibition sign (U+1F6AB NO ENTRY SIGN or U+1F6C7 PROHIBITED SIGN). The original icon is 26px wide by 26px tall.

It is rendered in the same EGA reds as the Cancel icon (#AA0000 and #FF5555) with a stroke width matching or perhaps slightly thinner than the thinnest part of the checkmark.

Take note, the stroke within the circle runs from the top-left to the bottom-right. Some fonts will get this reversed for at least one of the two codepoints.

Stylistically, I think the mechanical precision of this icon’s design feels bland and the thinner lines reinforce the impression that it was a lazy effort. I would welcome efforts to design an alternative which feels more in line with the calligraphic style used for OK/Yes and Cancel.

Abort Icon

The icon for stock Abort buttons is an undithered EGA-palette drawing of a cylindrical red pushbutton set into a silver collar. Its proportions resemble a DS-426, model 6054 though it may be a pixel or two more squat. It is rendered in what is probably an oblique perspective, which makes it appear to be rising directly toward the light source.

Posted in Geek Stuff | Leave a comment

Fanfiction – Harry Potter and the Daft Morons

…and another thing I decided to review on the first read-through. This one a bit of a guilty pleasure.

Harry Potter and the Daft Morons by Sinyk

As unsophisticated as it may sound, every now and then, I do enjoy reading a well-written fic which says “screw it” to canon. …where Harry Potter one-ups the kind of manipulative Dumbledore who may or may not be evil and may or may not be conspiring with some of the Weasleys.

This fic does that well. It’s not perfect, being a bit exposition-y at first, but it’s fun nonetheless.

Dumbledore isn’t portrayed as over-the-top evil… he’s just manipulative and arrogant to the point of self-destructiveness. The Weasleys as a whole aren’t bad… but Molly and Ron need an attitude adjustment. (And Percy even gets a chance to shine in a very natural and in-character way during a family meeting.)

…though, when, after several novels worth of events, they finally get Dumbledore dosed with Veritaserum, it is very novel to see a formal interrogation result in Dumbledore getting officially and legally declared a Dark Lord by Amelia Bones.

It’s also a “The Potters are wizarding nobility” fic, but I also enjoy those on occasion and this, again, does a pretty good job of not making it merely an excuse to fix-fic things, going into a fair bit of detail on the social norms and hierarchy.

On that note, it’s a story of a specific type I’m not sure I’ve seen before. I’ve seen stories where Harry outwits the wizarding world, often by staying one step ahead of the Order while on the run. I’ve also seen fix-fics and politics fics. This has a little bit of all of them, but focuses on a blend of “foolish wizards” and hard politics that I haven’t seen before. (Usually, “foolish wizards” is for the light fics and hard politics is for the serious ones.)

Harry reveals that he’s a lot smarter than people think he is, but then makes a habit of pointing out things readers probably noticed, to the chargrin of those around him… such as his three amusingly paced, should-be-obvious suggestions for how to get in contact with Sirius Black so he can finally get a trial. (Owl him, try a messenger Patronus, or ask a house elf to try delivering a letter)

It’s also nice to see a Dumbledore who’s always outwitted, yet still doesn’t get beaten and dismissed too handily. He manages to parlay his way out of getting sent to Azkaban and keeps his job at Hogwarts because he’s got tenure, but his own arrogance and obsession leads to him being demoted to a mere professor because he was away from Hogwarts, scheming, when notice was sent for the hearing with the board of governors. He still tries to get Harry back, but gets the maximum allowable wait in a Ministry holding cell after getting picked up for trespassing because Harry had the anti-apparation and anti-portkey wards set a metre back from the actual property line. etc. etc. etc.

The key to this clever alternative interpretation, which made me appreciate it so much more, was when one of the unspeakables clued me in… He’s running circles around everyone because, in this story, “marked as the Dark Lord’s equal” is referring to mental and political prowess. (And, as Dumbledore realizes, possibly not about Voldemort at all)

At the same time, it mixes in some nice “summer at Hermione’s” bits when Hogwarts gets shut down pending the hiring of replacements for the newly vacated positions. The interactions between Harry, Hermione, and her parents are an enjoyable read. (And the author clearly understands how to use one-off characters to good effect, which is something I almost never see. In this case, a brief interaction with a little old lady Hermione clearly knows.)

Also, very notably, it manages to detail what Harry makes when he decides to cook for Hermione’s family for fun without it feeling like a drain on the story. In fact, I find myself curious to see what Harry will make next… which is another nod to the author’s skill.

That said, I do wish it hadn’t taken 16 chapters to reveal the narrative justification for making “Harry” short for “Harrison” early in the first chapter (a classic “Author didn’t do the research or gratuitously breaks from canon” warning sign) and I don’t like how, at least in the earliest chapters, it seems to muddle together elements of the book and movie continuities. (Which is a crying shame because later chapters clearly show that “the research” was done on multiple occasions. I especially loved having Harry and Hermione see The Santa Clause in the theatre and then having Harry draw a parallel with his own “stuck in a contract he didn’t agree to” situation.)

All in all, in the context of what it’s aiming to be, I’d give it a 4.3 out of 5. At times, it’s a 4.0 and, at times, it’s 4.5. Either way, it’s 745,285 words long, still actively going as of this review, and hard to put down.

Posted in Fanfiction | Leave a comment