Sharing Terminal kill-ring with system clipboard on OS X

I managed to get vim in the terminal using the system clipboard by using a version compiled with +clipboard and using set clipboard=unnamed in .vimrc. But I wanted to go one further and have the last entry in my emacs-like kill-ring in bash go to the system clipboard too. So that when I hit Ctrl-k on the commandline I can Cmd-v that text into my text editor (or anywhere). Turns out this is pretty tricky.

The best solution I have so far is courtesy of user3439894 on the Apple Stack Exchange. It requires me to use Ctrl-Shift-k to kill instead of Ctrl-k but otherwise does what I want pretty well. You can find the gory details at https://apple.stackexchange.com/a/336361/301884.

Subsetting Fonts

On pennydreadfulmagic.com we use a bunch of unicode symbols for everything from pagination (←→) to tagging external links (↑) to indicating that a specific card has a bug (🐞).

Lots of these symbols are present in the glyphs of our main body text font. But some are not. These rely on the system of the viewer to display. Sometimes they look ugly and sometimes they aren’t present at all and get the ugly square box treatment.

To work around this I want to supply a font that provides versions of the glyphs that aren’t present in the base font. But something fonts like Symbola that provide complete coverage of unicode start at about 1.5MB and go up. That’s a high price to pay for a handful of symbols!

One solution is font subsetting. You can make a version of a font that only contains the symbols you are going to use. It will be much smaller. Our subsetted version of Symbola is more like 15KB as an inline woff in the CSS file. A big saving.

You can subset fonts online very simply with the super useful Transfonter.

Speeding up pystache

This unfortunately won’t do much good as a PR because the project seems to be abandoned but you can get really big speedups in pystache by caching templates and (particularly) parsed templates. Especially if you are using a lot of partials.

It looks something like this:

# Subclass pystache.Renderer to provide our custom caching versions of pystache classes for performance reasons.
class CachedRenderer(pystache.Renderer):
    def _make_loader(self) -> pystache.loader.Loader:
        return CachedLoader(file_encoding=self.file_encoding, extension=self.file_extension, to_unicode=self.str, search_dirs=self.search_dirs)

    def _make_render_engine(self) -> pystache.renderengine.RenderEngine:
        resolve_context = self._make_resolve_context()
        resolve_partial = self._make_resolve_partial()
        engine = CachedRenderEngine(literal=self._to_unicode_hard, escape=self._escape_to_unicode, resolve_context=resolve_context, resolve_partial=resolve_partial, to_str=self.str_coerce)
        return engine

# A custom loader that acts exactly as the default loader but only loads a given file once to speed up repeated use of partials.
# This will stop us loading record.mustache from disk 16,000 times on /cards/ for example.
class CachedLoader(pystache.loader.Loader):
    def __init__(self, file_encoding: Optional[str] = None, extension: Optional[Union[str, bool]] = None, to_unicode: Optional[StringConverterFunction] = None, search_dirs: Optional[List[str]] = None) -> None:
        super().__init__(file_encoding, extension, to_unicode, search_dirs)
        self.templates: Dict[str, str] = {}

    def read(self, path: str, encoding: Optional[str] = None) -> str:
        if self.templates.get(path) is None:
            # look in redis using modified date on filesystem of path
            self.templates[path] = super().read(path, encoding)
            # write to redis
        return self.templates[path]

# If you have already parsed a template, don't parse it again.
class CachedRenderEngine(pystache.renderengine.RenderEngine):
    # pylint: disable=too-many-arguments
    def __init__(self, literal: StringConverterFunction = None, escape: StringConverterFunction = None, resolve_context: Optional[Callable[[ContextStack, str], str]] = None, resolve_partial: Optional[StringConverterFunction] = None, to_str: Optional[Callable[[object], str]] = None) -> None:
        super().__init__(literal, escape, resolve_context, resolve_partial, to_str)
        self.parsed_templates: Dict[str, pystache.parsed.ParsedTemplate] = {}

    def render(self, template: str, context_stack: ContextStack, delimiters: Optional[Tuple[str, str]] = None) -> str:
        if self.parsed_templates.get(template) is None:
            # look in redis
            self.parsed_templates[template] = pystache.parser.parse(template, delimiters)
            # store in redis
        return self.parsed_templates[template].render(self, context_stack)

Blossom Algorithm in PHP

Following the Swiss Pairings Algorithm I wrote in python using weighted maximum matching I ported the blossom algorithm code to PHP.

This is a direct conversion of Joris van Rantwijk’s python code with the same tests and the same output.

The algorithm is taken from “Efficient Algorithms for Finding Maximum Matching in Graphs” by Zvi Galil, ACM Computing Surveys, 1986. It is based on the “blossom” method for finding augmenting paths and the “primal-dual” method for finding a matching of maximum weight, both due to Jack Edmonds.

Some ideas came from “Implementation of algorithms for maximum matching on non-bipartite graphs” by H.J. Gabow, Standford Ph.D. thesis, 1973.

A C program for maximum weight matching by Ed Rothberg was used extensively to validate this new code.

https://github.com/bakert/blossom-php/blob/master/mwmatching.php

Disabling a WordPress Plugin Without Access to wp-admin

I had an SSL plugin enabled making local access without SSL problematic. My glorious hack around this (only tested in bash):

mysql -N -B {db_name} -e "SELECT option_value FROM wp_options WHERE option_name = 'active_plugins';" | php -R '$a = unserialize($argn); $a = array_values(array_diff($a, ["{plugin_to_remove}"])); print("UPDATE wp_options SET option_value = '"'"'" . serialize($a)) . "'"'"' WHERE option_name = '"'"'active_plugins'"'"';\n";' | mysql -vv {db_name}

Replace {db_name} with the database name and {plugin_to_remove} with the plugin string, something like “really-simple-ssl/rlrsssl-really-simple-ssl.php”. You may need -u and -p options in the two mysql commands. In my local setup I lazily auto-login as mysql root.

Adding a property to a third party class in TypeScript

I’ve been on the TypeScript gitter and this is the best we’ve come up with:

import * as express from 'express';
import * as http from 'http';
import * as WebSocket from 'ws';

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

// ******* THIS IS THE IMPORTANT BIT  ********
interface WebSocketWithStatus extends WebSocket {
  isAlive?: boolean;
}

function heartbeat(this: WebSocketWithStatus) {
  this.isAlive = true;
}

function onConnection(ws: WebSocketWithStatus) {
  ws.isAlive = true;
  ws.on('pong', heartbeat);
}

wss.on('connection', onConnection);

Beats (ws as any).isAlve but it feels like there should be something better.

Resist, My People, Resist Them

Resist, my people, resist them.
In Jerusalem, I dressed my wounds and breathed my sorrows
And carried the soul in my palm
For an Arab Palestine.
I will not succumb to the “peaceful solution,”
Never lower my flags
Until I evict them from my land.
I cast them aside for a coming time.
Resist, my people, resist them.
Resist the settler’s robbery
And follow the caravan of martyrs.
Shred the disgraceful constitution
Which imposed degradation and humiliation
And deterred us from restoring justice.
They burned blameless children;
As for Hadil, they sniped her in public,
Killed her in broad daylight.
Resist, my people, resist them.
Resist the colonialist’s onslaught.
Pay no mind to his agents among us
Who chain us with the peaceful illusion.
Do not fear doubtful tongues;
The truth in your heart is stronger,
As long as you resist in a land
That has lived through raids and victory.
So Ali called from his grave:
Resist, my rebellious people.
Write me as prose on the agarwood;
My remains have you as a response.
Resist, my people, resist them.
Resist, my people, resist them.

https://www.aljazeera.com/news/2018/05/arabs-jaii-israel-convicts-palestinian-poem-180503161402330.html

An Omelette

One day young captain Jonathan,
he was eighteen at the time,
Captured a Pelican
On an island in the Far East
In the morning,
This Pelican
of Jonathan’s
Laid a white egg
and out of it came
a Pelican
Astonishingly like the first.
And this second Pelican
laid in its turn
A white egg,
from which came inevitably
Another
who did the same again.
This sort of thing can go on
A very long time,
if you don’t make an omelette.

Robert Desnos: Chantefleurs, Chantefables
Translated from the French by Elizabeth McGovern

Offline Maps on Apple Watch without Phone

(This is not a paid-for/affiliate link post, I just had great difficulty tracking down a working solution for this so I thought I’d post the answer now I’ve found it!)

I tried a lot of things before finding the WorkOutDoors App. It lets you save a segment of a map (of any size) to your phone in complete zoomable detail and will even show a track of where you have been and a persistent compass pointing back to your start point. $2.99 on the App Store. Went from wanting to run in a straight line and back in unfamiliar places to feeling confident to go wherever after one run with it.

Some of the things I tried that didn’t work even remotely well enough: maps.me (app never appeared on phone), Sygic (one of many apps that wants you to plan a route on your phone and then download that and only that to the watch – didn’t even manage to achieve that), Yandex (seemed like it might work but only has Russian cities), ViewRanger, Apple Maps after scanning around the map a bit while online so it’s in memory (this was not totally useless but you can’t zoom).

Swiss Pairing Algorithm

I needed a Swiss Pairing algorithm for a rewrite of the pairings code in gatherling.com. The existing code has a nasty habit of awarding the bye more than once to the same player or awarding more than one bye when things get tricky due to draws or drops or other complications.

A really good approach to the problem is described by Mark “Spike” Liu in Swiss Pairing: Leaguevine’s New Algorithm.

Some googling led me to Joris van Rantwijk’s Maximum Weighted Matching. This uses Edmonds’s Blossom algorithm. It takes a list of (index, index, weight) as inputs for every possible pairing and produces the highest scoring graph possible.

If you want to pair based on player/team skill things can get more complicated but I came up with a fairly simple weighting calculation that considers the following:

  • Playing the same player twice
  • Getting the bye twice
  • Someone who is not the lowest scoring player who hasn’t had the bye getting the bye
  • Getting paired down
  • Pairing down better-performing players being much less desirable than pairing down worse-performing players

but not anything about the players/teams themselves.

def weight(highest_points, p1, p2):
    w = 0

    # A pairing where the participants have not played each other as many times as they have played at least one other participant outscore all pairings where the participants have played the most times.
    # This will stave off re-pairs and second byes for as long as possible, and then re-re-pairs and third byes, and so on …
    counter = Counter(p1['opponents'])
    if len(counter) > 0 and counter.get(p2['id'], sys.maxsize) < max(counter.values()):
        w += quality(highest_points, highest_points) + 1

    # Determine a score for the quality of this pairing based on the points of the higher scoring participant of the two (importance) and how close the two participant's records are.
    best = max(p1['points'], p2['points'])
    worst = min(p1['points'], p2['points'])
    spread = best - worst
    closeness = highest_points - spread
    importance = best
    w += quality(importance, closeness)

    return w

# importance and closeness are values in the range 0..highest_points
def quality(importance, closeness):
    # We add one to these values to avoid sometimes multiplying by zero and losing information.
    return (importance + 1 ** 2) * (closeness + 1 ** 2)

You can get the full working python code with a simple 8-player example at https://github.com/bakert/swiss