Making a Chrome Extension

It's easy to make a chrome extension. The first thing you need is a manifest, describing the extension and defining permissions.

{
  "manifest_version": 2,

  "name": "test",
  "description": "a test extension",
  "version": "1.0",

  "browser_action": {
    "default_popup": "popup.html"
  },
  "permissions": [
    "activeTab"
  ]
}

As far as I can tell, this is basically the minimum that will work. The manifest version, name, description, and version are all required. Next, you need either a browser action or a page action. A browser action is one that is always available. When you click on the extension's icon, a popup appears, displaying popup.html. Finally, the permissions array lists what the extension is allowed to do. In this case, I gave it permission to ask the browser for information about the active tab.

Here's popup.html:
<html>
<div id="tab">test</div>

<script src="popup.js"></script>
</html>
All it does is define a div and load a script. Here is popup.js:
chrome.tabs.query({active:true},function(tab){
    url = tab[0].url;
    console.log(url);
    document.getElementById('tab').textContent = url;
});
All this does is asynchronously ask query the browser, filtering for active tab(s). The callback function takes a list of tabs. In this case, the list has only one element. It then finds the tag created in popup.html and sets the content to the active tab url. When you're debugging extensions, you can get access to the regular chrome developer tools for the popup by right clicking on the icon and clicking "inspect popup". »


Jewelry Box

Over Thanksgiving, Matt and I made a jewelry box. It's 5-3/8" by 10-3/4", made of walnut and oak with a hinged lid and finger joint corners. Here's how we did it.



Below are the basic plans.



We started by using our new planer to thin some 1" nominal oak and walnut boards down to 3/8".



Using the table saw, we ripped them to their final widths of 3-3/8" for the front and sides or 3" for the back.



We cut them to their final lengths and then got to work on the finger joints. We used a clever jig to make accurate finger joints. You can see how it works in this video It requires a dado stack and an accurately cut square peg. It took us some time to lock in the precise width of the dado stack by adding and removing shims.



We cut the lid to size using the table saw for the basic shape. We used a jig saw to create the tab. We then cut a notch into the front piece to make way for the tab. For the bottom, we cut a 1/8" thick piece of oak to 10" by 5-3/4" and cut slots in the front and back panels for the bottom. Then we made sure everything fit.



We sanded all the panels with 80 and 200 grit sand paper, then glued it up and clamped it in place.



We gave it a final sanding and then rubbed some finishing wax into the wood to protect it.


»


Router Based Planer

Matt and I have a tradition of doing woodworking projects when we're together at our parents' house. We don't have a thickness planer, so we decided to make one based on this YouTube video.



It's a jig for a router that allows it to slide in either direction, but constrains it to a consistent height. The base is made of a melamine shelf and two pieces of 1" aluminum angle. The sled is a piece of plywood with a slot cut in it, some guides to keep it centered on the base, two sides on top to guide the router, and stops on either end to prevent the router from cutting too far.



This thing is easy but tedious to use. You clamp a board to the base, set the height of the router, and run it back and forth over the wood. We limited our cuts to about 1/8" per pass. If you stick with that rule, you'll probably have to do several passes.



We successfully planed pine, oak, and walnut boards from 1" nominal thickness to 3/8" with no problem. The router bit leaves some lines in the wood, but these can easily be sanded away. Other than those lines, the results seemed perfect. The process does take a long time and it isn't pleasant time either, since you're holding a screaming router in your hands the whole time.

»


The Hot Hand Fallacy?

I was reading the Wikipedia article about the Hot Hand Fallacy, and I decided to try a little bit of statistical analysis myself. I've always found the idea of a player being hot or cold a bit suspicious. On one hand, it kind of feels right. Sometimes a player just has it, right? And there's no reason events in a game need to be considered completely independent. On the other hand, maybe the phenomenon can be explained by our natural inclination to look for patterns.

I chose baseball to look at. I downloaded the 2015 event database from Retrosheet, and wrote some code to calculate autocorrelation functions. I generated a long list of every plate appearance outcome for the whole season. The list is grouped by player and in order for each player. I labeled all hits as 1 and all outs as 0. I then computed the autocorrelation of this sequence.

I inserted the black line to guide the eye. As you can see, there is some correlation between successful plate appearances. I think this suggests that the time-scale for hotness or coldness is about ten plate appearances. Two games, or so. Also, it isn't a huge effect. It looks like 5% or something.

import numpy as np
import matplotlib.pyplot as plt
import os
from compiler.ast import flatten

# gets only the event lines from a file
def getEvents(filename):
    fp = open(filename)

    # splits line into parts
    lines = map(lambda line: line.split(","),fp)

    # filters for only play events
    events = filter(lambda line: line[0] == "play", lines)
    return events

# gets a list of players involved in a list of events
def getPlayers(events):
    names = map(lambda event: event[3], events)
    players = list(set(names))
    return players

# filters for only plays involving a certain hitter
def getEventsBy(events, name):
    return filter(lambda event: (event[3] == name), events)

# maps hits to 1 and outs to 0
def maskHits(events):
    return map(lambda event: 1 if ((event[6][0] == "S") or (event[6][0] == "D") or (event[6][0] == "T") or (event[6][0] == "H")) else 0, events)

# replaces all lines containing a hit with a 1 and all containing and out with a 0
def getPlayerSeries(events, name):
    return maskHits(getEventsBy(events, name))

# concatenates all the player series for a team
def getPlayerSeriesForTeam(filename):
    events = getEvents(filename)
    players = getPlayers(events)
    series = map(lambda player: getPlayerSeries(events, player), players)
    return flatten(series)

# concatenates the team series for the whole league
files = os.listdir('./teams')
total_series = map(lambda file: getPlayerSeriesForTeam('./teams/' + file), files)
total_series_flat = flatten(total_series)
print len(total_series_flat)

corr = np.correlate(np.concatenate((total_series_flat,total_series_flat[:100])), total_series_flat, mode='valid')

print corr
plt.plot(corr)
plt.plot([0, 100], [9900, 9900], 'k-')
plt.title("Correlation Between Sequential Plate Appearances, MLB 2015 ")
plt.xlabel(r'$\Delta$ PA')
plt.ylabel('autocorrelation')
plt.show()
»


Migrating from Wordpress on NearlyFreeSpeech to Jekyll

I messed up my Wordpress installation and I don't know how to fix it. It was hosted on nearlyfreespeech.net , but their version of the wordpress command line client seems to be either broken or too old to work with an up-to-date Wordpress install. either way, I don't have access to the wp-cli. So, I decided to try something else

I read good things about Jekyll, so I decided to try it. There's a lot there, but one sticking point was migrating the database into Jekyll. I don't think you can access NFS's mysql server from outside, so I downloaded the data using phpMyAdmin, created a database, imported the data with source data.sql, and ran the Jekyll import function.

ruby -rubygems -e 'require "jekyll-import";
    JekyllImport::Importers::WordPress.run({
      "dbname"   => "benwiener",
      "user"     => "username",
      "password" => "password",
      "host"     => "localhost",
      "table_prefix"   => "wp_"
    })'
»