hortont · blog · code

QChat from 30,000 feet

2010.08.21 in code, personal, and qualcomm

Ed.: the majority of this was written on the plane from San Diego to JFK, and then emailed to the QChat client dev list (plus a few extras)

Almost exactly three months ago, I boarded a plane from Burlington to San Diego, solo, entirely unsure of what lay ahead. I'd been to San Diego before — for a few hours — and I'd heard only good things about it from people who live in the area, but beyond that, nothing. I knew that I would be interning at Qualcomm, writing embedded software — that was about all I knew beforehand; I had yet to be introduced to QChat, and I certainly hadn't met anyone I would be working with.

My second day (the first was consumed with intern orientation activities, and discovering that I had to walk 2 miles to work and back every day) was filled with introductions to everyone, which, being as shy as I generally am, was expected to be as intimidating as could be. But as soon as they started, it was clear something was different here. From Ali, the first QChatter who I met, who toured me around and helped me get settled in, to Vikram, who I didn't meet until many weeks into my internship, as he was on vacation when I arrived, everyone was ridiculously friendly, approachable, and helpful.

I've worked with many teams of varying shapes, sizes, and purposes before (though less often in the real world), and the QChat client team is unquestionably the first to be this universally awesome. Throughout the whole summer, there was a complete lack of raised voices (except in laughter and jest), blame-laying (I think I was the worst offender there, because I wasn't totally used to the laid-back workflow yet), and argument — which made it extremely easy to quickly become comfortable with the group and the atmosphere and get to work.

I might have gotten too comfortable — after being here for three months, I felt so much like a part of the team that yesterday's departure was quite hard to bear. Unfortunately I didn't manage to find everyone (Shobha, Sachin, Sanket, and Vikram, at least, and Teja was still on vacation — so an extra goodbye and thank you to all of you) to say goodbye to, but if I'd hung around for much longer, there would have been a few tears, and we didn't need that.

I won't miss fighting with the ever so wonderful prototype handsets, nor cursing the engineer who thought that using the C escape character as their path separator was a good idea (or that you needed two characters to represent a newline — basically, I won't miss Windows), nor silly little things like timecards, but the list of things that I will miss is innumerable. The whole team, for starters — every single one of you. The spirit of QChat. The long walks in the San Diego sunshine into work every morning. The daily status meetings (you guys will think I'm crazy, but I was already missing these when they stopped halfway through — it was good to see everyone every day and get a handle on what was going on in the beginning of the day; I learned a lot about what we were doing just from listening to the chatter there, and I hope if you have another intern next summer, you'll do daily status at least for the first few weeks). I'll miss our little faraday cage, and the wonders of release days. So, so many things.

I think the moment it all really clicked for me was that one super long (4 AM) sanity day. I think it was my third or fourth release; hanging out with everyone just trying to finish up (through the USB hilarity that ensued that everyone who was there surely remembers); ordering Indian food (my first time!) and being introduced to that by the people who know it best (by the way, the countless anecdotes about home from everyone makes me feel almost obligated to visit India... someday!)

And then on the opposite end of that was Shilpa's goodbye lunch — the end of the team as I knew it for most of the summer, and the first realization that the summer really was coming to a close. It was certainly a bonding experience for me; a chance to hang out with a majority of the team and talk about anything but work. I think that was actually one of my favorite days of the summer, bittersweet though it was.

So... I don't know. Maybe I'll run in to some of you again; it seems incredibly unlikely that I'll run in to all of you again. If I end up back in San Diego, I'll be sure to look you guys up, and if any of you are ever in Albany, Burlington, or Boston, send me a note! You never know where I might be...

And who knows what might happen in May! I certainly don't...

Thanks for everything, and goodbye (for now), and good luck!

Tim

Coda Notes, Internote

2010.07.29 in code

Today, everyone's beloved Mac software house, Panic, launched something that seems SUPER familiar to me (anyone who was around me 5 years ago will know why):



Coda Notes!

In other news, Matthew Tuck is working on Internote 3! I think that's pretty awesome, considering how long it's been unmaintained. Try it out if you want, but whatever you do, don't ask me for help :-)

AverageLapse

2010.05.18 in code

Since the semester's over, and I've got a week until work starts (I'm flying to San Diego on Saturday), I spent a little bit of time working on a tiny Cocoa program Nate had been writing:



It's a very simple program called AverageLapse, which takes a sequence of images (or, alternatively, a video that Quicktime can decode) and outputs the running average at each frame as a JPEG. It's also very parallelizable — I took this opportunity to play with libdispatch for the first time, which was neat!

For example, here's a frame from a timelapse (from OpenFootage):



This turns into the following video (if the HTML5 video below doesn't work in your browser, it's on YouTube too):



If you want to try it out and you're feeling experimental, check out the code from GitHub. Otherwise, I'll make a post with a 10.6-only binary later in the week.

P.S. Another interesting sample output video here.

My Once-in-a-Lifetime Bug

2010.05.08 in code

Two days ago, I received what ended up receiving an email which detailed what I believe to be the single most coincidental and epically ridiculous bug I will ever manage (I hope) to contribute to this world.

It turns out (as Mr. German-person so politely detailed) that the very simple random pattern generator that Robb and I implemented for Lights Off generates an "offensive" pattern at some point.

Now I won't go off on a tirade about how insane it is that someone can be offended by a 5x5 grid of lights, nor how it might actually be illegal to display said grid of lights in at least three countries, nor how the pattern that Lights Off was generating is actually completely different from the pattern that this person stated it was, and actually approximates an ancient symbol for peace (or good luck, or some such). Those are components of the human condition which mostly just serve to infuriate me, so I'll leave them alone.

What's important to note here is that the generation of the pattern is not the epic part of this bug. The fact that the level number which contained this pattern happens to also be a number often used as an identifying code within (despicable) groups of people who subscribe to the worldview symbolized by the "offensive" symbol... that is truly incredible.

That's also what made my fabulous new friend quite positive that I was one of those people.

Which I most certainly am not.

You can be assured he got an earful. Well... inbox-full.

I promise I was polite.

Sort-of.

In any case, he replied with a very polite, very over-apologetic response, even retracting his request that the "bug" be fixed. I fixed it anyway, as a side-effect of applying a patch that someone else wrote to improve the level generation algorithm (and make it significantly more complex).

If you're really interested in being "offended" (and you have to promise me that you won't take it out on me, I promise it's all totally random — you can inspect the source if you want!), you can start up Lucid, install lights-off, and go to level 88 (this will be fixed in GNOME 2.32, which will be in Maverick). Or, click here.

It's just not reasonable.

My Favorite New WebKit Bug!

2010.05.07 in code

Watch the window decorations!

HTML5 video below; will only work with very recent browsers. Otherwise, here!

Horton Slab Writeup

2010.05.07 in code, school, and typography

Introduction

Don't expect this to be anything... it's just a bunch of relatively-disconnected words about what was going through my head at various times during the project, and how I fixed it, which I'm writing at the request of the professor. More or less...

Glyph shape

Each glyph is a Python class which, when instantiated, knows the properties of the glyph (weight, cap-height, slant, etc.). Using this information, it constructs the geometry of the glyph, which is made by combining two different primitives: line and circle. Both of these primitives can also be clipped by arbitrary polygons (this is how the C is constructed, for example: by taking a circle and clipping out a triangular wedge from it).

Geometry manipulation (basic boolean stuff; almost always either union, intersection, or difference) is done with the Shapely library, because I really didn't want to do that myself, as it's not very interesting.

Each glyph has a function which calculates its width relative to one em, information which is used heavily during the drawing phase.

The glyph shape function can be either very complicated (like, say, 2) or very simple, like that of the lowercase l:

    mainLine = Line(self.p(0.5, 1.0), self.p(0.5, 0.0),
                    self.weight(), serif=5)
    return [mainLine]


That's a very simple one. 2, in comparison, is about 50 lines long...

The line constructor that you see above takes three required arguments: the location of both endpoints, and the weight of the line to be drawn. The optional serif argument adds serifs, which we'll talk about later.

The 'p' function (I needed a really short name because I call it hundreds of times and wanted it to be neat - think of it as 'position') that I call there takes a percentage position (0.0 to 1.0) in x and y (measured from the bottom left, like things should be done) and turns it into coordinates in the glyph's coordinate space. p also takes another argument which determines whether it should consider the top of the glyph to be at the cap-height or the x-height.

Many of the glyphs have small adjustments that are made to the shape of the glyph as the weight changes, in order to correct for unpleasant effects.

So, the l above makes a line from the top, halfway across the glyph, to the bottom, halfway across the glyph, at the full weight of the glyph, with the 5th serif type, which will be described below.

You can look at the rest of the glyph functions on GitHub: Capitals, lowercase, numerals, punctuation.

Strange or Missing Glyphs

I added center-dot (for multiplication) and interrobang (at the request of my roommates) to the normal set of glyphs. My 0 is too wide, but I couldn't bring myself to make it an oval (or, more likely, similar to the shape of the 6 or 9). My angle-brackets are huge. HUGE! Maybe I'll fix them someday. I'm missing curly braces, because they'd be really annoying to draw. Much worse than 2, which was enough of a pain that I don't want to endure it again.

Serifs

Serifs are actually added by the line drawing logic - each character doesn't really need to know how to draw a serif, it just needs to know what kind of serif it wants, and asks politely for that. There are 6 kinds of serifs a glyph can ask for on one of its lines:

    0 - No serifs
    1 - A vertical half serif on one end of the line. (E)
    2 - A vertical half serif on both ends of the line. (T)
    3 - A full serif on one end of the line. (A)
    4 - A full serif on both ends of the line. (H)
    5 - A full serif on one end of the line, a half serif on the other. (l)
    6 - A half serif on one end of the line. (j)


The fact that glyphs don't know about serifs is neat, because it means we can turn off the serifs very easily, by just asking Line not to draw any! That's how we get the sans-serif variant, which isn't on the poster, but that's ok... it's just not as awesome.

Properties

PHI = 1.618... (golden ratio)

Fixed glyph properties are as follows:

    1 em = capHeight / PHI
    xHeight = capHeight / PHI


The defaults for variable glyph properties are as follows:

    weight = 3 (this is a unitless measure, where ultralight = 0.5 and heavy = 7)
    slanted = False (not really italic, it's more slanted than anything)
    outlined = False (this was more for testing, but turned it into outlines)
    color = Black (obvious)
    serifed = True (whether or not Line should draw serifs for this glyph)
    autoKern = True (you'll see, in a bit)


Italic

The italic variant isn't nearly as neat as all the rest, it's just made quite literally by shearing the character with Cairo while it's being drawn. Not interesting, not particularly awesome, but it worked out OK. There's a pretty good chance it will break the consistency of inter-word spacing, but I'm not totally sure how to fix that (without doing the shearing beforehand, with Shapely... or manually).

Weights

Technically, you can generate glyphs of whatever weight you want, because it's all procedurally generated. However, I blessed a few weights so that I didn't have to look at/tweak more than a few weights:

    Ultralight = 0.5
    Light = 2.0
    Regular = 3.0
    Bold = 5.0
    Heavy = 7.0


Kerning

Kerning was a stickling point for the first few days. At that point, I was just throwing glyphs down and advancing the x position by the reported width of the glyph. We all know why this doesn't work, though, with the AV pair being the classic example.

So, instead, I wrote an optical autokerner in a few lines of Python. It works by placing the two glyphs on a plane and shifting them back and forth until it finds the boundary where they're just touching, then adds the correct amount of kerning. There's a kerning table which gives adjustments relative to this value, but it only has a handful of entries (one case which was particularly problematic was +=, where the bar of the plus slid directly into the middle slot of the equal-sign, kerning them way too tightly). It could probably do with a few entries, but after all this, I didn't have a lot of time to work on the kerning table, and I didn't really think it looked terrible - at least not enough to worry about.

There's another issue with the optical autokerning: punctuation. Tiny little dots don't autokern well at all; also, quotes don't ever collide with lowercase letters, so that breaks things too... So I added a per-glyph override which instead kerns based on the bounding box of the glyph extended to basically-infinity in the vertical direction. This mostly fixes the problems with punctuation.

The autokerner is really quite slow (as you might expect), especially for large blocks of text, so there's a disk-based cache that stores the kerning values between runs. You have to delete it if you change the glyph shape, or your kerning will be horribly wrong. Also, the cache is per-capHeight-per-weight (as kerning values change slightly), so if you change the capHeight or weight, get ready to wait again...

Layout

The space character is also a glyph - it's a square block which is special-cased to not be drawn at all in the drawing logic. This fixed a lot of trouble I was having when advancing words in the "stupid" way (just adding some amount of x-advance each time you see a space character), where the space between the words ended up varying significantly, which was really tripping up reading.

My line-breaking algorithm is horribly primitive: it just draws words at a time; when it gets to each word, it checks to see if it's past the edge of the layout box. If it is, it moves down by the leading and moves back to the left side of the box. This is a problem mostly because it means the last word on a line could be (and usually is) extending beyond the right side of the layout box. Also, it creates really crappy right rag unless you pay a lot of attention, because it's really not aware of the idea of rag.

If I had a ton more time, I'd implement Knuth's famous line-breaking algorithm (the one TeX uses), which is pretty much ideal, but since I don't have that kind of time, I decided against writing a poor knockoff. I've heard it's not actually that complicated, but... relative terms...

Input Format

The main program takes an XML file with a very simple format. For example, you can see the one that makes the description of the various weights that's on the poster here.

There are only a few tags defined:

    u, l, r, b, h = Weight (ultralight, light, regular, bold, heavy)
    i = Slanted/Italic
    br = Newline
    textbox (attributes x, y, size, width, height) = A reflowing text container
    leading, tracking, size (attribute px) = Obvious text properties
    color (attributes r, g, b, a) = Obvious color properties
    sans, serif = Turn on/off serifs


More Stuff

If you have any questions, feel free to email me.

The code is all open-source, under the relatively permissive 2-clause BSD license, which basically just says you can do what you want with it as long as you keep my copyright header around... (the terms are in LICENSE in the source directory, but they're exactly the same as all of the gazillions of other BSD projects out there). The code is here.

Libraries/Thanks

Python
GEOS + Shapely
Cairo + PyCairo
ElementTree

Orbitals, Particles, a Font, and some Sheeple

2010.04.29 in code, school, and typography

Apparently the semester's nearly over, or so I've been told (repeatedly. naggingly.)! In any case, I've gotten a lot more done on some things than I expected, and a lot less on others... it's always hard to predict how the semester will go.

A Font

For Typography, I've been working on the font + renderer + autokerner that I just wrote about the other day. I won't post any more pictures, just scroll down a little further to see that post!

Orbitals

For Parallel Programming, I've been working on a atomic orbital simulation, using OpenCL to evaluate the electron probability density function for a hydrogen atom at many, many points. It makes nice smooth images like this:



It's showing approximately a 20x speedup, moving from Zoe's CPU to GPU (Core i7 @ 2x2.66/3.33GHz to a NVIDIA GeForce 330M GT). The move from Zoe's CPU to Jayne's GPU (the 4890) is even more awesome; it's something like 40x faster!

Eventually (soon), I'm going to make an animation with it, and then it's time to write a paper!

Particles

For Advanced Computer Graphics, I've been working on a particle system simulator that uses (surprise!) OpenCL to simulate tons and tons of particles at once (millions, anyway). And render them, attractively (the renderer is still in its infancy). And it comes with a tool to design them, too (also incomplete).

I don't have any really interesting examples to show now, because I just got emitters to work. Below is a picture of something like 1,000,000 particles being blown away from the origin by two "simple"-type forces (they just push outward from a point, with inverse-square falloff).



And a video (which will only work if you're using a very recent Chrome or Safari, probably) of the same simulation, though with only 128K points. This simulation really isn't interesting because there's nothing complicated going on. I've got gravity working, which is a gazillion times more interesting and more complicated, but I'll post pictures and video of that some other day (it's also much, much slower).

It also turns out that the overhead of OpenCL isn't worth it for simple forces; it significantly speeds up complex (O(n^2)) forces like gravity (I'm aware of many ways to speed up n-body simulation, I just haven't had a chance to implement them yet), but for O(n) forces like below, it really only provides a tiny-to-near-zero gain.



Sheeple

All of this (plus normal coursework) leaves less time than desired for other things, but I still manage to occasionally put a few hours in to work on Sheeple. I feel bad that I don't have tons of time for RCOS work, though I will note that all of these projects are open source (all of them are under the 2-clause BSD license except Sheeple, which is GPLv3), so the general idea of promoting/using/writing OSS is still there :-)

I recently wrote and pushed a partial implementation of a Google Contacts backend for Sheeple. It's a lot smaller (and nicer, since it's written in Vala), and it's what I'd like to use for the time being while developing the UI and backend stuff, since it's a lot easier to change.

Another thing that contributes to slow Sheeple development is that everything now takes place in a VM; I don't have a native Linux install anymore, and I consider that a good thing. I've gotten sick of wasting time with a broken system, and I'm just not going to do that anymore - I don't care enough nor have enough time to spend to fix things, and I'm just generally all-around much happier in OS X. So both of my machines are running OS X, and I'm pretty sure that's how it's going to stay for the foreseeable future.

I should thank Moorthy and Sean O'Sullivan for putting up with me, and for constructing RCOS and keeping it alive. I wrote a long bit about what I think about RCOS and the people involved a few months ago, and that all still stands. Given this semester's overload (which will likely continue next semester) and how RCOS has worked out within this semester, I find it somewhat likely that I'm not going to participate next semester; I feel guilty about being paid to do much less work than I feel like I should be doing. I'll still hang around, certainly, and I'll (obviously) still write OSS, I'll even happily talk about stuff I'm working on, but the absence of that feeling of guilt/obligation/deadline (and also the ability to bounce between projects as I feel like it) will be quite the load off.

Slow Transition to S3

2010.03.07 in code and personal

I finished another part of my slow transition away from Dreamhost and on to Amazon's S3 for this site last night: I deleted everything related to this domain from Dreamhost. This meant setting up the Google App Engine proxy I've been thinking about for a while (which ended up being a just slight bit of horrific hackery upon shrub), and moving my DNS stuff back to the much-less-flexible 1and1 servers (which I get for free with my registration). This is a really ugly solution, because it adds another bounce for all HTML pages, but it still seems to be faster than Dreamhost, somehow.

It's mostly all working - unfortunately, GAE apps can't run on a naked domain, so the www is required now - any links to a subdirectory of hortont.com will redirect to the toplevel page. But I decided the temporary inconvenience was well worth the ~10$/month savings, so that's OK.

Also, links from more than 8-10 months ago are completely invalid now (I had a bunch of redirects, before, but they're gone now too in the shuffle). But that's OK, too. Really, who keeps around links to my blog? All of the internal links should be valid... I guess the big issue is things subscribed to RSS feeds with the naked domain. (I've already fixed a few random things I've found with this... I should check on Planet Gnome and stuff, too...)

I just have to move Carol and Matt, and then everything will be great - I've spent less than a dollar over the course of 2 months or so of S3... excellent!

I expect to find things broken over the course of the next few days... if anyone else runs into anything, let me know!

The proxy code is on Github.

Sheeple, One Semester In

2010.02.26 in code

Last semester, during RCOS, I started working on a contact-management application for GNOME (Seed is mostly in maintenance mode, at this point), called (for lack of a better name, at the moment) Sheeple. I keep a carefully-organized, constantly-updated address book, so I spend a bit of time in whatever contact-management program I'm using, so this is something that matters a good bit to me personally.

The de-facto application for managing contacts on GNOME at the moment is, of course, the behemoth personal-information-management suite, Evolution. Evolution has a long history, and is a large codebase, written by a lot of people, over a very long time. It also looks a little bit outdated:



Not a pretty sight. Not to me, anyway, not in 2010, when my alternative is:



Another fundamental difference between the two is in their editing functionality. Address Book provides the ability to edit contacts inline; Evolution requires you to edit contact information in an overly-limited (while it can store more than four email addresses per contact, you can only edit four in the editor window... what!?) separate window.



I decided to start working on a more Address Book-like application for GNOME. After a bit of deliberation, I decided to have it backed by Evolution's evolution-data-server, so that people's contacts would transition over smoothly. This might have been a mistake, because the EDS API isn't beautiful, and there are very few complete, working bindings, but I've made it mostly work.

It's written (mostly - the EDS-related code is straight C, unfortunately) in Vala. It's my first Vala program, so it's been a learning experience — Vala seems nice, though there are a few bugs (I've reported one glaring bug which was acknowledged, though it hasn't been fixed yet), and some bindings are a little sketchy.

During the development, I discovered that Nokia was developing libosso-abook (for Maemo), an address book library that provides a lot of the functionality that I was planning for libsheeple. Unfortunately, libosso-abook is currently closed-source. Not cool, Nokia... Anyway, if they open-source it (it's under consideration, at the moment), I'll probably ditch most of libsheeple and base the Sheeple UI on top of that, because it's a ton of annoying code already done.

After the end of last semester, I had the following:



Lots of things are broken, but it's something. I don't have working syncing yet, and I believe writing back to EDS is broken at the moment (so no persistence of changes!), but those are things I plan on working on this semester...

There are slides and stuff available, too.

A Move to GitHub

2010.01.18 in code

I decided that hosting my Git repos on Jayne was a silly idea. While it did mean nearly infinite storage (and upgrades at a fraction of the price of any alternative) and incredibly fast clones/pushes, having to deal with repository downtime every time I move my computer or decide to start Windows to play a game is simply ridiculous.

So, I've moved everything to GitHub. One visiting my Github profile should keep in mind that a lot of the stuff there wasn't public before, and 90% of it is stuff that got about 1% of the way done and was abandoned, or stuff which is years old at this point. Therefore, browsing around there is not recommended. However, from now on when I reference projects, I'll link to GitHub (and I'll probably go back and update old links in my blog, too).

Interesting repositories include the one for this site; my old GMP+GD mandelbrot generator; Sheeple, the Gtk contact management app I've been working on for RCOS; and the code behind my web-based Aperture tag browser.