Category Archives: Freebie

Programming Puzzles and Our Mismatch Problem

In interviewing candidates for programming jobs, a common technique is to ask them to solve some programming puzzle. Makes sense, right? If the guy’s smart enough solve random silly questions, he’s probably good at programming, since that’s most of what programming is.

As it turns out, this bit of common sense is common bullshit. It’s just another mismatch problem, along with requiring elementary school teachers to have lots of formal education, cops to be big and strong, and law school applicants to have great grades in high school. It doesn’t predict success even a little.

A Tale of Two Coders

Feel free to skip to the fun stuff.

Let me tell you about two programmers I’ve worked with.

The first graduated from Stanford University in the top 10% of his class with a degree in Computer Science, and went on to get an Master of Science in the subject. He knew about B+ trees and maps. He could tell you what a directed acyclic graph was, and what it should be used for. He built an MVC system from scratch to design business cards in a web browser, 2 years before Ajax was “teh new hotness”. He interviewed well, and had a host of companies to choose from. He chose a job, and was one of the highest paid new hires in the history of the company.

The second graduated from high school, and had absolutely no intentions of ever taking classes again if he could help it. Not sure what to do with his life, he worked at a local electronics store (Circuit City, I believe) for a few years. He’d messed around with computers plenty, programmed a bit, but nothing serious. A friend of his worked at a software company, and managed to get him a job, despite his lack of experience and education, and despite the fact that he interviewed terribly. He came in at the low end of the pay scale.

Who was the better programmer?

Since I tipped my hand by talking about the mismatch problem, you’re probably guessing that the second one was better. You’d be right. But I doubt you’d realize just HOW right you are.

Despite the fact that I think he deserves any reputation his lack of skill earns him in life, it strikes me as being in poor taste to name him here. Let’s call the first programmer “X”.

Over a year after X left the company, one of the other guys found that he could reliably predict and fix crazy strange bugs by searching for the guy’s initials in the codebase. (There was a fairly strict rule about commenting changes in existing code, which, thankfully, X followed.) I’m talking real bone-headed stuff like:

If Len(".837") = 3 Then

When is “.837” ever 3 characters?! To make matters worse, that If block was wrapping about 250 lines of code, some of it essential to our customers getting paid. X was clearly operating in some kind of alternate universe. Real DailyWTF type shit. And, he was the kind of asshat who was nearly impossible to work with. I mean, imagine any quality that a programmer needs to have, except for IQ, and he lacked it. He was arrogant, rude, passive aggressive, and lazy. He was a bully who would go out of his way to make people feel uncomfortable once he decided that he didn’t like them. Every design discussion was an Argument from Intimidation—-either you agreed with his idea and stroked his ego, or you were an idiot, plain and simple. He was good at (useless) puzzles, but his attention to detail in real work was beyond terrible.

Within 2 years at the company, the second guy—-the uneducated, inexperienced, bad interviewer—-was one of the go-to architects who really grokked how everything was supposed to work. He picked up Visual Basic fast enough to pass by most of the existing team, some of whom had been writing code since he was in high school. He was responsible for designing and implementing a part of the software that was the primary killer feature. He redesigned a huge chunk of the program that never quite worked right. He was in databases, in the presentation layer, and in between. By any estimation, a very significant portion of the product’s value was entirely his doing.

After we’d both left that place, I referred him to Yahoo. Despite not having very much experience in front-end web development, and again interviewing terribly, the hiring manager was wise enough to heed my very strong recommendation. And good thing, because he very quickly became one of the most important members of the Yahoo Games team. (And he occasionally reads this blog and comments on stuff. Hi, Geoff.)

So, at this point, you might be thinking, Well, if the super educated brainiacs are bad programmers, and the lazy hobbyists are good programmers, then we just need to flip the test around, and use it in reverse. Then we’ll find the Geoffs, and avoid the Xes.

If only it was that easy.

You see, there actually are quite a few very good programmers that are very good at silly puzzles and have degrees in Computer Science. Almost every problem has some kind of mathematical component; a lot of the theories were discovered because they’re true and relevant. Some of X’s abilities are quite useful, so having both the will and the skill is best. The hobbyists eventually find that they have to hit the books and learn theory at some point, or else they get passed by.

But those skills aren’t nearly as useful or predictive of programming ability as we might think. Geoff has the attitude of a great hacker and a mind that is capable of learning quickly, which, as it turns out, is much more useful in the long run, and much harder to test for. X had a big brain and a bad attitude. Most of programming is not solving puzzles with algorithms. Most of programming is communication, attention to detail, and a relentless desire to build something beautiful.

Some Puzzles

Despite the fact that programming puzzles are almost 100% useless in the hiring process, they’re fun, and a good mental work-out to keep your thinking sharp. They’re a good part of a practice regimen. Here are a few that I’ve come across lately that were pretty interesting. (Sadly, my beliefs about the foolishness of puzzles-as-hiring-tool are not shared by all of my managers, and I learned about two of these because they are used in our interview process.)

I’ll edit this post to include solutions later. I didn’t make up any of these, but I did revise them somewhat. The goal in each of them is to devise a program or algorithm that will find a solution in the least number of steps/iterations/whatever.

Square the Sum

For all 6-digit numbers from 100000 to 999999, find the numbers that, if you add the top three digits to the bottom three digits, and square the result, it will equal the original number.

For example, for 123456, you’d add 123 and 456, which equals 579. Then, square that sum, which yields 579 * 579 = 335241. 335241 ≠ 123456, so 123456 is not in the set.

Dropping Eggs

Let’s say that you have 2 eggs, and a building that is 100 floors tall. You need to figure out how high up you have to drop the egg to have it break when it hits the pavement. Assume that the egg either breaks completely or is completely undamaged. That is, repeatedly dropping from the second floor will not make it more likely to break. (Hypothetical eggs are very hard, but when they break, they really BREAK.)

For example, if you drop the egg from floor #50 or below, it won’t break. But if you drop it from floor #51 or above, it will break.

What is the optimal approach to testing floors? Assuming that you take that approach, and the egg breaks on the last floor you test, how many times did you have to drop it?

Part 2

As the number of floors n increases to a very large number (millions, billions, whatever—-since it’s really not floors and eggs but a sorted database of records or something), how does your solution scale?

Let’s say that you have 3 eggs. What’s the value now?

As the number of eggs increases, how does the worst-case number of tests change? If you had an unlimited supply of eggs, is there a better solution?

I heard this one at work, and it sounded kind of familiar, but I didn’t remember the solution right away. I dug up my textbook from “CSC212: Data Structures and Algorithm Analysis”, and sure enough, it was one of the examples Dr. Sayed used to teach us big-O notation.

Non-Repeating Digits (Cedric’s Challenge, slightly revised)

Find the count of all natural numbers below a certain number of digits that have no repeated digits. For example, for length=2, the following numbers all satisfy: 10, 12, 21, 23, 32, 34; but these don’t: 11, 22, 33. For length=3, 97 and 102 are valid, but 99, 100, and 101 are not.

Additionally, find the two consecutive numbers that are furthest from one another, and the difference between them. For example, in the length=3 case, the greatest difference between two consecutive numbers is 4, between 98 and 102.

For example, in length=2, there are 90 matches. (1-99, except for 11,22,33,44,55,66,77,88,99.) The biggest jump between two consecutive numbers is 2, between 10 and 12.

Part 2

In addition to specifying the length in digits, also make the base variable. For example, in the (base=3,length=3) set, the following numbers are valid: 10, 12, 20, 21, 102, 201.

Compute the values for length=100,base=1000. Speed matters.

Part 3 (Cedric’s Challenge + arbitrary bases)

Print all the numbers in order before printing the count and difference. (Hint: if this doesn’t make it any more complicated, then you didn’t do parts 1 and 2 properly.)

Since the base can be arbitrarily high, express numbers in bases greater than 10 as a comma-delimited tuple rather than using character digits, optionally with a trailing comma. For example, the base-16 number normally written as “FA9” could be printed as either “15,10,9,” or “15,10,9”.

Hacking the Google Favicon

There’s been a lot of nerd rage about the new google favicon. I joined in with a rationalization for my distaste for their new design. After a few days of the lower-case “g” on a gray background, I decided today that I just couldn’t take it. Here’s how I fixed it, so my Mac shows the old logo.

Certainly, any company ought to think long and hard about any branding change so fundamental and wide-reaching as a change in logo. If you’re a web company, then your favicon IS your logo, and everything else is secondary. For Google’s sake, I sure hope they understand just how significant this change was, and weighed the pros and cons carefully.

While I recognize my position deep in peanut-gallery territory, I simply cannot accept that it was a good move. A favicon needs to be:

  1. Far from gray. Browser tabs are gray, and the purpose of a favicon is to let the faster right-brain processes identify your site in a list of tabs or bookmarks. If I can’t see it, it’s useless. FAIL
  2. Mostly not transparent. If you’re going to use a gray logo, fine. Put it on a white background, so you know it will stand out. A small logo in a transparent background is invisible. FAIL
  3. Evoke your corporate branding. I should be able to associate your favicon with your brand without thinking about it. If, for example, your corporate branding is focused on lots of bright colors on a white background, your favicon should echo this. FAIL
  4. Use big, simple shapes. Fine details (like those in the double-curl style of lower-case “g”) get lost at 16x16 size. FAIL

Poor contrast.  Not enough pixels.  Not "google" enough.  Prettier - Who cares?  FAIL

Yahoo and Google are effectively equivalent in terms of the objective quality of their search results. Scores of user-studies have shown that our perception in SERP quality is due primarily to brand loyalty and nothing else. If you’re a Yahoo searcher, and you see a red Y, your comfort filter tells you it’s good, no matter where the results actually came from. You can’t tell the difference, because, for the most part, there isn’t one. Most of the time, Yahoo and Google search pull up exactly the same sites, or close to it. They’re both very very good, and search is a case where there is a right answer, even if the method of finding it is a bit fuzzy.

For some searches, it seems that Yahoo is even significantly better than Google. Compare for yourself. Somewhat humorously, the results for “yahoo is better than google” seems to yield much better results on Yahoo. I tried the reverse search, expecting to see some kind of amusing self-bias, but actually Yahoo did that better, too. From my cursory non-scientific view, it seems like Yahoo puts a bit more weight on the title, and there are probably other slight differences. But the point is, the differences are slight enough to be overlooked. They’re both pretty damn good at finding what you ask for.

I work at Yahoo. But I use Google for search. I perhaps ought to bleed a little more purple than I do. I also own stock in Yahoo, so in a small way, using Google for search is not a financially rational move. So why do I do it?

Brand loyalty. I was using Google ever since it’s been around, and I’ll probably keep using it for a long time. I imprinted early on that big G in the white square, and some very low-level neural systems tell me loud and proud that, when it comes to searching, that G means Good. Frankly, rewiring all that stuff isn’t worth the effort.

I think that brand loyalty explains a lot of the nerd rage over the new favicon. Yes, it doesn’t affect the results. Yes, it’s just a case of cheese moving, and not even a very relevant one. And, face it, you’re not going to stop using Google over it if you’re already a Google user. But you may be consistently annoyed for several months while the brain circuits rewire themselves to imprint on the new design.

Unacceptable. I’m a web geek. I’m a hacker. There is no way in hell that I should have to put up with something I find even slightly distasteful in my regular internet experience. I refuse to be subjected to some marketing exec’s idea of what is best for me, when I clearly know my needs better. I don’t even care if he went to Stanford AND coded a rocket ship in Python.

Warning

If you use any Google services that require a login (such as GMail, Groups, Orkut, or pretty much anything other than Search), then you’ll need Apache 2. I tried really hard to make it work with Apache 1.3, but no dice.

The good news is, Apache 2 comes standard with Leopard. The bad news is, it doesn’t come standard with Tiger.

Since I was using Tiger, and Apache 1.3, this was a much more involved hack than I’d anticipated going in. Luckily, it’s just a matter of change one line in the /etc/hosts file to turn it off, which is good, because I had other things to do before I could fix it. I use MacPorts for a bunch of stuff, so I figured I’d just install Apache 2 that way.

Easier said than done, at least in my case.

I already had PHP and MySQL running a local copy of this site, and some other stuff. MacPorts really shines if you use it for everything—-try to run Apache on MacPorts and run PHP and MySQL from some other location, and you’re in for a world of hurt. It took a lot of SFTW and learning about reconfiguring to get it all working properly.

I’m not the best guy in the world to critique package management systems, but I’ve got some end-user experience. I use apt-get on my web server, MacPorts on my laptop, and of course, yinst on all the Yahoo! machines I work on. Of course, that’s not counting the Registry and Add/Remove programs dialog from Windows Land (which is hell), and the much more user-friendly “Applications” folder on the Mac (which is lovely, but not really a full-featured package manager). Of these, yinst is the best, hands down. Powerful, simple, effective, and sadly, 100% closed-source and proprietary. If you’re not at Yahoo, you’re not using yinst.

But enough about installing stuff. Long story short, you need Apache 2, or don’t go any further. If you primarily use Firefox, you can just follow Paul’s advice, and install this Greasemonkey script.

I still recommend doing this, especially if you write code for the web, and you’re not normally a “back end guy”. It’s good to tinker with this stuff, and even break it once in a while in your own little sandbox. Unless you tinker, you never learn anything new. Newton did revolutionary work in optics, largely motivated by his need for a better telescope to look at the planets. It’s good to have a working knowledge of the tools of your trade, even if they’re just a means to an end.

So, fixing the G favicon…

mod_proxy to the rescue!

The premise of this hack is pretty simple:

  1. Edit the /etc/hosts file to point “www.google.com” to your local machine.
  2. Use mod_proxy to transparently send all requests for “www.google.com” on to Google’s actual IP address, except for /favicon.ico
  3. Point /favicon.ico at the old favicon file, sitting on your local machine.

The interesting thing is that you can do this for any file or url out there that you want to swap in your local machine. Don’t like the favicon that a given site uses? Change it! You have the power! That’s the beauty of the web.

Prereqs

For this hack, you’ll need:

Apache 2 with mod_proxy, mod_ssl, and mod_rewrite

If you have a Mac with Leopard and the developer tools stuff on it, you probably already have this, and might just need to enable them. I’ll tell you how.

If you don’t already have Apache 2 and/or mod_proxy installed, then that’s outside the scope of this post, like I said above. Sorry.

About 15 30 minutes

Yes, it’s really that easy. It’s fairly easy, but a bit trickier than I’d originally thought.

I use a Mac, and these instructions are fairly mac-centric. If you use a Linux or Unix machine, then most of it will still make sense. If you use a Windows machine, then a lot of it won’t apply, but the basic idea should still be possible if you use Apache and install mod_proxy.

Some Apache setups install the Apache Control script as apache2ctl, and others call it apachectl. Since I used MacPorts, I’ve got apachectl on my machine. Substitute as required for your setup.

If you run into any sticky points you can’t get out of, post a comment. I’d like to hear it. If you run into any sticky points and DO get out of it, then definitely post a comment! I’ll update this post with your info.

Get the old favicon

I couldn’t find the actual ico file, but I found some screenshots on the internet talking about the favicon change. I got a pretty good png, and lifted out just the 16x16 piece from the address bar in the screenshot.

Then, I used png2ico to convert that png to an ico file. It’s a great tool that I use all the time to make favicons. It lets you embed multiple pngs into the ico, but in this case, all that I really care about is the 16x16 that shows up in my address bar and on the tabs in Firefox and Safari.

All in all, that took probably less than 10 minutes. But you can do this step even faster by just downloading the Old Google Favicon. Extract it in Terminal or iTerm by doing this:

tar -xzvf old-google-favicon.tgz

You’ll get a file called old-google-favicon.ico. Put that under the “Sites” folder in your home directory. If you just un-tarred it using the command above, then it would be:

mv old-google-favicon.ico ~/Sites/

Turn on Apache

If you already run web pages and whatnot on your local machine, then you are already set. Skip to the next step.

To see if Apache is running, fire up a web browser and go to localhost. If you see the default Apache startup screen, then you’re all set. If it redirects to localhost.com or a web search, or you get a “could not connect to server” message, then you need to enable Apache.

If you’re running Leopard, open up System Preferences, and click on Sharing. Click the little lock in the lower-left corner, and enter your password. Check “Personal Web Sharing”.

Try hitting localhost again. If it still doesn’t work, then do this in a terminal:

sudo apachectl graceful

If that doesn’t work, try:

sudo apache2ctl graceful

If it’s still not working, sorry, don’t know what to tell ya. Good luck.

Test

At this point, you should be able to see the desired favicon at http://localhost/~YOUR_USER_NAME/old-google-favicon.ico, where YOUR_USER_NAME is the username that you log in with. (If you’re not sure what that is, open up a terminal, and type whoami, and it’ll tell you.)

If you’ve configured Apache to have some different document root, then adjust the path accordingly. For example, since my Mac is effectively a single-user machine, I just have the default document root pointed at /Users/isaacs/Sites/, so the favicon is at http://localhost/old-google-favicon.ico. Your setup may vary.

Ultimately, it doesn’t much matter where you put it, since we’ll be telling Apache exactly where to find it later.

Enable Apache Modules

Fire up your favorite text editor, and open your httpd.conf. By default, this file is in /etc/httpd/ or /etc/apache2/; if you installed with MacPorts, then it’s in /opt/local/etc/apache2/. (You’ll have to save it as the super-user, since it’s a root-owned file, so that means vi and emacs users will have to open it with sudo. GUI editors will usually prompt for your password when you try to save the file.)

Each of these lines have to be in there somewhere. If they’re missing, add them. If they’re commented-out, un-comment them.

LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_connect_module modules/mod_proxy_connect.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule ssl_module modules/mod_ssl.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so LoadModule rewrite_module modules/mod_rewrite.so

If you notice that these rules look “out of place” for the stuff that’s already there, then modify to match. For example, if the other rules are all loading the .so files out of “libexec”, then change “modules” to “libexec”.

Restart apache by running this command in a terminal:

sudo apachectl graceful

If it tells you that the server couldn’t be restarted, try this to get a more helpful error message:

sudo apachectl configtest

If it’s not working, sorry, don’t know what to tell ya. You may need to install some of the required modules using the apxs utility.

SSL

Because we’ll be proxying an SSL (ie, https://…) connection, your server will have to be able to do SSL so that it can maintain the level of encryption.

I followed these instructions to create SSL keys. It directs you towards a sign.sh script, and finding that was a bit tricky. For your convenience, I’ve provided it here.

Also, I put the ssl.key folder in the same folder as the other Apache stuff, the location of the ServerRoot directive. That way, I can refer to it by a relative path. If you prefer to have it in a separate location, that’s fine, but you’ll need to refer to it by the complete path in the configs below.

Get Google’s IP Addresses

In a terminal, run this:

nslookup www.google.com

You’re looking for the “Address” lines, not the “Server” line. In my bash profile, I have a handy shortcut for this, so I just type getip www.google.com to see the results from both nslookup and ping.

Make a note of those IP addresses. As of this writing, from my location, I got these:

66.249.89.104 66.249.89.147 66.249.89.99

We’re actually going to define a load balancer to distribute your requests between these three. While that’s probably overkill, part of the benefit of this is educational, and that’s what a proxy would normally do.

Host File

Open up your /etc/hosts file in a text editor, and add this line:

127.0.0.1 www.google.com

Then, in a terminal, run this command to refresh your IP caches:

lookupd -flushcache

Bring up www.google.com in a web browser, and you should be looking at that default Apache page again. If so, you’re on track. If not, figure out what went wrong. You can see if Apache is in trouble by running this command and then hitting the url again:

tail -f /var/log/apache2/error_log

MacPorts users: tail -f /opt/local/apache2/logs/error_log

You may need to comment that line out with a # and do the lookupd -flushcache if you want to search google while doing this. Or you could just use Yahoo! Search temporarily. Maybe in the process, you’ll get used to Yahoo search and even find that you like it better. (See? I’m a good little purple-blooded corporate monkey!)

Set up mod_proxy

So, now let’s take your new and un-improved www.google.com, and turn it into a proxy for the actual www.google.com.

If you have a separate conf file where you keep your Apache customizations (which I highly recommend), then add this stuff in there. If you don’t, then you can just add it to /etc/httpd/httpd.conf or /etc/apache2/httpd.conf or /opt/local/apache2/conf/httpd.conf. Either way should work, as long as Apache finds out about it somehow.

Stuff that you may need to change wrapped in strong tags.

#google proxy stuff Listen 443 SSLPassPhraseDialog builtin SSLSessionCache dbm:/var/run/ssl_scache SSLMutex file:/var/run/ssl_mutex SSLRandomSeed startup builtin <VirtualHost :80> # the place where you put the .ico file. DocumentRoot /Users/isaacs/Sites/ ProxyPreserveHost On ProxyRequests Off ServerName www.google.com <LocationMatch .> Order deny,allow Allow from 127.0.0.1 </LocationMatch> SSLProtocol all -SSLv2 SSLSessionCacheTimeout 300 AllowCONNECT 443 563 80 SSLEngine on # enable SSLv3 but not SSLv2 SSLProtocol all -SSLv2 SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL SSLCertificateFile ssl.key/server.crt SSLCertificateKeyFile ssl.key/server.key # correction for browsers that don't always handle SSL connections well # You don't really use MSIE on your own machine, though, do you?? SetEnvIf User-Agent ".MSIE." \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 SSLProxyEngine on <Proxy balancer://googlecluster> # the IP addresses you fetched before. BalancerMember http://66.249.89.104 BalancerMember http://66.249.89.147 BalancerMember http://66.249.89.99 </Proxy> # Browsing History seemed broken unless it proxies back to https. # This is probably safer anyhow, for privacy. ProxyPass /history https://www.google.com/history ProxyPassReverse /history https://www.google.com/history RewriteEngine On RewriteRule /favicon.ico /old-google-favicon.ico [L] ProxyPass / balancer://googlecluster/ </VirtualHost> <VirtualHost :443> # the place where you put the .ico file. DocumentRoot /Users/isaacs/Sites/ ProxyPreserveHost On ProxyRequests Off ServerName www.google.com <LocationMatch .> Order deny,allow Allow from 127.0.0.1 </LocationMatch> <Proxy balancer://googlecluster> # the IP addresses you fetched before. # note the "https" on these ones. BalancerMember https://66.249.89.104 BalancerMember https://66.249.89.147 BalancerMember https://66.249.89.99 </Proxy> SSLProtocol all -SSLv2 SSLSessionCacheTimeout 300 AllowCONNECT 443 563 80 SSLEngine on # enable SSLv3 but not SSLv2 SSLProtocol all -SSLv2 SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL SSLCertificateFile ssl.key/server.crt SSLCertificateKeyFile ssl.key/server.key # correction for browsers that don't always handle SSL connections well # You don't really use MSIE on your own machine, though, do you?? SetEnvIf User-Agent ".MSIE." \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 SSLProxyEngine on RewriteEngine On RewriteRule /favicon.ico /old-google-favicon.ico [L] ProxyPass / balancer://googlecluster/ </VirtualHost>

Save the file, and then restart Apache:

sudo apachectl graceful

Again, if it doesn’t work, try this to figure out what’s wrong:

sudo apachectl configtest

Test

Now, go to www.google.com. You should see the google home page, complete with the old lovable [G] favicon. If you see google, but not the old favicon, go directly to the favicon.ico and refresh a whole bunch. Clear your cache, etc.

If you get the new favicon, try running some tests. Search, go to your account. Make sure everything works.

When you hit an https address, you’ll get a prompt that the certificate is issued by an untrusted authority. This is good! Check the cert details, and make sure that they’re what you typed when you created the certificate. Now, the question, do you trust yourself? (I’d already added myself as a trusted authority, so didn’t get this problem in Firefox, but I did see it in Safari.)

If it doesn’t show you the new favicon, then you might have put the virtual host config someplace where it doesn’t belong, or where it won’t be picked up. Tail the error_log file and see if Apache tells you anything is wrong. Note that some Apache configurations use “apache.conf” instead of “httpd.conf”, so maybe try that.

If it doesn’t load at all, tail the apache logs again, and see if anything is barfing.

Done

You may now resume your google usage as normal, before the disruptive new favicon appeared.

Note: The Google Notifier won’t work, because it checks the certificate, and doesn’t give you the option to trust another authority, which is, in my opinion, very bad design. Also, the Google Notifier sends your password and username out in clear text by default, so it’s very insecure. You shouldn’t be using it in the first place.

Instead, you can use the RSS feed to get inbox alerts without exposing your info.

Steal My Bash Profile

Feel free to skip the monologue and just get the goodies.

I am in love with the Bourne Again Shell. Bash is a fantastic terminal environment, and a very interesting programming language in its own right.

I grew up using DOS. Unix shells always seemed scary and foreign, for some reason. I think a big part of the reason that I stayed on Windows for as long as I did was that I knew DOS, and could always resort to it in times of need. As a support tech in college, I got very familiar with DOS. It was comfortable and handy.

When I got into web programming, I had no choice but to learn at least the rudimentary basics of a unix-style environment. At that time, I was as a support tech at a software company whose product uses VisualBasic ASP over IIS, and had started playing around in that environment. However, I had no money, and web hosts that support ASP cost money.

By some stroke of luck or persistence, I managed to find a host that was free, Beigetower. That link doesn’t work any more, of course. I don’t know how long that server’s been down. Cuong Nghiem’s still listed as the owner on whois, though.) On top of that, they provided shell access. Not being able to resist the temptation to tinker with a real live web server, I learned enough Bash to poke around. As I learned more PHP, I picked up more bits and pieces along the way.

When I started at Yahoo, it was sink or swim to some extent. I was issued a FreeBSD dev box, and a windows desktop. I did most of my development in my safe windows world, but there are a lot of things you have to do on your dev box as an engineer at Yahoo that simply can’t be done in any other way. Bash was a regular part of my daily routine almost from the first day.

Eventually, I fell so head over heels in love with Bash that I had to say goodbye to Windows and get a Mac.

There are many good reasons to get a Mac instead of a PC. They’re easier and more intuitive in a lot of ways. They certainly look a lot nicer on almost every level. But I’d be lying if I said that having Bash right there all the time wasn’t the ultimate dealmaker.

One of the best things about Bash, in my opinion, is the fact that you can add shortcuts to your .profile (or .bash_profile or .bashrc, of course) that will be loaded every time you log in. As soon as I learned this, I started adding stuff.

Eventually, I had my profile so tricked out that it was hideously painful to have to work on a machine that didn’t have my shortcuts. Without my customized prompt, I’d get really confused about which directory I was currently in, and have to type pwd every three seconds just to not get lost. The sequence would usually go like this:

$ la -bash: la: command not found $ la -bash: la: command not found $ la -bash: la: command not found $ alias la="ls -laF"

Those first few entries of la were accompanied by plenty of growling and confusion, every. single. time.

So, I got into the habit of using scp or rsync to send my bash profile to any machine that I’d have to work on. However, some machines have vi, and some don’t. I’d make a change on the profile on my mac, and forget to sync it to my dev box. Machines that I didn’t log into often would be so far out of date that it was the “la” situation all over again. What’s worse, I put some stuff in other shell script files that were called by the profile to do other things, so it was no longer straightforward to keep them in sync. I’d send half the package, and then log in, and be inundated with errors all over the place.

When I switched from FreeBSD to a Red Hat Linux box, half my stuff didn’t work quite the same way. Also, I moved Foo Hack to a great new host, which is running Ubuntu. On the Mac, I use MacPorts, and the Ubuntu slice uses apt-get, and the RHEL of course uses yinst, the Yahoo! package management tool that quite simply makes all others look like crap by comparison. (Sadly, yinst is not open source. There’s this hack to simulate yinst on top of apt, though.) The Ubuntu and RHEL environments used vi as the default editor, but I’d changed that on the Mac to point to mate, the command-line interface to TextMate.

To say the least, a simple sync wasn’t cutting it even a little.

I re-wrote all my bash profile goodies to fit in a single file. Shell scripts were replaced with functions so that they could all live together. The edit command was defined to use the first available editor from a list of alternatives. Then, I put it in a file that was external from the main .profile or .bashrc file, so that it could be synced without overwriting anything that the OS placed in there by default. The only thing to do on a new server was to add . ~/.extra.bashrc to the bottom of whatever profile script it was already using.

I had already added a command called editprof that would bring my profile up in an editor. All that was needed then was a pushprof command that would rsync the .extra.bashrc file to a given host.

I’m releasing it under the WTFPL. There are actually a few files, since some stuff simply didn’t make any sense to have in certain environments. The copy here on foohack.com on github is symlinked from my home directory updated frequently, so it’ll stay pretty up to date. Feel free to copy, learn, fork, or, like the license says, just do wtf you like with it.

A word of warning: like government regulation, this file increases in size but rarely gets revised. Some stuff may be completely useless or pointless. Some of it I hardly ever use any more. Figuring out better solutions to these problems is left as an exercise for the reader.

Get my bash extras.

Open in TextMate in Finder for Tiger

This post has a great little droplet that can be added to the Finder toolbar to open either the selected items or the current Finder folder in TextMate.

Sadly, it doesn’t work in Tiger, and I haven’t made the jump to Leopard yet. If you’re a TextMate user who’s still on Tiger, and wants this feature, I tweaked Henrik’s AppleScript to play nice with Tiger.

Open in TextMate (for Tiger)

Enjoy!

Update: Just fixed the script to work with folders and files that have spaces in the name.

CSS Modal Dialog that Works Right

Note: This method has a few problems. Scrolling breaks on the iPhone, and the test page has some issues with tabbing through links. See my comment below. A new version will be posted soon. —i

In my last post, I touched on a method to get different browsers to handle the inline-block display style. I decided to use that on a project that I’m working on now that has a few modal dialogs.

Feel free to skip all this and go straight to the example.

In the application world, creating a modal is pretty straightforward. Here are some features that every modal window should have:

  1. Interaction with the contents of the parent window should be *impossible* until the modal is dealt with. Scroll-mouse should not scroll the background page, clicking should not click the background page, tabbing should not get you there, etc.
  2. When you dismiss the modal, the parent window should be *exactly* how you left it.
  3. The parent window should be dimmed, or there should be some other indicator that it is currently not available for interaction. This has the corollary effect of making the modal “pop” a bit more.
  4. In a web page, a modal should be constrained within the viewport. Opening a new window just to show a dialog box is ugly as a bucket of slugs.
  5. The modal should be placed consistently. If it is not movable, then it should be centered vertically and horizontally. This positioning should be consistent if the parent window is resized or moved.
  6. The modal should be smaller than the parent window. If the viewport is resized smaller than the modal, then scrollbars should appear that allow the user to see the rest of the modal.

The rule of thumb: The modal should be visible always and in every situation, the parent should be dimmed and preserved. Almost every modal dialog I could find online broke a few of these rules.

In some, the html and body elements have their overflow set to hidden when the modal is shown, so the current scroll position of those elements is lost. If you were looking through a list of items, and you brought up a modal dialog related to one of them, then you’re back to the start of the list when the modal is dismissed. Annoying.

In others, you CAN scroll the background, but the modal is set to respond to the onscroll event to try to stay in place. Some of the time, they use display:fixed to behave a little nicer in non-IE browsers. At worse, you get a jumpy seizure-inducing experience; at best, you accidentally scroll the background and lose your place without realizing it.

It’s a bit of an edge case, but you do have to handle cases where the modal might be taller/wider than the viewport. As a test, I tried resizing the viewport down on a bunch of modal approaches. Vertical centering often doesn’t do too well unless the contents are smaller than the viewport, so the top and bottom of the modal were cut off. Unacceptable.

It wasn’t terribly difficult to create one that obeyed these rules. Here’s the approach that I took.

  1. Build it with tables.
  2. Replace the tables with divs, and give them the appropriate display:table, display:table-cell CSS rules.
  3. Fret and hack to try to get it to work in IE, unsuccessfully.
  4. IM another yahoo who has a reputation for being a great webdev hacker.
  5. Adapt what he did to my needs.

For the non-IE browsers, it’s pretty straightforward. Take the scrollbars off of the HTML and BODY elements, and put them on #body instead. #modal is a sibling of #body, so when it is 100% height and width, it will cover it up. Then #modal will overlap the scrollbars of #body, without losing the scroll position. Also, that means there’s no need to do any trickery with a negative right margin to try (unsuccessfully, on the mac) to overlap the scrollbars.

Since .overlay element in the modal has a display:table, it will always expand to fit its contents. .overlay’s parent is overflow:auto, so if .overlay is too big, it’ll let you scroll to see the rest.

What this means is that you can’t cut off the top and bottom of the modal. It’ll be vertically centered if there’s room, and if not, it’ll be flush to the top and scrollable. Perfect.

For IE it gets trickier. Hedger’s example showed 2 great ideas, though. Basically, if you have 2 siblings that are display:inline-block, then, in IE at least, the line-block will expand to fit both of them. So, they both end up being vertically centered to the height of the taller child. If that taller element is width:0, then you essentially have an arbitrary line-height setter for the inline-block row. In this case, the height is set to 100%.

The other child will be whatever height it is based on its contents. If that happens to be taller than 100%, then the line-height will be taller than the viewport. At that point, the overflow:auto parent shows a scrollbar to let you see the rest. Identical behavior to the standards browsers!

The second problem arises with IE’s peculiarities when it comes to percentage heights. For whatever reason, if you have a position:absolute element, it doesn’t like to do height:100% unless some parent has a fixed height value, like 500px. 100% of 100% doesn’t compute, for some reason. Sadly, that means that the element that does the overlay wouldn’t be able to properly do its job in IE. So, instead of using a separate transparent layer with a background image, Hedger used the DXImageTransform.Microsoft.gradient filter on the modal container itself. However, since the gradient filter doesn’t actually prevent interaction with the background, I added a 1 pixel transparent gif as the background image.

I’d very much like to not use this transparent pixel. It feels a bit like a spacer gif to me. But, all in all, it’s a pretty small price to pay.

I didn’t bother to tackle the tab-order focus stuff in this little test page, since I wanted to just isolate the stylistic stuff to get it working across browsers. However, it would be good to put a focus handler on #body, and any time a #body element gets focus, focus the #modal instead. That way, once you tab off the modal dialog, you’d get right back onto it. In the spirit of being friendly to keyboard users, it would also be a good idea to keep track of the currently focused element when the modal opens, and go back to it once the dialog closes.

Here it is for your view-source pleasure.

Please please feel free use this modal. Life is too short to futz around trying to see the “cancel” button that is hiding off the screen so you can go back to reading your page.

Let me know if you can think of any enhancements or find any problems with it. Those of you in the US, I hope you had a great Thanksgiving.

Update

I updated it to add support for focus and blur events. It works in Firefox, MSIE, and Safari. Opera on the Mac has some really strange behavior regarding focusing on links, and I decided that it just wasn’t salvageable. Safari requires a bit of hacking to get the focus stuff to work properly, but I think it’s acceptable.