Bemoaning the AI copy assistant

I've been using GitHub Copilot for a few about half a year now, and it feels like an amazing piece of magic. Not only does it seem to do most of the rote coding for me but it also gives me a new sense for what is actually rote.

Since I edit the content of this blog, and just about everything else I write, in VSCode and already use Copilot for work, it tries to suggest things everywhere.

Even, as I type this, it keeps suggesting things. Often, the things it suggests are so close to what I want to say that it's tempting to hit the tab key but it's voice is not quite my own.

With code, the voice hardly matters and Copilot is quite good at knowing what I want to say, of course, it's well constrained. With prose, not so much. Sure, what it suggests would be fine but that's not the point.

A proper Gimlet, sans corn syrup

A Gimlet is a refreshing cocktail with a subtle but distinct flavor profile. It can be quite tasty but is very hard to get right without accepting an awful lot of high fructose corn syrup. I tend to avoid high fructose corn syrup, so I rarely make a proper Gimlet, but I've been experimenting with syrups over the years and think I've struck on a pretty good alternative.

The Classic Gimlet

The starting point for a Gimlet is a simple mix of gin and Rose's Lime Juice. Sadly, Rose's is mostly water, high fructose corn syrup, and a little bit of flavoring. It gives the right taste (tuotologically) but isn't something I feel good about drinking.

Gimlet

  • 2 oz Gin

  • 1 oz Rose's Lime Juice

Shake with ice and serve in a Nick and Nora glass.

The Gin Sour

Commonly, one will find recipes calling for fresh lime juice an simple syrup. While a good drink, the flavor profile is quite different from a true Gimlet.

Gin Sour

  • 2 oz Gin

  • 3/4 oz Lime Juice

  • 3/4 oz Simple Syrup

Shake with ice and serve in a Nick and Nora glass. Garnish with a lime slice.

Roll Your Own

From here, the path forward is to start trying to make your own lime syrup. The first recipes that I tried were based on a simple syrup infused with lime zest. This works well enough but the flavor is a bit too subtle and not quite right.

From there, I largely set aside the matter until I came across a recipe trying to resurrect the original Rose's recipe on Reddit. To my taste, the recipe is much to tart, more like a Sour Patch Kid than something I want to use in drinks. That said, the flavor profile was in the right direction.

I played with the ratios and ended up with something that tastes really good to my taste.

Key Lime Syrup

  • 3/4 cup Water

  • 1 1/2 cup white Sugar

  • 1 Tbsp Citric Acid

  • Zest of 11 key limes

  • Juice of 11 key limes

Put the sugar, citric acid, and key lime zest in a sauce pan. Add the water and bring to a gentle boil. Stir until the sugar is dissolved. Remove from heat, add the lime juice, cover, and let cool to room temperature. Strain through a fine strainer (I use a nut milk bag) and bottle.

The Homemade Gimlet

  • 2 oz Gin

  • 1 oz Key Lime Syrup

Shake with ice and serve in a Nick and Nora glass.

Delicious.

Uncut Jewel

Once a year, I take a month off from Caffeine and Alcohol (sometimes I'll throw in something else like high fructose corn syrup). It was fairly arbitrary for a number of years but now, having learned it's kind of a thing, I tend to take my temperance in January. This time around, I've moved things up a few months and am abstaining in October.

Giving up booze, even temporarily, doesn't mean that I want to give up cocktails. Turns out, however, it's really hard to make something without alcohol that doesn't end up tasting like juice or flavored water. Seedlip is meant for this purpose and helps some but tends to fall pretty easily into the juice or flavored water trap.

Through a mix of experimenting, Seedlip recipe ideas, Aviary Cocktail Book inspiration, staring at my liquor shelf, and starting at my fridge, I've had a modicum of success. I seem to have hit on a formula that works well stirred with ice and served Up:

A Non-Alcoholic Up formula

  • 1 oz Seedlip (Spice 94 or Garden 108)

  • 1/2 oz Verjus Blanc (Fusion Napa Valley)

  • 1/2 oz Verjus Rouge (Fusion Napa Valley)

  • 1/2 oz Cranberry Juice

  • 1/2 oz Syrup (Simple, Demerara, etc.)

  • 1-2 dash(es) bitters

Gomme Syrup and Garden 108 seem to work well together but I think the best that I've hit on so far is what I'm calling an Uncut Jewel:

Uncut Jewel and its ingredients

Uncut Jewel recipe

  • 1 oz Seedlip Spice 94

  • 1/2 oz Verjus Blanc (Fusion Napa Valley)

  • 1/2 oz Verjus Rouge (Fusion Napa Valley)

  • 1/2 oz Cranberry Juice

  • 1/2 oz Maple Syrup (Grade A Amber Color, Rich Taste)

  • 1 dash Salted Cacao Bitters (Workhorse Rye + Dandelion Chocolate)

Stir with ice, serve up, and garnish with a Maraschino cherry.

Notes

The drink leads with a note of allspice before taking on dominant notes of fruit and nuts and finally closes with a hint of cocoa. Overall, it's well balanced, sippable, and fairly complex, without assaulting the palette.

An Arbitrary map from SQL with Go

I've been writing a lot of Go lately and finding it a pleasant balance of simplicity, power, functionality, and ecosystem support. In a lot of cases, I am finding the guarantees afforded by type safety to be really nice but, occasionally, the strict requirements can make some easy things much harder than I want them to be.

Recently, I found myself wanting to test the behavior of some code the hit a SQL database. Specifically, I wanted to check the results of a handful of queries with varied columns and column types. With Python, I'd approach this with SQLAlchemy, and turn the result into a list of dicts.

def rows_to_dicts(rows):
    """Covert a SQLAlchemy RowProxy into a list of dicts."""
    return [dict(r) for r in rows]

From here, it's pretty straightforward to assert the result matches expectations. If you're using pytest, you'll also get really clear details on where the results aren't what you expect. If you don't have the expected columns or column types spot on, you're assertion will be off but you won't hit any underlying errors at this point of your testing.

Go, on the other hand doesn't have quite as easy an option. The crux of the problem is that the only way to get a result row out of a sql query is via (*Rows) Scan, which demands you know something about the structure of the result before you query. Luckily Scan is happy to read anything into a *string as long as you're asking for the right number of values so we can write an equivalent function to the python list comprehension.

import (
    "database/sql"
)

func RowsToMaps(rows *sql.Rows) ([]map[string]string, error) {
    columns, err := rows.Columns()
    if err != nil {
        return nil, err
    }
    columnCount := len(columns)

    cursor := make([]interface{}, columnCount)
    for i := 0; i < columnCount; i++ {
        var columnValue string
        cursor[i] = &columnValue
    }

    var resultMaps []map[string]string
    for rows.Next() {
        err := rows.Scan(cursor...)
        if err != nil {
            return resultMaps, err
        }
        rowMap := make(map[string]string, columnCount)
        for i, columnPtr := range cursor {
            key := columns[i]
            var columnStr string
            if columnStrPtr := columnPtr.(*string); columnStrPtr != nil {
                columnStr = *columnStrPtr
            }
            rowMap[key] = columnStr
        }
        resultMaps = append(resultMaps, rowMap)
    }
    if err := rows.Err(); err != nil {
        return resultMaps, err
    }
    return resultMaps, nil
}

This, much like the Python above, gives us a list of maps of column name to column value, with the minor caveats that all values are strings and NULL values become empty strings. I found it a useful chunk of code, so I thought I'd throw it up.

Sure, it's more verbose but sometimes that's the price we pay for dealing with dynamic results in a staticly typed language. There are other prices paid in the other direction.

Grenadine

In my ongoing quest to make delicious alcoholic beverages, I have increasingly found myself digging into my ingredients. Syrups, as a class of ingredient, have received a decent amount of my attention. As an aside, if you're buying simple syrup, you are doing a lot of things wrong. In my experience, it is decidedly tricky to find decent grenadine, where decent is defined as being made with real pomegranate and without high fructose corn syrup or food coloring. So, I've started to make my own:

Grenadine

A pomegranate syrup that adds a sweet tartness to drinks and a distinctive red color. Notable in small quantities in a great many drinks and also as the second ingredient in a Shirley Temple, a drink the actress was apparently never fond of.

Ingredients

  • 1 cup fresh Pomegranate Juice (~2 large pomegranates)

  • 1 oz Pomegranate Molasses

  • 1 1/2 cup White Sugar

  • 1/2 tsp Orange Blossom Water

  • 1 oz over-proof grain neutral spirit (Everclear or vodka)

Read more…

Slowcooker Yogurt

Some jars of homemade yogurt

I have a 14 month old daughter, a wife that likes yogurt with granola, and I kind of like the stuff too. Needless to say, we go through a lot of yogurt in my house. Specifically, we go through a lot of plain, whole milk, Greek yogurt.

We were recently visiting my wife's aunt and uncle (my daughter's graunt and gruncle), and we had yogurt most mornings. They use an EasiYo to make their yogurt, which piqued my curiosity.

Fancy yogurt is pretty expensive at the store, upwards of $7 or $8 per 32oz container. Yogurt is just fermented milk and I've fermented plenty of things before. I should be able to make yogurt, right?

So, how about EasiYo? Turns out it's not that much cheaper.

We can do better, let's ask the Internet.

Turns out it's pretty straightforward; I just finished our second batch yesterday. It also turns out to be really good, and it's less than $2 per 32oz (milk choice depending).

Read more…

Let's Encrypt on App Engine

UPDATE: As of September, 2017, Google App Engine will manage SSL certificates for you.


Let's Encrypt is a fantastically convenient way to get SSL certificates for your website without paying a bunch of money or resorting to a self-signed certificate. It's also pretty easy to set up.

Easy as it is to set up, the instructions don't really explain much about setup for App Engine. It turns out to be pretty straightforward.

Read more…

Internet Time Now script

On account of being mentioned by Reply All, I've been listening to back episodes of [TLDR]. Listening to #15 - Internet Time caught my attention and made me aware of Swatch Internet Time. It's kind of impractical but also kind of fun, especially as I've been a little annoyed at recording times across timezones for something meant to persist, like this blog.

For fun, I whipped up a quick python implementation:

import datetime
import decimal

def decimal_time(ts):
    mus_ts = (ts.hour * 3600 + ts.minute * 60 + ts.second) * 1000000 + ts.microsecond
    mus_day = 24 * 3600 * 1000000
    dec_time = decimal.Decimal(mus_ts) / decimal.Decimal(mus_day)
    return dec_time * 1000

def internet_time_now(precision=0):
    precision = int(max(0, min(25, precision)))
    precision = 0 if precision < 1 else int(precision)
    format_len = 3 if precision < 1 else 4 + precision
    format_str = '@{{:0{l:d}.0{p:d}f}}'.format(l=format_len, p=precision)
    it_utc_p1 = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
    return format_str.format(decimal_time(it_utc_p1))

Or, if you don't care about precision:

import datetime

def decimal_time(ts):
    s_ts = ts.hour * 3600 + ts.minute * 60 + ts.second
    s_day = 24 * 3600
    return int(1000 * s_ts / s_day)

def internet_time_now():
    it_utc_p1 = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
    return '@{:03d}'.format(decimal_time(it_utc_p1))

Fixing Nikola Footnote Locations

Personally, I prefer to intersperse my footnote declarations with the text that is being footnoted when writing my. For example:[1]

I might want to write something[#]_ where there's a footnote there.

.. [#] I put the footnote definition here.

And then I continue on with the rest of my writing.

Wherever they are declared, I prefer to have all of my footnotes appear at the end of my posts. By default, Nikola puts the footnotes in wherever they are declared. A simple snippet of javascript can be used to fix the locations of footnotes:

$(document).ready(function() {
    $('.footnote').each(function(i, el) {
        $(el).appendTo(
            $(el).closest('.entry-content,.entry-summary'));
    });
});

Simply wrap in a <script> tag and include in the BODY_END section of conf.py or add it to your theme.

Will O' The Wisp

Continuing my earlier work in the realm of mixology, I would like to present my second cocktail invention. The invention of this cocktail is the result of playing around with gin, Chartreuse, St. Germain, and various other liqueurs in an attempt to make something tasty. This cocktail earns its name, Will O' The Wisp, from its faint, ghostly, green color.

Ingredients

  • 3/4 oz Green Chartreuse

  • 3/4 oz St. Germain

  • 3/4 oz White Vermouth

  • 1 dash Lavender Bitters

  • 3 oz Dry Gin

  • 1/4 oz Herbsaint or Absinth

Recipe

  1. Pour the Chartreuse, St. Germain, Vermouth, Bitters, and Gin into a cocktail shaker

  2. Pour the Herbsaint/Absinth into a chilled cocktail glass

  3. Swirl the cocktail glass, coating the sides, and pouring off any excess Herbsaint/Absinth

  4. Add ice to the cocktail shaker and shake

  5. Pour shaken cocktail into the prepared glass

Notes

The Herbsaint/Absinth can be skipped, though I don't recommend it. The Lavender Bitters are also optional but very highly recommended. I would recommend stirring this cocktail (instead of shaking) as the resulting beverage has a very different appearance.