Friday, July 05, 2019

A Low End Camera Shootout

We've got some travel with our nieces and nephew coming up, so it was time to dust off my collection of makePads and insure everything was ready for the kids to start creating.

The BLU Advance 4.0 has been working well as the makePad's hardware platform. The device is compact, cheap and functional. At $40 each, I can comfortably hand the phone to a kid and not worry how rough they'll play with it. One nagging limitation, however, is the quality of the camera. At 5 megapixels, the photos are fine at small sizes, but any degree of enlargement reveals how sub-par the pics are. I've wrestled with this pretty extensively: do the photos really need to be high quality? Could the lower quality be considered a creative constraint? How big a jump in megapixels would I need before I saw a notable difference?

Thankfully, Shira stepped in with a suggestion: swap the thought experiment with actual tests. That is, buy a bunch of BLU phones and do a photo shootout. And that's what I did.

The photos below are from a BLU Advance 4.0, BLU Advance 5.2 and a BLU R2 Plus. These have 5, 8 and 13 megapixel cameras respectively:

I found the results of this test to be insightful. At low resolutions, for example the thumbnails above, all the cameras look about the same. When enlarged, it's obvious at the A5 is better quality than the A4 and the R2 is leaps ahead of the A5. However, the jump from the 5 megapixel A4 to 8 megapixel A5 isn't as dramatic as I'd hoped. It's only when you hit 13 megapixels that you start to see some real improvement. So trading up to A5 from the A4 to gain 3 megapixels isn't worth it.

This is perhaps the best advertisement I've ever seen for a point and shoot digital camera. I'm tempted to try out this $40, 20 megapixel camera to see if it can deliver high quality pictures at a budget price tag. Though, a stand alone camera loses out to even the A4 in terms of versatility, so I'm not sure what that test would ultimately teach me.

Bottom line: unless I want to splurge on the $100/device, I'm just going to have to accept the cruddy image quality of the BLU A4.

Wednesday, July 03, 2019

One Wicked Bug: Fixing a PHP Upload Error #3

A few weeks back one of my customers started seeing a new issue with a recently updated Ionic app: uploading files resulted in a PHP Upload error #3, UPLOAD_ERR_PARTIAL. I'd come across the usual PHP upload errors before: needing to increase post_max_size, upload_max_filesize and max_execution_time. But these settings had never caused an UPLOAD_ERR_PARTIAL before.

One of the problems with the UPLOAD_ERR_PARTIAL error is how little information you're given. Apache and PHP report no errors, and there's no way to see the underlying web request that caused the problem. Using mod_security and mitmproxy gave me some interesting data, but nothing conclusive. mod_security reported a 408 Timeout and using mitmproxy actually corrected the problem altogether.

What had changed was replacing the standard Angular HTTP Client with a Cordova specific plugin. I'd found some evidence that iOS had timeout issues due to Keep-Alives, and thought that may be in play. Turning off Keep-Alive didn't help. I then swapped out the Ionic plugin, first for the FileTranser plugin, then for the native HTTP plugin. The problem persisted.

I then switched back to the Angular HTTP Client, and to my surprise, the issue showed up there as well.

I was just about to swap out Apache for Nginx, when it occurred to me that I hadn't investigated the issue from the Apache side of things. Attacking the problem from this angle yielded this hit on Google: Can't upload larger files to server. This individual ran into a similar issue and for once I got a new answer:

Found the problem. The Apache had a RequestReadTimeout header=20-40,MinRate=500 body=20-40,MinRate=500 setting which means the request's forced to timeout after max 40 sec... Another thing to watch out for.

I quick Google search of Apache RequestReadTimeout turned up a module I had no idea even existed, let alone one that was turned on by default. The mod_reqtimeout does what you think it does: if it takes too long to read a request, the Apache truncates the request. I enabled the logging the module suggested (LogLevel reqtimeout:info) and had my customer try again. Sure enough, the module reported that the request timed out.

Suddenly, the whole scenario made sense. My customer's slow connection was causing his uploads to be timed-out and truncated. From PHP's perspective the file was indeed a partial upload. Putting mitmproxy in between my client and Apache 'fixed' the problem because mitmproxy read the entire request slowly, reported it to me, and then delivered it all at once to Apache, which made Apache quite happy.

Not only am I pleased that I've fixed this bug, but I'm happy to have uncovered yet another critical Apache setting. Heck, just being reminded that you can turn up Apache's logging by setting LogLevel was an invaluable take away from all of this.

And here was I blaming Ionic, Cordova and iOS when the issue was fully due to my Apache ignorance.

Tuesday, July 02, 2019

More Columbia Pike Adjacent Fishing

Given the fishing success I had at Holmes Run, I was curious if a creek-like section of Four Mile Run would have similar results. So last night I made my way back down Columbia Pike and took advantage of the free parking at Arlington Mill Community Center.

I took the stairway down to the run and walked North. The water level was low, but I remained undeterred. Within 50 yards of entering the run I found what appeared to be a pool that was a couple of feet deep. I tossed in a small orange grubby plastic thing and bam! a sunfish snatched it up. I had my answer: there were definitely fish here!

For the next hour I made my way up the run, finding pools and pulling in sunfish. Obviously, they weren't huge, but for the size of the run they were actually pretty chubby.

At one point I came across a point where faster water was flowing between two rocks. I could see some larger fish--perhaps trout--hanging out in this section. I tried variety of baits, but they weren't biting. Still, this tells me that there's definitely interesting fish to be had in this section of the run.

Like Holmes Run, I was impressed at the solitude and nature factor. It was easy to forget that I was just a few hundred feet from homes and buildings. It was a relaxing time, with only the occasional runner, walker or biker passing by to break the illusion that I was fishing in a pristine wilderness.

If you're looking for an easy fishing option, look no further than Four Mile Run near the Arlington Mill Community Center. What you'll give up in terms of stalking monster fish, you'll make back in convenience and simplicity. And I'm so going back with more gear to try to land me some trout.

Monday, July 01, 2019

A Very DC Ultra Run

A few years back I enjoyed this read: I Walked 64 Miles Around the Beltway. What the Hell Was I Thinking? It's the tale of two friends tracing a path, as close as possible, to the DC beltway. The TL;DR version is this: they got way more than they bargained for. What seemed like a novel idea turned into a death march. An entertaining to read death march, but a death march none the less.

I enjoyed the story because it's a wonderful reminder that adventure doesn't require hopping a plane to a far off land. There are challenges and discoveries to be had in our own backyard. It's also a humble reminder that miles always seem small on paper. How gruelling can a 64 mile hike be? Turns out, very.

Why mention this story now? Over the weekend, Shira shared this tweet with me:

That's right, fellow Aringtonian Michael Wardian *ran* around the beltway. In one day. And he didn't cover 64 miles; his route took him almost 90. Even Mother-Nature didn't want to cooperate, and made the weather extra hot for his run.

You can read more details of Michael's run here and here. You can see the route he took here.

In short, what a superhuman effort.

Friday, June 28, 2019

Discovering the Goldmine that is the M5Stack Arduino Environment

When I last played with my M5Stack Fire device I had figured out a development environment and had my code for my first trivial app written. The app, if you can even call it that, accepted button input and made web requests to a particular URL with the button label appended. I was able to get both button detection and URL invocation working. Alas, when I combined these operations into one program the result was a system crash. Such a pain.

Out of frustration I put the device down planning to return it with fresh eyes.

This week I picked up the device and thought I'd try another approach to programming it. I'd had a recollection that the Arduino IDE had M5Stack support. A quick Google search turned up a YouTube video that promised I'd have this environment setup in less than 5 minutes.

Impressively, the video wasn't far off from its 5 minute promise. There were a bunch of steps, but everything fell into place and before I knew it, I'd configured the Arduino dev environment to work with my Fire.

But the part that blew me away was all the example code that's available:

For a good 20 minutes I was a kid in a candy store: opening up demos, running them, and ooh-and-ahhing as my M5 came to life. Bluetooth, WiFi, microphone support, LED support--there's code to demonstrate it all. If I can see the individual examples running, I should be able to mix and match the pieces into interesting projects. So. Cool.

Returning to my original challenge, I used the Display, Button and BasicHttpClient examples to work up my little button triggered URL app.

I ran into one gotcha during the process. At some point, attempts to flash new code to the device resulted in the cryptic message:

Arduino: 1.8.9 (Mac OS X), Board: "M5Stack-FIRE, Enabled, Default (2 x 6.5 MB app, 3.6 MB SPIFFS), 115200, None"

Sketch uses 344988 bytes (5%) of program storage space. Maximum is 6553600 bytes.
Global variables use 16604 bytes (0%) of dynamic memory, leaving 4505380 bytes for local variables. Maximum is 4521984 bytes. v2.6
Serial port /dev/cu.SLAB_USBtoUART
Chip is ESP32D0WDQ6 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 84:0d:8e:25:aa:34
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Warning: Could not auto-detect Flash size (FlashID=0xffffff, SizeID=0xff), defaulting to 4MB
Compressed 8192 bytes to 47...

A fatal error occurred: Timed out waiting for packet content
A fatal error occurred: Timed out waiting for packet content

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

I eventually arrived at a simple fix: hold down the power button on the device while Arduino is compiling and flashing the code. Easy peasy.

You might be wondering, what good is having a small device where a button press triggers a URL call? Thanks to Tasker and AutoRemote, it's possible to make your phone take essentially any action in response to a web request to a special public URL. For example, I setup a trivial Tasker profile that plays an ear splitting sound when button B is pressed on the M5. This is useful when I've put my phone down in my house and lost track of it; something that seems to happen constantly.

While I'm excited that I've got my first baby M5Stack project completed I'm even more excited to have this mountain of demo code to play with. Now the real fun can begin!

Here's the code to power the behavior described above, as well as some action shots. Enjoy!

 * Pressy!
#include <M5Stack.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>

WiFiMulti WiFiMulti;

#define AUTOREMOTE_BASE String("")
#define AUTOREMOTE_KEY String("--auto remote key goes here--")
#define AUTOREMOTE_PREFIX String("Pressy_")

void clearScreen() {
  M5.Lcd.println("Ready: ");

void autoRemote(String btn) {
  String url = AUTOREMOTE_BASE + "?key=" + AUTOREMOTE_KEY + "&message=" + AUTOREMOTE_PREFIX + btn;
  HTTPClient http;
  M5.Lcd.print(btn + "...");

void setup() {
  // init lcd, serial, but don't init sd card
  M5.begin(true, false, true);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.print("Setting up WiFi:");

  WiFiMulti.addAP("SSID", "PASSWORD");

  while( != WL_CONNECTED) {


// Add the main program code into the continuous loop() function
void loop() {

  // if you want to use Releasefor("was released for"), use .wasReleasefor(int time) below
  if (M5.BtnA.wasReleased()) {
  } else if (M5.BtnB.wasReleased()) {
  } else if (M5.BtnC.wasReleased()) {
  } else if (M5.BtnB.wasReleasefor(700)) {

Tuesday, June 25, 2019

Review: Crossed by Ally Condie

Crossed by Ally Condie was, for me, a dud. It had to have some redeeming qualities as I continued to listen to it (more on that below), but overall it just wasn't a fit.

I started reading Crossed randomly without any clue to its content. I quickly realized that it was in the Distopian-Young-Adult genre, à la Hunger Games. The problem is, the Hunger Games series ended up being so awful that anything I read that's remotely similar triggers a bad reaction. This, of course, is totally unfair to Crossed. For all I know Crossed could have been written well before Hunger Games (checks Amazon: nope, Crossed was published years after Hunger Games).

The other strike against Crossed is the whole young-adult aspect. I get it; you're a teenager and you're wrestling with your feelings. And you've got a crush on someone, and you so want to hold their hand and get that first kiss. Yes, it's cute. But apparently, I'm so over it.

Perhaps I need to track down an adventure story about a couple who's been married for decades. They've had crushes on each other, and their share of blow-out-fights. There's no question of will-they or won't-they end up together, because the are together. It isn't cutesy, but it's effective. By now, they're an unstoppable team that can read each other's minds and anticipate each other's moves. What they lack in fawning over each other, they make up for in support, love and respect. I'd so read that.

The final strike against Crossed was that it's book #2 in a trilogy, so by its very nature it has to be a transitional story. In other words, for all the action nothing really happens. Clearly reading book #2 first was a mistake, and that's what I get for going in cold. I suppose if the story had been riveting, I would be inspired to read the the other two. But alas, it was just OK, so I'll pass on the series.

Kvetching aside, Crossed isn't without its redeeming qualities. The characters are pretty likable, even if they are a bit insufferable. And the story didn't descend into the pointless abyss that the Hunger Games did. I also enjoyed using the clues provided to figure out the rules of the distopian society, an exercises needed because I skipped the first book.

While I don't totally get why, I thought it was clever to emphasize the beauty and power of poetry. I for one found myself Googling various poems, inspired by the book. If Crossed manages to get teens to read and think about poetry then I'll gladly take back any and all of my complaints.

I also liked the suggestions that the distopian society evolved not out of pure evil, but out of the intention to do good. Again, I didn't read the first book, so my interpretation of this may be wrong. It seems that in an attempt to cure cancer and most likely other woes, humans have backed themselves into a corner. Ah yes, the power of unintended consequences. Like the emphasis on poetry, this is another great topic for teens to encounter and explore.

For the right (and intended) audience, Crossed and the other books in the series are almost certainly a winner. Kids should dig the love story, and parents should appreciate that their kids are being exposed to important themes. It's a win-win. Just not for me.

Monday, June 24, 2019

mitmproxy: X-Ray Vision for Web Developers

Last week I found myself needing to debug a PHP upload error. The problem: PHP was reporting a UPLOAD_ERR_PARTIAL without giving specifics. For starters, I was curious what data was being uploaded. This turned out to be trickier to discover than I thought.

First, I tried using the file_get_contents('php://input') trick to grab the bytes being uploaded. This doesn't work, because as the manual reports, php://input is not available with enctype="multipart/form-data". In other words: you're out luck if you're dealing with file uploads.

Undeterred, I decided to move up the stack a bit. If PHP wasn't going to reveal the raw data, then I'd simply ask Apache to log this information for me. This lead me to try mod_dumpio, mod_dumpost and mod_security. mod_security was the closest to a viable solution, as it didn't just log the data but also gave me the option of extracting and storing the data being uploaded. The problem with mod_security is its complexity; it does so much. I found this post pointed me in the right direction to getting mod_security at least partially configured. I still wasn't happy with this solution.

I decided to take a step even further back: could I run some sort of proxy server that could sit between my browser and Apache?

I can, and I did! I give you the well named: Man-in-the-Middle Proxy, or mitmproxy for short.

I was skeptical about how much work setting up mitmproxy would be. I cheated and grabbed a binary download for linux. I then made a single tweak to apache: instead of listening on port 80, I changed it to listen on port 8080.

# Listen 80
Listen 8080

I restarted apache and then kicked off mitmproxy from the command line like so:

$ sudo ./mitmproxy -p 80 \
        --set keep_host_header=true \
        --mode reverse:http://localhost:8080

I pointed my web browser to the usual location and started accessing my web app. To my surprise, everything Just Worked. Flipping back to the mitmproxy screen, I saw my browser requests streaming in. At this point I started to appreciate the interactive side of mitmproxy. I realized I could choose to inspect individual requests on the fly, including those with multi-part file uploads. Finally, I could easily inspect these mysterious failed PHP uploads.

I've used Proxy Servers in the past to aid with debugging, but mitmproxy takes this to a new level. It's definitely going into my bag of tricks for future debugging sessions.

Friday, June 21, 2019

Gift-of-a-Playlist, Now Even More Gift'ier

It bothered me that Gift-of-a-Playlist started off with all of the YouTube videos visible. I want to give recipients a chance to read what I've written, then view the videos.

So I added a big 'ol Reveal button on top of each clip:

With that feature implemented, I can officially create my brother's birthday gift and send it off to him; only 1 month late. Not bad!

You can try this little app for yourself by visiting: and plugging in the sample playlist document:

I'm telling you, gifting playlists should so be a thing. And now they are.

Thursday, June 20, 2019

A Dopp Kit Dump

This past weekend I was organizing a shelf full of travel stuff and realized my dopp kit was missing. Did I leave it at a hotel? Or maybe I just put it back in a non-standard location? Regardless, I was bummed. Not because the kit contained anything of significant value. No, the problem was that after years of travel I'd finally tuned it to be Just Right. It was split into two sections: a compact set of toiletries and a collection of handy utilities. I didn't relish the idea of rebuilding it.

Fortunately, I found it. But before I put it away I dumped the contents and took a few pictures. If I do lose my kit, I'll now have a much easier time recreating it.

So here it is, my finely tuned travel toiletry setup:

The razor is an old Gillette Sensor Excel with off brand blades. It's a compact and inexpensive setup; perfect for travel. The little plastic bags contain soap and deodorant respectively.

The deodorant solution took me years to arrive at. I found the easy-to-pack deodorant crystal rock to be ineffective. And Shira wasn't having my, 'but I'm traveling I don't need to wear deodorant' philosophy. So now I buy a travel size deodorant, remove the tray of antiperspirant material and discard the bulky plastic shell. The result takes up far less space, yet is just as effective as any other standard deodorant.

The blue container has a blob of Bed Head Men Matte Separation Workable Wax in it. I find that stuff beefy enough to keep my hair relatively in check.

The utility side is more interesting. I keep quite a few over the counter meds in there, including allergy, cold and antidiarrheal pills. When you need any of these pills, they're a life saver.

I intentionally keep caffeinated and decaffeinated tea bags on hand, knowing the caffeinated options can be used to help keep me awake.

I carry the thumb-sized USB light for the same reason I carry a Bic lighter: it has an impressive size to functionality ratio. One common use of the light: plug it into a USB charger in the bathroom and use it as a nightlight.

Do you carry any unusual items in your dopp kit? If so, do share in the comments below.

Wednesday, June 19, 2019

More Thought, Less Cost - Gift-of-a-Playlist

I have a vague recollection of a post from years ago where I suggested what a meaningful gift a YouTube playlist could be. I can't find it now, but the concept has stuck with me. Compiling music, How-To-Videos, movie clips, and other YouTube discoveries for a friend or loved one seems like a fun, frugal and thoughtful way to show you care without buying more stuff. Think of it as a YouTube powered mixtape.

With my oldest Brother's birthday coming up, I figured I'd finally try my idea out. I visited YouTube and started collecting up clips. Finding content was easy, the problem I ran into was there was no way to annotate my playlist. Just sending my brother a list of videos wasn't going to cut it. Each video needed a little explanation to provide context. I couldn't find a way to do this on YouTube so I whipped up my own solution.

I give you: Gift-of-a-Playlist.

Step 1: create and publish a Google Sheet with two columns: Video and Message. See this example.

Step 2: visit Gift-of-a-Playlist and enter the URL of your spreadsheet:

Step 3: choose the tab within the Google Spreadsheet:

Step 4: share the URL of the generated playlist. Here's the above example in playlist form.

You can find the source code for this little app here.

One neat feature is that the playlist you send remains connected to the spreadsheet. If you send the link and find a typo or think of another clip to add, you can update the spreadsheet and the link will reflect those changes.

Before I send my brother his now belated birthday gift, I've got one more feature to implement. I'd like to start off with the videos hidden and have a 'Reveal' button that shows them. Think of it as giving the person a chance to unwrap your virtual gift.

Happy gifting!

Monday, June 17, 2019

Name that Plant: Two-Toned Purple Leaves Edition

While on a walk, I couldn't help but notice this out-of-place plant:

With the triangularly shaped two-tone purple leaves it wasn't hard to identify. This guy is almost certainly an Oxalis triangularis. While exotic to me, this is a common ornamental plant. It supposedly does well both in your garden and as a house plant. They have a reputation for being low maintenance.

The plant is edible, though not in large quantities. It's also a bit of a movie star, making for impressive time-lapses due to its photonastic behavior.

He's a fun one!

Here's a couple more pictures from our walk, which took us along Holmes Run for a mile or so.

Wednesday, June 12, 2019

I've Got a Guy For That: Painless Running Shoe Shopping

Part of my plantar fasciitis recovery plan was to get new running shoes, an activity which is usually fraught with frustration. From finding the right size, to avoiding the latest gimmick, buying shoes has always been a crap shoot. Worst of all, I thought I had found a winner with the Merrell Trail Glove 4 . They were lightweight, comfortable, and promised all the rewards of a minimalist shoe.

This all held true, until it didn't. It's like a friend had turned on me: suddenly running in my Trail Gloves left me with debilitating pain in my left foot. I tried running with them using orthotics, no dice. My body was loudly and clearly telling me it was time to get new shoes.

I had one glimmer of hope during this upcoming shoe buying experience. I've got a friend, John, who works at Metro Run & Walk in Springfield. For years he's been encouraging me to come out and get fitted for running shoes. Now, with pain and no clue what shoes I should buy, I finally made the effort to visit him.

The shopping experience was almost surreal. John asked me some questions about my running, which as far as I can tell, solicited only vague answers. He measured my foot and inspected my orthotics. He then returned from the back room with two pairs of shoes. I slipped each on in turn and they both felt awesome. I ended up selecting the first pair, paid and walked out with my brand new kicks.

There was no stream of endless shoe styles to consider; no mental battle as to whether I was wearing the right size. It was just: put shoes on, feel good, move on.

So far I've logged about 20 miles of activity in the shoes. My right foot, the one without the plantar fasciitis is in heaven. My left foot has been achy during my runs, but this is orders of magnitude less pain than I was getting with my Trail Gloves. There's no doubt I've traded the lightweight sports-car feel of the Merrells for a bulky Cadillac ride in these new shoes. But with my current injury, the luxury feel is just what I need.

I was happy to leave all of this alone: I had shoes that fit and were comfortable. But Shira was doing some online shopping and managed to come across a review for the Brooks Ghost 11 (size 12, 110288 1D 006), the shoes I'd bought. Reading the review, I found the shoes were decidedly on target for my needs:

I came across this shoe when I ran into a sore Achilles tendon. Usually I run in zero drop shoes but sometimes running with this style of shoe can put a lot of stress on the Achilles tendon. While making the Achilles tendon and calf muscles stronger can be a good thing getting Achilles tendonitis can sideline any runner. I still love running in my Altra running shoes and they’re my shoe of choice for race day but I now rotate in the Brooks ghost 11 when I feel like my Achilles tendons are getting tight. Just like a good bowler uses a few balls a good runner will have a few different shoes when they need them.

Wait, your zero drop shoes stopped being comfortable and you needed a more comfortable option? Me too!

When it comes to performance I wouldn’t give the Brooks ghost 11 high marks. It is a big bulky shoe that isn’t built for speed. The shoe is great for an easy run or recovery run but when I try to go fast it’s just plain hard in this shoe. If you’re a speedster I would skip the Brooks ghost 11 and get something lighter without as much bulk on the bottom of the shoe. If you’re focused on endurance only and have ankle issues the Brooks ghost 11 is a great choice.

I'll gladly trade speed for endurance and comfort. Any run I finish injury free is a win. This reviewer suggests there's value in using both a minimalist shoe (my Trail Gloves) and the Brooks ghost 11 in tandem. That's a novel concept, and perhaps when my PF fully clears up, I'll give that a try. Until then, I'm going to relish my new uber comfy shoes.

And if I did need a shoe built for speed, I'd have a solution there too: head back to Metro Run & Walk and ask John to work his magic again.

Tuesday, June 11, 2019

A Review of Biblical Proportions: I Am Mother

This post is basically one big spoiler - so don't bother reading it till you've watched I Am Mother.

Perhaps it's all the shul I've attended thanks to Shavuot, but I can't help but see I Am Mother as a sort of uber-modern take on the story of Noah's Ark and biblical creation in general. This may all be in my head, but the links seem too obvious to ignore.

Consider these brief comments on the story of Noah:

In Parshat Noah, however, there is a moral imperative. The world is flooded not because God arbitrarily decides to destroy the world, but because it had become corrupt and destructive. Noah is not arbitrarily saved. He is deserving. He is a “righteous man, perfect in his generation. With God, Noah walked”

In a movie like I Am Mother, one expects the robot uprising to be the result of AI outgrowing their human creators. But that's only partially the case here. In this case, robots don't want to destroy us, they want to 'help' us. It's like they've taken a page out of Bereshit: to fix the world, one must wipe out humanity and start anew with a moral core of society.

I can't help but see other biblical connections: for one, there's massive container ship that couldn't look more ark-like if the movie makers tried. There's Daughter's folded paper animals which mirror Noah's ship-mates. Noah uses a dove to confirm that the Earth is habitable, the movie uses a rat. Genesis arranges for a number of tests to confirm Abraham's moral fortitude, Mother has Daughter take a series of tests as well, the failing of which we learn would mean her destruction and a restart of the experiment. Mother explaining that it's a universal consciousness that isn't confined to one body but is everywhere sounds an awful lot like a description of G-d. By Daughter destroying the robot form of Mother, we see a severing of the direct link between man and G-d, leaving only an etherial one. The robot's planting of crops seems to mirror G-d's construction of the Garden of Eden.

With these connections, I see a story that's more nuanced than your typical post-apocalyptic humans-fight-for-their-survival flick. I see a story that wants to test our ideas of what it means to be moral, and what it means to put the good of the world above the good of the person. The story of Noah and religion in general should be a challenging thing, and I Am Mother brings to light why that is. And if one goal of the movie was to take these settled ideas and make us wrestle with them again, then it has succeeded.

Update: Here's another biblical connection, this one provided by the IMDB movie FAQ:

None of the characters we meet are ever given a name, and the named characters (whom we never meet) all have well-known biblical names: Jacob, Rachel, and Simon.

Wednesday, June 05, 2019

Fishing Holmes Run

Every time I bike, hike or run Holmes Run Trail I have the same thought: can I fish this run? In some sections it's quite shallow, but other sections are inviting. There's a note at the Columbia Pike trail head that talks about how the waterway is under a delayed trout harvest, so that tells me that they stock the stream with trout; a promising sign.

Last night, I decided to forego my run and find out first hand what fishing Holmes Run is like.

I spent a couple of hours fishing the first 1,000 yards of the trail; from the trail head off Columbia Pike to the first water crossing. Getting down to the water was simple, as there was a bushwhacked trail to follow. From there, I made my way first up the bank to the bridge, and then down the bank to the water crossing. My first thought when getting to the edge of the water was that the level was too low; I thought for sure my little adventure was over before it had started.

I was immediately put at ease when my first cast landed me a tiny sunfish (or was it a bluegill?). He snatched up my trout magnet lure like it was a gourmet meal and he hadn't eaten in days. As I made my way along the water, I found a number of slightly deeper pockets of water and pulled in more pan fish. All told, I easily caught more than half a dozen, all on trout magnets.

But it wasn't just that I caught fish that made this adventure so notable. I'd driven less than 20 minutes from my house and found myself surrounded by the sites and sounds of nature. While off-trail fishing, I saw more herons than people (herons: 2, people: 1). It was wonderfully relaxing, and actually catching fish was a nice bonus.

The trail isn't perfect: I didn't have any luck pulling out more noble trout and you can hear road noise at various points along the water. Holmes Run has a reputation for smelling like sewage, which at moments I could detect hints of. But my gosh, I've stood along the Potomac a number of times on a weekday trying to catch fish, only to watch time expire before I had to head home. And the sunfish I caught were truly beautiful creatures.

I know folks fish the Potomac to haul in massive catfish and the like, and if that's your jam go for it. But if you're looking for a close-to-DC ultralight-friendly fishing experience, definitely give Holmes Run a try. I know I'm curious to go back again and see if my experience is repeatable, or just beginner's luck.

Tuesday, June 04, 2019

One Click Spreadsheet Archiving | Google App Script For The Win

I was using Google Sheets for planning, and noted that I was making copies of the various tabs to serve as an impromptu archiving mechanism. But why manually duplicate tabs when you can write code to properly snapshot the data? Below is a the Google App Script to do just this.

function archiveSheet() {
  var pad = function(x) {
    return x < 10 ? ("0"+x) : x;
  var archiveDirId = "1GCaGcqsP1FzWe_ZAXJ4N6GHW1vbP0tBk";
  var now     = new Date();
  var sourceDoc = SpreadsheetApp.getActiveSpreadsheet();
  var sourceSheet = SpreadsheetApp.getActiveSheet();
  var workingSheet = sourceSheet.copyTo(sourceDoc);
  workingSheet.setName(sourceSheet.getName() + " To Archive");
  var data = workingSheet.getDataRange();
  data.copyTo(workingSheet.getDataRange(), {contentsOnly: true});
  var archiveName =  sourceDoc.getName() + " - " + sourceSheet.getName() + " - " + 
    now.getFullYear() + pad(now.getMonth()+1) + pad(now.getDate());
  var archiveDoc = SpreadsheetApp.create(archiveName);
  var archiveSheet = workingSheet.copyTo(archiveDoc);
  var emptySheet = archiveDoc.getSheetByName("Sheet1");
  var archiveFile = DriveApp.getFileById(archiveDoc.getId());
  var archiveFolder = DriveApp.getFolderById(archiveDirId);

function onOpen() {
  var ui = SpreadsheetApp.getUi();
      .addItem('Archive current sheet', 'archiveSheet')

The above code grabs the active sheet and makes a copy of it. It then copies the data back onto itself with contentsOnly set to true. This insures that there won't be broken formula references when the archive is created. The code then creates a new document, removes the unneeded Sheet1 from it, and copies the prepared data into it. The code also moves the archived file from Google Drive's root to a folder of your choice.

Here's a few screenshots and a link to a sample document.

If you make use of Installable Triggers, you can set this archiving function to happen automatically at a given day or time.

It's impressive how easy it was to implement this functionality. App Script really delivered.

Monday, June 03, 2019

Review: Sailing Alone Around The World

Browsing YouTube you might think Adventurer / Storyteller was a millennial invented job. But I can tell with authoritatively this isn't so. I just finished listening to a book that would fit perfectly among its polished YouTube and Instagram peers. That story is Sailing Alone Around The World by Joshua Slocum. The only reason it isn't featured highly on social media is that it was written in 1898!

That was the year that Captain Slocum finished the first known solo-around-the-world sea voyage. Even with my little knowledge of sailing I can appreciate how epic this feat was. This is the second sailing related book I've read in a row, and while my last book was modern, both voyages faced remarkably similar challenges. Storms, pirates, repairs, improvisations, loneliness, navigational hurdles, and even the dangers of coral reefs. And yet in Slocum's case, the challenges are complicated by both lack of technology and crew.

How does one keep a ship on course and yet sleep? How does one wake in the middle of the ocean and be confident of their position without GPS or at least an accurate chronometer? When storms overpower the vessel, how does one manipulate the sails solo? How does one protect oneself from hostile natives and pirates?

Overcoming any of these challenges would be impressive; Slocum navigated them all. What he lacked in technology and hands he made up for with skill and luck.

Listening to Slocum's journey was a pleasure. Like an episode out of HGTV, Slocum's adventure starts by restoring a washed up vessel by hand. We're then taken on a 3+ year cruise that crisscrosses the globe.

During this journey we experience gales and illness, natives and pirates, successes and failures. It's a great read listen. If I could offer one criticism though, it would be that Slocum's tone is just a bit too up beat. Yes he faced challenges, but he can't help but brush them aside. Like I said, he'd fit in with the Instagram crowd. I want to hear more details of the hard won lessons.

Of course it's his story, and his acts of courage and fortitude. If he wants to throw in a bit of humble bragging about his navigational skills, he's more than earned it. #thisboatsailsitself #2700mileswithoutsteering. And besides, I probably sound the same way when I recount trips I've taken. (Sure we missed the bus and spent 8 hours in a run down bus station, but I did get to try a new flavor of soda from the vending machine! It tasted terrible. But it was new! How insufferable. How me.)

The text for Slocum's book is out of copyright, so you can read it for free on There's also an impressive set of narrated Google Earth videos available on YouTube.

After listening to Slocum's account, I found this article detailing the search for details about Slocum's on-board clock. At the time, a sailor's clock would have been an essential navigational tool, and it's hard not to pause at Slocum's flippant selection. Think a modern day explorer opting to leave his GPS at home and instead bring along a novelty compass. I think the author has it right when he suggests Slocum's intention of bringing an inferior clock was to make a statement:

Modern technology was turning Slocum’s world around and turning him into a living anachronism. While he might have to give way to the new age, he was not going to concede without a statement. Slocum’s statement was his amazing voyage and the equipment he chose to take with him. He didn’t need an iron steamer, a polished crew or a fine timepiece to do what had never been done before.

There were many notable moments from Slocum's journey, but one that stayed with me was this exchange he had with a passing ship:

In the log for July 18 there is this entry: "Fine weather, wind south-southwest. Porpoises gamboling all about. The S.S. Olympia passed at 11:30 A.M., long. W. 34 degrees 50'."

"It lacks now three minutes of the half-hour," shouted the captain, as he gave me the longitude and the time. I admired the businesslike air of the Olympia; but I have the feeling still that the captain was just a little too precise in his reckoning. That may be all well enough, however, where there is plenty of sea-room. But over-confidence, I believe, was the cause of the disaster to the liner Atlantic, and many more like her. The captain knew too well where he was.

I love that: beware the trap of knowing your location too well. There's a life lesson in there, though I'm not exactly sure what it is.

Slocum was clearly an interesting fellow, and perhaps he was waging an unwinnable war against innovation. But there's no denying that he's an adventurer and story tell of the first order; a true model for all fellow Adventure / Storytellers to learn from and emulate.

Thursday, May 30, 2019

My Journey Through Plantar Fasciitis

Months ago I started feeling foot pain during and after running. Little did I know I was entering my first bout with plantar fasciitis. Here's how I've coped with this scourge.

Phase 1: Denial. I chalked the pain up to simple muscle soreness. Surely I was pushing my running to the next level and some discomfort was to be expected. To some degree, this held true. The pain in my right foot went away. But the pain in my left foot persisted. After the third run in a row where the pain was significant, I knew I had to do something.

Phase 2: More Denial. I decided I'd give myself two weeks off of running. Surely absolute rest would fix it. Never mind that I continued to stand at my desk and my left foot continued to hurt. Still, I felt like it was getting better. After two weeks of no running I went for a jog. Within minutes, the pain returned and I had to stop. That was quite a moment of despair.

Phase 3: Google can fix this, right? I finally had to face it: I was injured. I made an appointment with a podiatrist, and in the mean time did some Googling. Typically, using the Internet to self diagnose is a bad idea. I figured I'd end up deciding I had foot cancer or the the like. But in this case my symptoms matched plantar fasciitis to a tee. It wasn't just my left foot that hurt, but it was my left heel. And the fact that the pain was worse stepping out of bed in the morning made it even more obvious that I'd named my curse properly.

I'd only ever heard of plantar fasciitis in passing, and it was always hinted at as an unshakable condition. These discussions conjured up images of a chronic disease; the same way someone might say their crohn's is acting up.

Phase 4: Taking Action. While I was waiting for my doctor's appointment, I adopted two new strategies. One, I lowered my desk to a sitting position. Man, that provided some immediate relief. I also ordered a mat to stand on and will at some point re-introduce the my standing routine. I also did some research and found a series of suggested exercises to help runners recover from injury. I've lost the source of this list of exercises (sorry oh brilliant list maker!), but the routine was as follows:

The first time I finished this routine I noticed something remarkable: my heel pain was gone! I was cured! OK, not so fast. The pain did return. But it was a relief just to know that I could affect this pain in some way.

Pushing my luck a bit, I tried going through the routine and then immediately going for a run. I started my run with zero pain, and after a few minutes I felt a dull ache. Still, I was able to complete my run with minimal discomfort. This was another sign that my running life as I knew it wasn't over.

I can't recommend the above workout highly enough. I awkwardly made my way through the exercises the first few times, but with practice I could tell that I was gaining small measures of flexibility, balance and strength to perform the exercises with a modicum of grace. Sticking to the same exercises is almost certainly a recipe for disaster, but I'm telling you, the above sequence is a winner for runners.

Between the sitting and the exercises, I found that I could resume my running. At times the heel pain would disappear, and other times it would flair up. Whatever was going on wasn't a simple linear equation: I'd feel like I was on the mend, and then bam! I'd found myself with a burning pain in my left heel.

Phase 5: Seeing a Doctor. Given how clearly my symptoms matched the plantar fasciitis descriptions I'd found on the web, part of me felt it was excessive to see a doctor. I'm glad I ignored that instinct. The doctor took x-rays and confirmed my diagnosis. She also gave me the same set of stretches and advice I'd found all over the web. But it was comment that the plantar fasciitis would go away that I suppose I really needed to hear. I could make it go away faster by doing the stretches and exercises she prescribed; but just by the nature of the injury, it would eventually correct itself. What a relief to hear those words.

It's now been a few weeks since seeing the doctor and I've been keeping up with my stretches. I've also started wearing orthotics in my shoes and have plans to switch to more supportive shoes. My left heel pain still flares up occasionally, but I can tell that things are clearly improving. The pain in my heel no longer dominates my thoughts during my run. Every day it looks more and more like my journey with this bout of plantar fasciitis is coming to a close. (And yes, I realize that posting this before completely recovered is tempting the evil eye; but I'm willing to take that shot.)

If you're struck down with plantar fasciitis don't panic. Own it. Do the stretches. Follow the conventional wisdom. You'll get better.

Update: Sue also adds this advice: I also recommend getting the night brace, if it comes back. It is amazing how quickly that augments the exercises. I speak from much experience. I fought the brace for a long time but oh my goodness it really does help.. Thanks Sue!

Wednesday, May 29, 2019

From Subject to Photographer

While visiting a playground this last weekend, Dovid mentioned that he enjoyed watching the birds. Well I explained, if you like watching them you're going to love photographing them. I handed him my DSLR with 300mm lens, showed him where the viewfinder, zoom and shutter button were and sent him on his way.

After watching Dovid shoot photos for a while, Tzipora wanted in on the action and I gave her the same quick tutorial.

For the rest of the day, including our trip to Castle Island, the kids took turns shooting with my DSLR.

Below are some examples of their work. I couldn't be more proud of them.

You can bet that our next trip is going to include even more photography. Perhaps a trip to the zoo is in order to practice photographing animals? Or maybe we tackle some photo challenges? Is it too early to teach them the rule of thirds? Oh, this is going to be fun!


Related Posts with Thumbnails