Using an egpu on Linux

I've written previously about getting a Thunderbolt dock to power my external monitor and it's been mostly fine. I can plug my monitor, speakers and usb devices into it and just have one Thunderbolt cable to plug into my XPS 13 and get access to all the good stuff.

My one complaint is that even though my external monitor doesn't stutter anymore, performance wasn't as good as it could be. General windowing operations still had noticable lag, my laptop got super hot when it was driving the monitor, and games were still pretty much unplayable on due to poor framerate.

I've been following the progress of external graphics cards (egpus), and it sounded like they're pretty much plug and play, at least for Windows, and more and more OS X. There haven't been too many reports of it working on Linux, but emboldened by my excellent experience running Arch, I took the plunge and bought a Sonnet eGFX Breakaway Box and a secondhand Nvidia GTX 660.

Sonnet eGFX Breakaway Box

After I got everything and plugged the graphics card into the Sonnet enclosure, I installed the nvidia-dkms package and dependencies, plugged the egpu into my dock's Thunderbolt port, plugged my XPS into my dock and everything just worked!

X found the second gpu just fine and rendered the second monitor as an extension of the laptop monitor the same way I had it with the single integrated gpu.

General windowing performance was snappy. Full screen YouTube videos on the monitor didn't burn up my laptop. Framerate on simpler games like Don't Starve and Rimworld was excellent, in the 60s, and games like XCOM2 and Everspace were playable in the 20s. Everything was just how it should be for the most part.

The only annoying thing now is that I can't hotunplug the egpu out. I have to poweroff my laptop before unplugging it from the egpu, which is kind of a drag. If I don't, everything just freezes. Hopefully as more people get egpus on Linux, kernel/driver/xorg devs will fix this issue. If you're working on it, drop me a line, I'm happy to test stuff!

Besides hotplugging, everything was great. Until I got a dreaded breaking change in the nvidia drivers 😱

Upgrading from nvidia driver version 390.48 to 396.24 caused my X to crash on bootup. After digging in the X logs (/var/log/Xorg.0.log) I found:

[    23.631] (WW) NVIDIA(GPU-0): This device is an external GPU, but external GPUs have not
[    23.631] (WW) NVIDIA(GPU-0):     been enabled with AllowExternalGpus. Disabling this device
[    23.631] (WW) NVIDIA(GPU-0):     to prevent crashes from accidental removal.
[    23.694] (EE) NVIDIA(0): Failing initialization of X screen 0

Kind of ironic that it did end up causing a crash anyway.

I was kind of annoyed that I had to add this new X option because I had 0 X config. Everything was configured dynamically, and I set my desktop resolution and positioning using an xrandr script at startup.

At first I thought I had to configure EVERY. SINGLE. THING statically in xorg config and was super frustrated that I couldn't get X to merge my two monitors with static config.

Eventually I figured out that I can still let xrandr do most of the work, I just needed to define my devices. This is the config I ended up with:

Section "Monitor"
	Identifier   "Laptop"
	VendorName   "Dell"
	Option "Below" "External"
	Option "DPMS" "true"
EndSection

Section "Monitor"
	Identifier   "External"
	VendorName   "Asus"
	Option "Above" "Laptop"
	Option "DPMS" "true"
EndSection

Section "Device"
	Identifier  "gtx660"
	Driver      "nvidia"
	BusID       "PCI:12:0:0"
	Option      "AllowExternalGpus" "True"
	Option      "Monitor-HDMI-0" "External"
EndSection

Section "Device"
	Identifier  "iris"
	Driver      "modesetting"
	BusID       "PCI:0:2:0"
	Option      "Monitor-eDP-1-1" "Laptop"
EndSection

And then everything was fine again! Unfortunately, hotswapping still didn't work even with the new AllowExternalGpus option. But I could upgrade to the latest packages and everything was back to normal!

My workstation with the dual monitors and egpu

Hooray for Linux continuing to be a great option as an everyday workstation.

Syntactic Bay Leaves is now HTTPS-secured Wed, Feb 14, 2018

Now that Chrome is shaming everyone into using HTTPS and crypto kiddies are man-in-the-middleing you with javascript miners, I decided it's time to convert the ol' blog to HTTPS.

I host this blog as an S3 static site, but S3 doesn't offer HTTPS for their buckets. I could use Cloudfront, but it always felt a little clunky when I worked with it in the past. That said, after doing some after-the-fact research, I found that someone has create some Terraform modules to automate this very thing.

Anyways, I went with Cloudflare since they have a free plan the lets me use their shared TLS certificate, with the added bonus of caching the contents to shave millipennies off of the pennies I pay for S3 hosting.

And now you can peruse this blog without fear. Enjoy.

Making a simple AwesomeWM widget Sun, Jun 18, 2017

It's been a long time since I switched to Linux, but I've been running Arch Linux instead of Mint for a few years now. My current workstation is a Dell XPS 13, which is a really lightweight, pleasantly designed device whose hardware is all well-supported on Linux.

The main weak point is its integrated graphics card, which I found couldn't drive an external 1080p monitor on its own without stuttering. I bought the Dell TB16 Dock to drive the monitor, which fixed the problem nicely with minimal fuss. Now I can use an external monitor like a normal person!

But! The fans are always on high when I'm plugged into the dock and using the external monitor. I got concerned about the cpu temperature, so started monitoring it with a simple watch command:

$ watch -n 1 sensors
Every 1.0s: sensors                       xps13-arch: Sun Jun 18 14:47:16 2017
coretemp-isa-0000
Adapter: ISA adapter
Package id 0:  +53.0°C  (high = +100.0°C, crit = +100.0°C)
Core 0:        +52.0°C  (high = +100.0°C, crit = +100.0°C)
Core 1:        +52.0°C  (high = +100.0°C, crit = +100.0°C)

acpitz-virtual-0
Adapter: Virtual device
temp1:        +25.0°C  (crit = +107.0°C)
temp2:        +27.8°C  (crit = +105.0°C)
temp3:        +29.8°C  (crit = +105.0°C)

iwlwifi-virtual-0
Adapter: Virtual device
temp1:        +37.0°C

pch_skylake-virtual-0
Adapter: Virtual device
temp1:        +49.5°C

I thought it would be cool to see temperature in a more minimal way on my taskbar. Since I used Awesome as my window manager, I have pretty fine-grained control over the UI, so instead of installing a standalone app just for the temperature, I decided to learn a little bit about Awesome's text widget api so I can translate my command line call into data that drives a text widget. This is what I came up with:

-- Instantiate a new textbox widget
local tempwidget = wibox.widget.textbox()

-- The shell command to run. In this case, we call sensors in a for loop,
-- sleeping 5s in between each call. We pass -u to sensors to get raw
-- unformatted data from it, and coretemp-isa-0000 tells it to get just
-- my cpu's temperature. We pipe that output into awk to get just the
-- numeric value.
local cmd = [[bash -c "
while true; do
    sensors -u coretemp-isa-0000 | awk '/temp1_input/ { print  }'
    sleep 5
done
"]]

-- The shell command is a blocking call but we don't want to block
-- the rest of the UI waiting on it, so we use Awesome's
-- awful.spawn.with_line_callback() to spawn a subprocess for the
-- command and call our callback whenever there's new stdout data.
-- Awesome handles this subprocess communication in a nonblocking
-- way so the rest of the UI stays responsive.
awful.spawn.with_line_callback(cmd, {
    stdout = function(line)
        -- This callback gets called whenever there's a new stdout line,
        -- so in our command's case, every new temperature sample.
        -- We do some simple string formatting on the value and update
        -- the widget's value. Note that tempwidget is a closure on
        -- the widget we instantiated earlier.
        tempwidget:set_markup(string.format(' CPU: %.0f°C ', tonumber(line)))
    end,
    stderr = function(line)
        -- Here we just post Awesome notifications if there's anything in stderr
        -- in case the sensors command writes some errors to stderr.
        naughty.notify({ text = "ERR:"..line})
    end,
})

-- I'm omitting a lot of other layout code that probably already exists in your
-- theme, but I'm assuming there's a layout for the right side of your taskbar
right_layout:add(tempwidget)

This all feels nicely Linuxly. I didn't have to spin up a new app with complicated GUI dependencies just to get a simple value that I could already get from command line.

Encrypt your local AWS credentials with aws-vault Sun, Jun 04, 2017

I want to start blogging again, so that means figuring out how my static site generator works again. Turns out its ruby dependencies have rotted, so I'm just gonna copy-paste the html to publish stuff.

Next step: redownload the content from s3. Since I wiped my laptop since I last published, I don't have the original AWS keys I used to post, so I took the opportunity to Do The Right Thing and immediately put my new AWS keys in aws-vault encrypted files.

Normally to use AWS APIs from a workstation command line, you need to pass AWS credentials either via a plaintext config file, or in environment variables, presumably from sourced from a plaintext bashrc file or similar. This leaves your credentials vulnerable if some malware manages to get on your machine and looks for AWS credentials, or if you laptop gets stolen and your hard drive isn't encrypted, or is encrypted but you've already logged in before its been stolen.

You could probably encrypt your AWS credentials file with GPG and have some wrapper script to decrypt it when you're trying to use the AWS command line tools, but aws-vault makes this much more conventient for you. How it works:

  1. Download aws-vault and put it in your PATH. Since it's a Go app, it's a single self-contained binary which is convenient. If you're running Arch Linux, it's also in the AUR

  2. To add your credentials:

    $ aws-vault add my-profile
    Enter Access Key ID:
    Enter Secret Access Key:
    Enter passphrase to unlock /home/carlo/.awsvault/keys:

    The passphrase is the encryption key to encrypt and decrypt those credentials, so don't leave it blank.

  3. To use the credentials:

    $ aws-vault exec personal ./my-script-that-needs-aws-creds
    Enter passphrase to unlock /home/carlo/.awsvault/keys:

Now, your credentials aren't in plaintext at rest. For some extra protection, you can add these parameters:

  • --session-ttl - Defaults to 4h but for increased security, you can reduce that time. Conversely, if you get tired of recreating your aws-vault session, you can increase the time, though it increases the amount of time a bad guy has to use your creds if your machine gets stolen.

  • --mfa-token - If you have multi-factor auth enabled on your IAM account, you can pass those tokens into aws-vault

Making animated gifs from command line Tue, Feb 26, 2013

Sometimes when you're watching your favorite show, a perfect moment comes along that you just gotta capture and share with everyone. That's where the animated gif comes in. Though they're really popular with the kids these days, they're surprisingly hard to make. Luckily there's some powerful open source command line tools that can help you: ffmpeg, ImageMagick and gifsicle. If you're on OS X and have Homebrew set up, all you have to do is run:

brew install ffmpeg imagemagick gifsicle

Boom. So the first thing you'll need is a video file. They're getting quite rare these days since everything's streaming now, but assuming you've got one, you'll wanna find the start time of the moment you wanna capture, and how long the moment is.

Once you've know those two things, you'll wanna fire up ffmpeg to extract the moment from the video into a series of gif images. For example, if I wanted 5 seconds from myvideo.avi, starting at 9 minutes and 52 seconds in, I'd run:

ffmpeg -ss 00:09:52 -t 5 -i /path/to/myvideo.avi myanim-%3d.gif

This will output a series of myanim-001.gif, myanim-002.gif, etc images to the current directory, with one image per frame in the video.

From here, you could just compile these images into an animated gif with gifsicle:

gifsicle --delay=4 --loop myanim-*.gif > myanim.gif

That will create an animated gif myanim.gif from all of the frames that ffmpeg extract with a delay of 4 hundreths of a second between each frame, looped forever. You can view it in a browser like Chrome this:

open -a /Applications/Google\ Chrome.app myanim.gif

Most of the time though, this will generate an image file that's way to large for you to post or others to view in a timely manner, so you'll wanna crop and scale down the image using ImageMagick, specifically ImageMagick's mogrify tool.

mogrify -crop 1024x1024+200+0 +repage -resize 480 myanim-*.gif

This will crop the images to 1024 by 1024 with a horizontal offset of 200 pixels, remove the cropped portion from the image, then resize it proportionally to 480 by 480. Now you can rerun the gifsicle command and you'll have a nice and svelte animated gif file on your hands!

Note that gifsicle has some options to crop and scale the animation, but I found that it doesn't preserve the quality of the images as well as mogrify does. Also be careful with mogrify because it modifies the image files you point it at, so you may want to make a copy of the first frame and test your mogrify command on it before applying the command to all the frames. Though if you mess up, you can always run ffmpeg again.

Enjoy!

Gangnam, Fox News style Sat, Dec 01, 2012

I saw a funny/racist clip of Bill O'Reilly "analyzing" PSY's Gangnam Style video to try to figure out why it's so popular. The pundit he had on said that it was just a mindless pop song with a good beat and it was meaningless and that's what people are looking for these days.

At best, this is extremely lazy, as they didn't even translate the words from Korean. At worst, it's just plain racist, implying that because it's in a language they don't understand, it's meaningless.

In most cases they would have been right: pop songs are mostly meaningless. However, this pop song actually did have a meaning: it was parodying Korean superficiality, where poser kids claim to be from the uber-rich Gangnam district, the Beverly Hills of Seoul. They could have picked that up from a quick scan of Gangnam Style's wikipedia page.

I didn't think much of the O'Reilly clip because, well it's Fox News. Getting mad at Fox News is pretty much just pissing in the wind. Mostly forgetting about it, I went on my merry way to get a long-overdue haircut in Chinatown.

I was chatting with the woman washing my hair, a middle-aged woman a few years younger than my mom. She asked if I worked or studied and when I said I worked she asked, "Oh, do you get two days off?"

I was thinking she was asking about Christmas break until she followed up with "like Saturday and Sunday?"

I prodded a bit, asking, "When do you have off?"

"Oh Tuesdays."

I was a bit taken aback, laying face up with my hair lathered up, feeling like an asshole because I get to not work for two days of the week and still be able to subsist.

This woman washing my hair for tips works 6 days a week, while we all take for granted our God-given right to a weekend. I didn't get a chance to ask if she had kids, but I knew the story well enough.

It was my parents story, both of them working 7 days a week to feed their 3 kids and aging parents with their local real estate business that served the immigrant community that the big real estate companies had no patience for.

My dad had the business phone line forwarded to our home phone during off hours so they were literally working the whole day. I grew up in fear of answering the phone because an angry client shouted at me the one time I did. I hated their business. They were always b busy working, and I was always the last to get picked up from school. As an adult though, I look back and thank God for my parents' diligence, paying my college tuition in motherfuckin' cash and giving me such a great position in life.

It's also the story of the Filipino lady who served me fried chicken at my college's local munchies spot, the one that got robbed every other month. She lived in Baltimore with her shut-in mother, supporting both of them with her fast food salary, as well as paying for her children in the Philippines to go to nursing school. Before I graduated, she had gotten a new job with my college's food services staff, a big step up. She had also met a nice man, an American citizen, who agreed to marry her so that the byzantine immigration laws would let her bring the rest of her family here. She asked me to be her best man(???) but I politely declined.

What does this have to do with Bill O'Reilly, you might ask? Well, these business-minded family-oriented Asian folks are exactly the kind of people who would vote Republican if the Republican party would even acknowledge their existence.

We start small businesses, creating jobs despite not benefiting from the "job creator" tax cuts. We don't rely on state assistance when we're old or sick or down on our luck because we have a strong family-oriented culture that has us take care of each other when we're in trouble. We do whatever it takes to excel in the broken school system so we don't have to go through the same economic hardships our parents went through. But Asians don't exist on the political radar, so it's ok to blatantly discrimint against.

Fuck that, I'm so tired of that shit.

Adventure game prototype 2 - A* pathfinding Sun, Oct 14, 2012

I wanted to add an easy way to script a scene with various sprites doing different movements and animations at different times, but my current implementation of sprites was too tied to actions triggered from player input. Additionally, I was trying to use physics collision boxes for obstructions and have the NPC sprites avoid them, but they only knew the obstructions existed when they actually bumped into them.

Luckily, I just so happened to be taking an AI class through BerkeleyX, where the first lesson was on search algorithms. Once we started learning about how to get Pacman through a maze in the most efficient way possible, I knew it was just what I was looking for. I learned that if you represent your problem as a start state, a goal state, a series of actions that can transition between states, and a domain of states your guy could be in, you can solve your search problem in a very general way, the best being the A* search algorithm. Intuitively, A* search means trying the next cheapest possible state, where cheap is defined as the total cost of all the actions to get to that state plus an estimated cost of getting to the goal once you're at that state.

After reading a rant about game pathfinding, I decided to represent my search states as vertices of navigable rectangles, or navmesh, on my tile map, and actions as displacement vectors. My sprites would be able to take a list of displacement vectors and queue up a bunch of actions that will move the sprites along those displacement vectors at a given velocity. This is a sample of a sprite moving to a northern area, a western area, and eastern area and back to the northern area:

Moving the sprite in black from one area to another requires a new search, and once the sprite finishes the actions from that search, it executes another search to get to the next area. Notice that she tries to avoid trees and walks along the edge of the path. What's nice is that I can define the navigable areas, as well as possible goal areas in my Tiled map editor.


Tilemap with navmesh overlay

Next, I might either continue on with the exposition side of things and add dialogue and transitioning between scenes, or maybe add some fighting again.

Adventure game prototype 1 - new art, better editor integration Fri, Sep 28, 2012

I updated the art I was using with free-er as in speech art from the Liberated Pixel Cup. The grass, trees and bee are all from the very excellent base assests they provide, and the player sprite is from Emilio J. Sanchez-Sierra's entry. Here's what it looks like now:

A lot of the LPC assests are in .xcf, so I had to install GIMP to work with them. Luckily, the OS X version can run mostly natively and doesn't need X11 anymore (though it still uses GTK-style dialogues! </nitpick>). The LPC assets let you mix and match hair, facial features and clothing by just switching up the layers, which is pretty freakin awesome, though I'm having a little trouble with basic operations with GIMP, arg.

I also updated the code to pull more data about the dynamic sprites from the .tmx map file in addition to the background tiles. Since the Tiled is such a great free standards-based .tmx map editor, having my game engine read object data from .tmx files will let me focus on map design instead of technical details. It would also let me collaborate on maps with people who may not know how to code, which is helpful.

There's still some work to be done to fix my collision handling code, it makes my character warp around when colliding with a tree. I also need to get the melee attacks going, probably going to have placeholder animations for individual attacks since the sprites aren't meant for fighting games. I'd also like to have a scriptable camera so that I can do interesting things with it, like panning and zooming across the scenery instead of always focusing on the player.

Adventure game prototype Fri, Sep 21, 2012

Somewhere along the way, I came up with a desire to do a 2D adventure game. I wanted it to be a top down game similar to the SNES Legend of Zelda, but with a Tekken-style combat system. I wrote up a a bunch of backstory and the initial quests which I'll share later, but I needed to verify that mashing Zelda with Tekken would make for a fun game, or if it were even possible.

So I whipped up a prototype using the Lua Löve framework, tiles from Mozilla's HTML5 tech demo/lovefest, BrowserQuest that I found on Open Game Art, and some River City Ransom sprites that I had lying around. Check it out:

I took Tekken's rock-scissor-paper style attacking/blocking/dodging scheme where high attacks were blockable blocking high and dodgable crouching low, mid attacks were blockable blocking high, but hit when blocking low, and low attacks were blockable blocking low but hit when blocking high. This leads to interesting guessing games where two attacks might have similar starting animations but one hits mid and the other hits low. I wanted combat in my game to be challenging, even against non-boss enemies, so you felt accomplished when you beat them.

I'll need to figure out what actual attacks will be available for the player and for the first few enemies and do my own art for it instead of ripping River City Ransom. Also gotta implement mundane things like getting obstructed by objects in the background, losing health and dying, tracking and improving player stats, etc.

I'll keep you posted.

Cleaning up that mess of wires Wed, Mar 28, 2012

The other day I tripped on one of the wires I have jutting out from the back of my media center and got fed up with the whole mess back there. My media center consists of a tv with rabbit ears, an Xbox 360 with Kinect and controller charging dock, an old Xbox (modded with XBMC) an Apple TV 2 (also modded with XBMC), a QNAP home server (for serving content to XBMC), a cable modem, a router and a subwoofer, and they all have wires wires wires all over the place. I need two power strips just to keep them all plugged in, not to mention two large power bricks, five power adaptors and 4 ethernet cords. That adds up to a ton of wires.

I tweeted a picture of my mess of wires asking, half-jokingly, if there's some startup dedicated to fixing the mess of wires behind people's media centers.

Luckily my good friend and colleague @jongala pointed me to a company called Bluelounge and their CableBox product. It's basically a rectangular box with a removable top that's big enough to put your power strips and adapters into, with two vertical slits to let out the wires. It seemed so simple, and I felt like a jerkface for paying 9.95 for a box when there are desperate children in the Philippines whose cables will remain tangled forever, but what the hell, I bought it anyway. And let me tell you, it worked great! Here's a before and after picture:

I couldn't be happier with my CableBox. Less cluster in my life = huge win.

Switching from OS X to Linux Mint 12 Sun, Feb 19, 2012

I've been an OS X user since Tiger's launch in 2005. I got a G4 Powerbook as a graduation present from my parents, and I loved how coherent an operating system it was. The biggest win for me was that it was unix-y enough to be a nice programming environment (Aquaemacs ftw) while at the same time having nice apps for normal day life things like Quicksilver, iTunes, iPhoto and Adium. I was coming from the frankenstein user experience of Windows XP + Cygwin environment, so OS X was a breathe of fresh air. I messed a bit with Gnome desktop on Fedora Core 3, but either I was still too much of a Linux n00b, or it still sucked too much to be useful (hello recompiling the kernel on video driver updates).

Fast forward to 2012, where my workstation is an iMac running OS X Snow Leopard, my music player of choice is Spotify, my editor is Sublime Text 2 and I spend a large portion of my time in iTerm2 in fullscreen mode with 3 or 4 terminal tabs split into 6 panes each. I refuse to upgrade to Lion because I hate the one-app-per-virtual-desktop-but-never-quite-knowing-the-order-of-the-desktops paradigm. The scrolling/scrollbars, and Mail.app are nicer, but not worth losing out on the virtual desktop issue. Also, the App Store can go to hell and die.

When Apple announced Mountain Lion, I could see that they were pushing for more iPadification and not much else to get excited about, so on a whim, I decided to give Linux desktop another shot. Apparently Linux Mint became the hot new distro in town when Ubuntu pushed out the much-maligned Unity desktop onto everyone, so I torrented the Linux Mint 12 "Lisa" iso, partitioned off a 20GB piece of my hard drive and gave it a go.

The install was pretty painless. It discovered the partition right away and started installing in the background while the wizard asked me the usual install questions, which I thought was a nice touch. It installed GRUB on my Windows partition, which threw me off for a bit, but nothing a little Googling couldn't unearth.

But yeah, everything installed fine, and after a Software Center package upgrade, I was running the latest and greatest Gnome 3 desktop. The things that you normally feared would fail on Linux worked fine: sound, video, wifi, builtin volume/brightness buttons, suspend, Flash, they all worked without any intervention on my part. Had to enable two-finger scrolling in the settings pane, but that's about it. I proceeded to get the same apps that I had worked with on OS X: Chrome, Spotify (sadly, doesn't have Spotify Apps yet), Sublime Text 2 (boo, no apt repo!), Dropbox. There's no shortage of terminals on Linux but I settled with Terminator for the split panes (not quite ready for Xmonad). I couldn't find a particularly nice Twitter client, which is surprisingly coming from OS X/iOS land where there's dozens of clients that was decent. I ended up settling on Gwibber, even though it had a comically low score of -81 in Software Center.

Also, can I just say, apt-get for the muthaf'ing win? Apt-get is great not just for getting all your development dependencies with zero fuss (homebrew on OS X is mostly good enough for that), but for all your system updates. Instead of getting annoying updater popups from Apple that require a system reboot, or every single app trying to do their own updates when opening the app, or the App Store where you need to explicitly go out of your way to discover if there are new updates and install them yourself. That is one paradigm that Apple definitely should not have copied from iOS. Nope, apt-get just goes and does its thing. You might get a notification from Software Center to run your updates, which is just a wrapper around apt-get, but for the most part you could probably just cron an apt-get upgrade && apt-get update every week and you'll be fine.

Gnome Shell is a pretty nice desktop environment. I like that they've created a (Mission Control + Quicksilver)-like view when you press the super key. They've managed to show all your open windows on the current workspace, plus a high level preview of all your workspaces, plus a search-as-you-type app search without it being a visual overload. I like it much more than OS X's Mission Control, though I do miss being able to search for songs from Quicksilver. I'm sure there's a shell extension that can do that, just haven't found it.

Speaking of shell extensions, I love that I can install or disable extensions right from the extensions website. My favorite extension so far is gTile, a nice way to resize your windows into fixed grid sizes (again, not ready for Xmonad). Apparently shell extensions are still bleeding edge, as there aren't great documentation on them. There's a brief intro on the Gnome wiki, but it doesn't try to help you with the GUI API, just on setup. It's nice that the extensions are Javascript and CSS, but the GUI API just looks like a thin wrapper around the Clutter API, which is C++, and doesn't look any prettier in Javascript. Still, it's a start. I'd like to create a nice Twitter shell extension at some point.

So, this is day 4 of me switching from OS X to Linux Mint 12, and I am loving it. My next steps are to figure out a nice cross-platform notetaking replacement for Evernote, which I'm leaning towards plain Markdown files + Dropbox, and to set up my Datadog dev environment, which should be a cinch since our prod environment also uses apt-get. Maybe also trying out a native email client, though the Gmail web app plus a shell extension for email notifications are working out fine.

Hooray for the Linux community!

Thumbnails

Hello world 3 Sat, Feb 18, 2012

Well here we are again, with me trying another blogging engine. This time, I'm moving away from a database-backed blog to a more simple static site. Gotta figure how how to make it easy to post to. Maybe this will encourage me to write longer form posts, instead of knee-jerk links.