Hi! My name is Itai. I'm a Mac and iOS developer, mostly. You can find me on GitHub and Twitter. If you're looking for a professional profile, you can take a look at my StackOverflow Careers page. If you want to contact me, feel free to send me an email.

Hazel Workflow Update

Turns out, the workflow I posted for Hazel is broken. Not terribly so, but still broken. I hadn’t considered the fact that DEVONthink doesn’t store files as-is, but rather copies them over into its database file and splits them up. DEVONthink doesn’t copy all files into its database (specifically, dotfiles: a Git repository, a Mercury repository, etc.), and that’s fine. It’s not really meant for that; it’s a consumer-oriented application.

So, I wanted to update my workflow to ignore Git directories (since I use Git, and not Mercurial or Subversion) and decided to update the rules for my Desktop and Downloads actions to check files using an embedded Ruby script. The shell is /Users/atlas/.rvm/bin/rvm-auto-ruby since I use RVM to manage my Ruby installation, but it could likely also work with /usr/bin/ruby since it doesn’t rely on any external Gems. The script goes as follows:

# Returns the size of the folder or file in megabytes.
def file_size (file)
  begin
    if File.directory? file
        entries = Dir.new(file).entries.select { |filename| filename != '.' and filename != '..' }
        entries.inject { |size, filename| size += file_size File.new "#{file.path}/#{filename}" }
    else
      file.size / 1024.0
    end
  rescue
    0
  end
end

# Load the given file.
file = File.new ARGV[0]

# Ensure the file is less than 100MB in size.
exit(1) unless file_size(file) < 100

# Check the creation date and modification date.
require 'date'
cutoff = (Date.today - 7).to_time
exit(1) unless file.ctime < cutoff and file.mtime < cutoff

# Reject git repos.
require 'shellwords'
exit(1) if File.directory? file and `cd #{file.path.shellescape} && git status &>/dev/null` and $?.exitstatus == 0

That will check every file for its file size, ensure its creation date and modification date are over one week ago, and if it’s a directory, will make sure it’s not a Git repository. If all those conditions are satisfied, the file or folder can be archived.

I removed all the old rules, and Git repositories should now be left alone. (It’s trivial to add support for dotfiles in general, or Hg repositories, but that’s an exercise left for the reader.)

Archiving Files with Hazel and DEVONthink

I keep three kinds of files on my system: scratch files (temporary files I’m working on that haven’t been finalized and placed somewhere permanent — or deleted — yet; they almost always sit in ~/Desktop), project files, and files destined for long-term cold storage (reference documents, eBooks, receipts, backups of font files, etc.). I have few scratch files, a moderate number of work files, and an exceeding amount of ‘dead’ files. For a long time, I simply kept the dead files in ~/Documents along with my projects, but at some point I realized that those dead files were just clutter that needed to be stowed away somewhere (preferably never to be seen again).

DEVONthink is where I now store those files. Much like Yojimbo for Shawn Blanc, DEVONthink serves as my Anything Bucket (or rather, my Anything I No Longer Need On Hand Bucket). It creates a taggable, searchable database of files that I can find when I need to, but that doesn’t get in the way when I don’t. When I find a file I can safely cryo-freeze, I drop it into DEVONthink, tag it, and move on with my life. The Pro Office version also lets me scan and OCR documents directly into it, so they don’t even need to land on my desktop, which is a huge benefit.

For those who care about this stuff, I store the database in Dropbox inside an encrypted sparsebundle that gets auto-mounted at login (the password is stored in my keychain), so the process is completely transparent. No one can read my files without access, but it’s not a hassle to use. I’ll occasionally run into a race condition where DEVONthink will launch before the DMG is mounted, but it’s rare and isn’t a big issue.

But what about files I forget to toss in there? Files that sit for too long in ~/Desktop and ~/Downloads? Well, that’s what Hazel is for. Anything that’s done repeatedly on a computer can almost always be delegated to the computer itself to automate, and that’s what I do with Hazel. Both my desktop and downloads folder (the sources of most scratch files) have an action called ‘Archive’ applied to them that looks like this:

Archive

Essentially, if I haven’t touched a file (created it, moved it, or opened it) in a week, and it’s not too big (since I’m limited in Dropbox space), Hazel will run an AppleScript to archive it. That script looks like this:

-- Get file metadata from Finder.
tell application "Finder"
  set _path to (the POSIX path of theFile as string)
  set _name to (the name of theFile as string)
end tell

-- Lauch DEVONthink if it isn't already open.
tell application "System Events"
  if not (exists process "DEVONthink Pro Office") then
    tell application id "com.devon-technologies.thinkpro2" to activate
  end if
end tell

-- Import the file.
tell application id "com.devon-technologies.thinkpro2"
  import _path name _name to create location "Inbox/Archive"
end tell

The script should be pretty self-explanatory. theFile is a variable Hazel uses to represent the file that needs to be imported, and _path and _name store the file’s full filepath (e.g. ~/Desktop/some_file.md) and just its filename (some_file.md), respectively. Once the file has been imported, Hazel pops up a Growl notification letting me know the import finished, and it runs a shell script to move the now-unnecessary file to the trash:

filename="$(basename $1)" 
extension="${filename##*.}" 
basename="${filename%.*}" 
while [[ -e $HOME/.Trash/"$filename" ]]
do
  filename="$basename$(/bin/date +%l.%M.%S\ %p).$extension" 
done
/bin/mv "$1" $HOME/.Trash/"$filename"

I’ll save you the trouble: in short, that replicates the Finder’s “move file to trash” behavior. It tries to delete the file, but if there’s already a file with the same name in the trash, it’ll append a timestamp to create a unique name. I use a similar script in my rm function.

All in all, this workflow fits me pretty well. I don’t have to worry as much about clearing off my desktop (which I do anyway, constantly) or going through my downloads folder, and if I ever find I’m missing a file, I always know where to look.

If you’re interested in taking a deeper look into this Hazel ruleset, I encourage you to download it and try it out for yourself, here.

The Great Internet Switchboard

A few weeks ago, I ordered a new pair of headphones, the BrainWAVZ (pronounced like ‘brainwaves’) HM5s. They’re great headphones, and I like them a lot. But this isn’t about the headphones. This is about why and how I got them, and about what I saw along the way.

I’m a real geek at heart, and very much a perfectionist. I like knowing I have the best of whatever my money can buy, even if I don’t necessarily need it. Before I buy almost anything, I’ll read reviews of it, product descriptions, press releases, whatever I can to know as much about the product as possible. I compare it to similar products — can I buy something better? If I find I can spend just a bit more money to get something better, I’ll do that. If I can find something for cheaper, even better. I put more research into buying pens than most people would into buying television sets or phones. That’s just part of me; an obsessive, perfection-seeking part of me.

And that bleeds into other parts of my life. I love listening to music, and have ever since I was a child. I listen to music daily — while on public transportation, while taking a walk, while doing homework, and while studying for tests. Since music is such a big part of my life, it just has to be perfect. It would pain me to own low-quality music. Seeing a number lower than 320kbps MP3 or 256kbps AAC in my iTunes library bothers me deeply and I try to do my best to ignore whatever music I wasn’t able to get in perfect form. I download FLAC when I can, and I’m grateful the iTunes store stepped its quality up to 256kbps. Mind you, it’s not necessarily that I can tell the difference between 192kbps MP3 and lossless, but it’s just knowing that I don’t have the best thing that bothers me.

I own a set of Bowers & Wilkins P5s (note: affiliate link), bought at an Apple store, and they’ve been quite good to me. They’re swell headphones: portable, comfortable, and stylish. But after three years, they’ve started to show some wear and tear, it was starting to bug me that I had paid so much money for them ($300) without doing that much research. They sounded pretty good to me, but maybe it was time to replace them. Could I have gotten something better for cheaper? Down the rabbit hole I went, in search of my answer.

Let me skip to the end here, for a while, and say this. What I found astounded me. Not at all because I found a better set of headphones, but because of this: while searching for something so mundane as a new set of headphones, I took a step back and tried to look at the bigger picture — of what I was doing, and how I was doing it. And it amazed me. As a geek, as someone who knows how to use computers and the internet, as someone who’s not content to amble down to the nearest RadioShack (if there even is one anymore) and buy the first pair of headphones I see, it really blew my mind to take a look at my process. To see what I could access.

I very quickly ended up on a website called Head-Fi that features a large forum of audiophiles and headphone lovers, full of reviews and pictures and questions and impressions. It’s a huge community of the very people who knew all about what it is I wanted to know. So I looked around, hunting for the information I wanted. And boy did I find it.

For any product category you’re looking for, there’s a huge array of products that are readily and publicly available — I’m sure that anyone looking for headphones would arrive at Bose or Sennheiser pretty quickly, and they’d be pretty content overpaying for their headphones without worrying about it at all. But there are larger, outer rings of products that are harder to find, that aren’t always listed on Amazon, that you won’t find on your own. It’s a sort of gray area, full of products on some somewhat shady-looking websites that my mother would be wary of purchasing from. Almost like the outskirts of a large industrial city. This is where the real fans hang out. The real products are here: the really, really good stuff. After a lot of research, I’d made my selection, made the order, and waited six weeks to get my headphones.

Twenty years ago, there’d be no way I’d get a pair of BrainWAVZ HM5s (which have now made their way to Amazon). I wouldn’t have heard about them, wouldn’t have found them, and wouldn’t have even known they existed. I wouldn’t have known where to look for them, or even to start looking for them. Twenty years ago, I wouldn’t have found Head-Fi. I wouldn’t have found the community built around loving and appreciating headphones. Without Google or search engines, I doubt I even would have bothered looking for anything other than what I had, because short of asking around or finding a local store that carried headphones, there wouldn’t have even been a way to do what I did in the course of a few days.

And that’s what amazed me. Man is it a good time to be a geek. To be someone who knows how to use the internet, and search engines, properly. Who can let their curiosity lead them to the darkest corners of the internet. Because being able to do that is like having a key to every door out there. It’s like being in control of the largest switchboard in the world. You want to tap in to the world of headphones? No problem. Not only does that exist, but you can find it and get to it. You want to find a group of people who are enthusiastic about animals? Here you go. That’s not even a specific enough query anymore, because there are so many subcategories of these groups that it boggles the mind. You can get anywhere you want. It reminds me of the scene in the Matrix where the Keymaker is taking Neo to the Source — there are infinite doors and portals you can walk through, and you’ve got the keys to all of them.

So, where do you want to go?

Redux

Before this post existed, there was a blog with a different design running on itaiferber.net. Before that, I had a small (and quite empty) portfolio site running on itaiferber.com (prior to foolishly lost the domain). Before that, I tried maintaining a Tumblr blog, and before that, a WordPress one. Somehow, I manage to keep trying my best to create blogs, abandon them after one or two test posts, delete them in embarrassment, and then repeat the whole process. I might just hold some kind of record for being one of the most persistent failed website owners. Like clockwork, every couple of months over the last couple of years, I’ve gotten an Idea (capitalized, because it was important), something I felt like I had a lot to say about, but no one to say it to, mostly because none of my friends are geeks, or like Macs, or care about pens, or really hold any interest in whatever silly topic I was wanting to gush about. So off to blogging about it I went.

When I started writing on itaiferber.net (which, to date, has housed an astonishing total of 4 blog posts), I was trying really hard to emulate some of my favorite writers (Shawn Blanc, Ben Brooks, Brett Terpstra, John Gruber). And I failed at it pretty hard too, because I was trying to write like people whose style I couldn’t match (not to mention people whose job it is to write, and who have the time to write as prolifically as they do). I had bought a website theme, set up my site as a Jekyll template, and started writing. And then, just as quickly, stopped. Because I didn’t have the time to write, and couldn’t live up to my own expectations. I don’t have the time or the energy to write 3 posts a day, or even 3 posts a week, or perhaps even 3 posts a month, and so I bummed myself out pretty quickly, and stopped altogether.

I’ve realized, though, that this outlet is important to me. Because really, there are some things I want to get out there. Some opinions I hold, some technical information I want to share. Things that I know no one will read (because now, with modern day site statistics, I can watch my site gather dust in real time!), but things that are important for me to say anyway. So this time around, I decided to go for a different approach. Instead of looking at the authors I like and trying to copy their site structure and layout and their content and their voice, I decided that I should copy myself. I should be my own favorite writer and author. My site should be designed as I would want to read it. So I cut out all the crap that wasn’t important, and outsourced information elsewhere. Want to see my portfolio? It’s on StackOverflow Careers. Looking for a colophon? There isn’t one. You can find me on Twitter and GitHub to easily to see things I’ve written or released. I’ve decided to focus on only what matters – my writing – because it’s what I’m looking to most improve. Most of all, for the first time, I’ve designed my site myself, from the ground up. It fits my criteria for a) looking nice, b) working on all my devices, in all their shapes and sizes, and c) having great typography. That’s what I care about, and that’s what I want to see.

I try not to sound like the “Sorry I Haven’t Updated Supercut” video, but it’s really refreshing, I think, to finally have something I designed myself, that works the way I want it. Besides, I’ve already got topics and content I want to write about. So, to the imaginary people I’m writing to write now, welcome, and stay tuned for some upcoming posts.