Home

Bell Curves

January 12, 2018

No, not the racist bullshit artist’s book.

One thing I realized a few years ago is that for human attributes, bell curves are everywhere. The standard examples are things like height and weight, but why not, say, strength, or patience, or organizational skills, or empathy? Some people have more, some people have less, and there’s no particular reason to treat them as much different from (say) physical strength; something that we possess in different quantities, and something that we can improve within bounds, but that improvement itself takes work, and the bounds are real.

“Work” generalizes similarly. We can get tired of walking, of lifting, of thinking, of maintaining a pleasant attitude, and so on.

Another corollary is not knowing which parts of my own personal experience are typical and which are not.  If I’m in the middle of the curve for some particular relevant thing, typical, if I am off to one end or the other, not so typical.

More twitter tomfoolery

December 16, 2017

I wrote a Go program to install blocks from a file of Twitter IDs. It’s not on github yet because my development sandbox looks more like a development catbox, and I can’t clean it up too much because the program’s running right now and Twitter’s rate limited so it’ll be a while (at 5 blocks per second, about 10 days). Recall that my goal is to completely remove fascists and griefers from my Twitter feed, and from any conversation that I happen to be in — they shouldn’t even notice the opportunity to respond, never mind wasting anyone’s time with their crap.

At least as important as the program is the list of IDs to block.
It’s 4 million lines long, sorted from most-to-least-desirable-to-block order, so this is the only way to share it. I did some by-hand sampling, and the first 10% really are notably more obnoxious than the last 10%, so I may not run this all the way to completion.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/BurntSushi/toml"
	"github.com/ChimeraCoder/anaconda"
)

var digits = regexp.MustCompile("[0-9]+")
var runtime = time.Now().Format(time.RFC3339)

type ConsumerAndAppKeysAndSecrets struct {
	ConKey, ConSecret, AppToken, AppSecret string
}

var caksFile = ".twitter/ids"

/* The .twitter/ids file contains four lines with string values
   obtained from the twitter developer api.

ConKey = "..."
ConSecret = "..."
AppToken = "..."
AppSecret = "..."

   For an App token and secret, you need to create an app here: https://apps.twitter.com/app/new
   This will then give you the option to create a consumer key and secret.
   (This useful information cribbed from
   https://stackoverflow.com/questions/1808855/getting-new-twitter-api-consumer-and-secret-keys )

*/

func main() {
	caks := &ConsumerAndAppKeysAndSecrets{}
	blob, err := ioutil.ReadFile(caksFile)
	if err != nil {
		fmt.Printf("There was an error opening or reading file %s: %v\n", caksFile, err)
		os.Exit(1)
		return
	}

	err = toml.Unmarshal(blob, caks)
	if err != nil {
		fmt.Printf("There was an error unmarshalling contents of %s: %v\n", caksFile, err)
		os.Exit(1)
		return
	}

	anaconda.SetConsumerKey(caks.ConKey)
	anaconda.SetConsumerSecret(caks.ConSecret)
	api := anaconda.NewTwitterApi(caks.AppToken, caks.AppSecret)
	fmt.Println("Credentials = ", *api.Credentials)

	a := os.Args
	if len(a)  0 && i%1000 == 0 {
			flush(users, i)
			users = users[:0]
		}
		user, err := api.BlockUserId(int64(u), url.Values{})
		if err != nil {
			errst := err.Error()
			if !strings.Contains(errst, "User not found.") {
				fmt.Printf("i=%d, u=%d, err=%v\n", i, u, err)
				flush(users, i)
				os.Exit(1)
			}
			fmt.Print("X")
		} else {
			fmt.Print(".")
		}
		users = append(users, user)
	}

	flush(users, len(wlids))

}

type tomlWantsStruct struct {
	users []anaconda.User
}

func flush(users []anaconda.User, ending int) {
	buf := new(bytes.Buffer)
	if err := json.NewEncoder(buf).Encode(users); err != nil {
		fmt.Printf("There was an error encoding users: %v\n", err)
		os.Exit(1)
	}
	fname := fmt.Sprintf("Blocked-%s-%08d", runtime, ending)
	err := ioutil.WriteFile(fname, buf.Bytes(), 0666)
	if err != nil {
		fmt.Printf("There was an error writing %v: %v\n", fname, err)
		os.Exit(1)
	}
}

func readFileAsUint64s(filename string) (uids []uint64, err error) {
	var b []byte
	b, err = ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	bids := bytes.Split(b, []byte("\n"))
	uids = make([]uint64, 0)
	for i, bid := range bids {
		s := digits.FindString(string(bid))
		if s == "" {
			continue
		}
		var uid uint64
		uid, err = strconv.ParseUint(s, 10, 64)
		if err != nil {
			fmt.Printf("Failure to parse line %d of %s\n", i, filename)
			return
		}
		uids = append(uids, uid)
	}
	return
}

Back in 1997 the New England Lily Society (then, the New England Regional Lily Group) hosted the annual meeting and show of the North American Lily Society in Burlington, Massachusetts. Among other things, “we” (not me, but other then-members) designed and built a huge number of stem holders, which we have used for years ever since in our own shows. We’re hosting the show again in 2019, and may need more stem holders. I have a few (because otherwise they would have been thrown out as excess), and I thought I shold record and publish their dimensions. It turns out that for some of the larger trumpet-oriental crosses a larger base is needed, and the largest stems also inhale so much water (for respiration and/or bud opening) that a larger reservoir is necessary. But for most lilies these work great.

The stem holder has a wooden base and a removable stoppered PVC insert. The PVC is thin-walled (2mm), outer diameter appears to be 1-and-5/16 inches, length 11-and-5/8 inches. The base is stepped, with a 5-and-half inch square by 1-and-half-inch high bottom part (clearly cut from US “2-by-6”) and a 3-and-a-half by three-quarters top part (clearly cut from US “1-by-4”). The base has a central hole for the PVC to wedge into (pretty tightly, too) that is 1-and-a-half inches deep by 1-and-5/16 inches diameter.

New England Lily Society stem holder.

New Twitter Algorithms

November 5, 2017

My Twitter block list got unmanageably large, and blocktogether.org was not even able to remove blocks at any sort of a reasonable rate to help me fix it. So, I used my employer’s mighty-fine search engine to look for any Go packages for the Twitter API, and found Anaconda.
Read the rest of this entry »

I guess people think I am tedious on this subject (people on Facebook think I am tedious on this subject), but bike share is very safe. By design, it can count the number of trips. We’re pretty good at counting deaths, too. In over 100 million trips there have been two deaths. (Death #1)

On “normal” bicycles, we’d expect to see 20 deaths in that many trips. In cars, we’d expect to see 9 deaths in that many trips. Instead, two. (As a sanity check on those rates, Canadian statistics are similar.)

Read the rest of this entry »

The last time I did this, I had figures through 2011.
Now I have 2012, 2014 and 2105 (2013 seems to be missing).
Now in a Google spreadsheet, so you can look at the numbers directly and poke at the links if you want to see where the numbers came from.

In words — since 2009, each gallon of gasoline or diesel is taxed between 40 and 50 cents too low even if the only purpose of that tax is to pay for road construction and maintenance. Any other taxes (carbon, pollution, noise, congestion, health care) would be on top of that. This also does not include the maintenance or construction that we ought to be doing; this is just what is spent.

Totaled over all the fuel sold, each year since 2009 the annual shortfall totals somewhere between 75 and 100 billion dollars.

Read the rest of this entry »

This is a (very) rare work-related entry. I mostly work on the compiler for a programming language named “Go”, and one of the problems we face is if and how we should add “generics” to a future version of Go. I can’t possibly summarize easily for a non-technical reader, but the TLDR version is (1) lots of other languages have generics (2) we’re pretty sure they’re useful (3) but they come with associated costs and complexity and we’re not sure they’re worth it. Also, “generics” is not just a single thing, there’s several semantic variants and several ways to implement them (for example, erased versus dictionary-passing versus template-stamping). So our team is collecting example stories of how Go generics would be useful in various situations — the jargon term for this is “use case”. Here’s mine:

Read the rest of this entry »