Systems: Because You Can’t Count That Fast

Me trying to explain a global SAP ERP network to kids.

On Thursday, it was bring your daughters and sons to work day at Genentech. My little Marlowe is only 6 weeks old so I didn’t bring her, but my VP shot me a note Wednesday saying she was bringing her two boys, knew of some other kids who would be there, and wondered if I could give a 30 minute talk on systems. I responded, “sure.”

But what the heck do you tell kids ranging from 6-12 years old about your corporate ERP system? While fascinating, I doubt they’d care about the usual things that I work on and I wouldn’t dare show them PowerPoint slides. So what to do?

Continue reading

Hello Marlowe!

Allow me to introduce to the world, Marlowe Maxine McBride!

Marlowe was born in San Francisco, California at the University of California San Francisco (UCSF) hospital at 12:23pm on Sunday, 10 March 2013 (10 + 3 = 13 … yay! A math trivia birthdate!). She weighed in at 7 pounds 7 ounces, and measured 21 inches in length.

Both Alicia and Marlowe are doing great and getting a lot of needed rest. Marlowe’s middle name is borrowed from my paternal grandmother. Her first name was her mom’s top pick and after witnessing the process of giving birth, mom had final decision rights on the name. Luckily, when we both gave our final suggestion on what her name should be around noon on the 11th (24 hours after her birth), we both agreed Marlowe matched her personality.

For those of you looking for more pics, I will upload highlights by day to the link below for the first week or two, so check back each day for more:

Click for Marlowe Pics!

Cleanup Unused Linux Kernels in Ubuntu

I update Ubuntu with a very simple script I call apt-update that looks like this:

$ cat ./apt-update 
sudo apt-get update; sudo apt-get dist-upgrade; sudo apt-get autoremove

Nothing too crazy there. It updates the apt-get cache, performs the upgrade, and then removes all the residual junk that’s laying around. Well, almost all. If you do this enough, eventually you’ll see the following (assuming you’ve got the default motd Ubuntu script running and you’re logging in from a terminal):

=> /boot is using 86.3% of 227MB

This is because that script I mentioned doesn’t consider old kernel images to be junk. However, unless you’ve got an abnormal /boot partition, it doesn’t take too many old images to fill it up.

A quick Google search found Ubuntu Cleanup: How to Remove All Unused Linux Kernel Headers, Images and Modules. The solution on the page had exactly what I’m looking for, however, I couldn’t take it at face value. While the article offers an adequate solution, it doesn’t offer much explanation. The remainder of this article explains the details for this one-liner noted in the article above:

$ dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge

Note: Only run this if you’ve rebooted after installing a new kernel.

Ick. Let’s dig into what’s going on here. The pipe characters are chaining a bunch of commands together. Each command’s output becomes the input for the next. Given that, let’s walk through what’s going on in 3 steps.
Continue reading

Remove Chromatic Aberration With Lightroom

I was chatting with Karen Yang last week about photography and she mentioned that she uses Photoshop to open each of her photos individually to edit them. As I’m a huge fan of all of the powerful one-or-two-click tweaks in Lightroom, I thought I’d note one here that I fixed over the weekend and hopefully begin to help Karen see the Light … room. :)

The issue I ran into with my photo is called chromatic aberration. It’s a term that simply means not all colors of light had the same focal alignment when captured. Chromatic aberration usually can be seen by colors bleeding out on the edges of subjects in your photos. Check out this shot of me as an example:

Continue reading

Managing A Large Photo Library With Lightroom, Dropbox, and Crashplan

Late last year I made the switch to Adobe’s Lightroom 4 from Aperture and Picasa for a variety of reasons, but a big one was photo/file management. As my photo collection got larger I found that I’d need more than my laptop’s hard drive to store them all. Despite all the things I liked about Aperture and Picasa, both had clunky file management and the burden was enough to make me consider alternatives. I’m now very happy with the workflow described below using Lightroom, Dropbox, Crashplan, and a Linux file server.

What I Want to Accomplish

I want my setup to enable the following:

  1. Mobile Photo Management: To be clear, when I say “mobile,” I don’t mean smartphone. I take my Canon 5D Mark III everywhere and like to transfer photos to my Apple MacBook Pro immediately. It’s important that I be able to do whatever I need to do no matter where I am, i.e., I don’t want to be tied to my office.
  2. Large Photo Archive: Photos (especially RAW photos) consume a lot of disk space. I want a file server to store any photos that I’m not actively working on. It has to be huge and scalable.
  3. Passive Transport: I want my files to get to my file server as quickly as possible, but I don’t want it to be an active part of my workflow, e.g., I don’t want to get stuck waiting on a FTP program to finish its batch before I can disconnect from a wifi spot or put my computer to sleep. I’d rather it just happen when the opportunity arises.
  4. One-Time, Offsite Backup: Once my files are on the file server, I want them to back up from the server only (i.e., I don’t want my laptop doing a second backup). Also, as I’ve noted before, I like offsite backup of my photos. A local copy isn’t good enough.
  5. Accessibility. When home, I want to easily access all of my photos, whether they’re on my laptop or in the archive.

Sound like a lot to accomplish? It turns out it’s pretty easy to do. Continue reading

Stop Taking Lossy JPG Screen Shots for Text in OS X. Use PNG.

If you take a lot of screen shots in OS X using the built-in screen capture functionality (e.g., cmd-shift-4) and present them to other people, you should really consider changing one of the default OS X settings. This is especially true if the content contains a lot of text. To be clear about what I mean, consider these two captures of a random gDoc form:

Lossy capture using JPG:

Lossless capture using PNG:

You can probably see the difference quite clearly. The jpg looks blotchy and the color of red has been distorted. This is because the JPG format will degrade image quality to produce a smaller file. Given that we’re talking 9 vs. 13 KB in this case, the savings don’t really matter. What does matter is that the image looks terrible and makes you look oh-so-non-tech-savvy.

The solution is quite simple if you’re using OS X. Simply change the default format for screen captures. Launch the Terminal app and issue the following commands:

$ defaults write type png
$ killall SystemUIServer

That’s it! All of your screen captures will now be in the much cleaner PNG format. If you decide you’d rather have JPG again, just replace “png” with “jpg” in that first command.

Controlling Movies in QuickTime Player X (10.1) With AppleScript

The following works for Quicktime Player X (10.1) in OS X 10.7 (Lion). It takes arguments from the command line and opens a movie, resizes it, sets the volume, and starts playing the movie (there are other properties you could add). Hopefully this is useful for someone like me who was trying to find examples of this, but only finding mounds of info for QuickTime Player 7 (and earlier), which doesn’t help much as many of the properties have changed.

-- AppleScript to open and control movie files in QuickTime Player X

-- The script is meant to run at the command line, like so:
-- $ osascript /path/to/movie.mp4 movie.mp4 800 60
-- If you don't want to use a shell, just remove this and 
-- the last line and manually populate the first 4 variables
on run argv
	set movieFile to item 1 of argv -- the full path with movie filename
	set movieName to item 2 of argv -- the file name only of the movie
	set desiredWidth to item 3 of argv -- the width of the movie on the screen
	set startOffset to item 4 of argv -- how many seconds into the movie to start
	-- this finds the right side of the screen, then offsets to the left
	-- the desired width of the movie
	tell application "Finder"
		set desktopBounds to bounds of window of desktop
	end tell
	set rightX to item 3 of desktopBounds
	set leftX to (rightX - desiredWidth)
	tell application "QuickTime Player"
		-- open the movie and bring it to the forefront (if other movies are open)
		open movieFile
		set lastOpenedWindow to (first window whose name contains movieName)
		set visible of lastOpenedWindow to true
		-- resize the movie using its original aspect ratio
		set movieBounds to bounds of lastOpenedWindow
		set widthOrigin to leftX
		set heightOrigin to 1
		set originalWidth to ((item 3 of movieBounds) - (item 1 of movieBounds))
		set originalHeight to ((item 4 of movieBounds) - (item 2 of movieBounds))
		set calculatedHeight to (round ((desiredWidth / originalWidth) * originalHeight) rounding down)
		set desiredWidth to (desiredWidth + widthOrigin)
		set calculatedHeight to (calculatedHeight + heightOrigin)
		set the bounds of lastOpenedWindow to {widthOrigin, heightOrigin, desiredWidth, calculatedHeight}
		-- if opening multiple movies, ensure they don't overlap
		set slideDown to 1
		repeat with aWindow in (get every window)
			set boundsOfAWindow to bounds of aWindow
			set heightOfAWindow to item 4 of boundsOfAWindow
			if (heightOfAWindow > slideDown) then
				if (name of aWindow does not contain movieName) then
					set slideDown to (heightOfAWindow + 1)
				end if
			end if
		end repeat
		set the bounds of lastOpenedWindow to {widthOrigin, (heightOrigin + slideDown), desiredWidth, (calculatedHeight + slideDown)}
		-- note, here we select a document, not a window
		set myMovie to document 1
		tell myMovie
			set audio volume to 0
			set current time to startOffset
			activate -- makes QuickTime Player the frontmost application
		end tell
	end tell
end run

Understanding Offsite Backup vs. Local Backup vs. Syncing

A few days ago a good friend of mine, Jami, sent me this question via email:

… a while back … you wrote about cloud back ups and I believe you recommended Crash Plan. I tried the free trial but was disappointed because it was SO slow. I like drop box, but couldn’t figure out a way to get it to automatically back up my whole computer like time machine did. I tried hooking up my old time capsule that we used to use as a router directly to my computer via ethernet, but I couldn’t get that to work. SO, I thought maybe it was just a random thing that Crash Plan was so slow the first time, so I signed up again in desperation. For 150+ gb, it says over 57 days?!? Do you think that seems right?

Do you have any other recommendations? I want something that worked like time machine did, preferably cloud based. I’m curious what you’re using.

The following is what I responded with via email, but I’ve actually gotten this question from a few people lately, so I thought I’d post it here.
Continue reading

Replacing –, ’, “, etc., with UTF-8 Characters in Ruby on Rails

Recently I upgraded some older Rails applications to Rails 3.1 and Ruby 1.9.2 (from 2.3 and 1.8.7 respectively). One post-upgrade issue was that text content had a lot of garbage showing up like –, ’, “, etc. For example, here’s an actual example from a comment in one of the applications:

One of my “things to do before I’m 50” is

This should read:

One of my “things to do before I’m 50” is

It turns out these are just special characters that were improperly encoded for utf-8. The fix is simple enough: loop through your content and replace where needed.

If your database is big, this could take a long time unless you disable callbacks. The script below highlights both how to replace the characters using Ruby and how to disable your Rails callbacks to make this script run in seconds instead of hours (depending on the complexity of your callbacks).

replacements = []
replacements << ['…', '…']           # elipsis
replacements << ['–', '–']           # long hyphen
replacements << ['’', '’']           # curly apostrophe
replacements << ['“', '“']           # curly open quote
replacements << [/â€[[:cntrl:]]/, '”'] # curly close quote
klasses = [Comment, Article]           # replace with relevant classes
klasses.each do |klass|
  klass.all.each do |obj|
    original = obj.body
    replacements.each{ |set| obj.body = obj.body.gsub(set[0], set[1]) }
    unless (original == obj.body)
      #### Remove or Customize ####
      # This should reflect your models' callbacks.  It should be safe
      # since we're just doing a simple find/replace.
      Comment.skip_callback(:save, :after,  :do_after_save_tasks ) if obj.is_a?(Comment)
      Article.skip_callback(:save, :before, :do_before_save_tasks) if obj.is_a?(Article)
      #### End Remove or Customize ####! 

If you noticed, I used a regular expression for the curly close quote. This is because there is an invisible control character that is not easily copy/pasted into your code. Using [[:cntrl:]] is just an easier way to catch it.

Integer Compression in Ruby (Base-10 to Base-62)

A few days ago I was thinking about all those link shortening sites and wondered how easy it would be to compress a base-10 number like 1,234,567,890 to something much smaller like 1LY7VK. Here’s what I came up with:

class IntegerCompressor
  CompressionCharacterSet = %w(0 1 2 3 4 5 6 7 8 9
  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
  a b c d e f g h i j k l m n o p q r s t u v w x y z)
  def self.to_base

  def self.compress(number_to_convert)
    digits_needed = Math.log(number_to_convert, IntegerCompressor.to_base).floor + 1
    compressed_number_string = ''
    previous_remainder = number_to_convert
    (digits_needed-1).downto(0) do |power|
      compressed_number_string << CompressionCharacterSet[r[0]]
      previous_remainder = r[1]
  def self.decompress(compressed_number)
    power = 0
    base_10_integer = 0
    compressed_number.to_s.reverse.each_char do |digit|
      base_10_integer += ((IntegerCompressor.to_base**power)*CompressionCharacterSet.index(digit))

It seems to work:

$ irb
>> require '/path/to/file/integer_compressor.rb'
=> true
>> IntegerCompressor.compress 1234567890
=> "1LY7VK"
>> IntegerCompressor.decompress "1LY7VK"
=> 1234567890

If anyone has a more elegant solution, I'd be curious to see it.

(Thanks to Tamara for the log refresher.)