Dallas police officer Robert Powell is a jackass (and probably racist)

From the Dallas Morning News:

Jackass “officer” pulls his gun during a traffic stop, then takes 13 minutes to write a ticket. Oh yeah, Moats’ mother-in-law died while he waited for the ticket to be written.

Kunkle said Officer Robert Powell has been placed on paid administrative leave in connection with an incident last week in which he stopped a family rushing to visit a dying mother, detaining them for 13 minutes to write a traffic ticket.

During the traffic stop, caught on the officer’s in-car camera, Powell berated the driver, 26-year-old NFL running back Ryan Moats, and threatened him with arrest for running a traffic light.

“I can screw you over,” said Powell, 25. “I’d rather not do that.”

Powell drew his gun and yelled at her to get back in.

Moats and Collinsworth’s father went into the hospital, where they found Collinsworth had died, with her daughter at her side.

HOWTO deploy PHP sites with Capistrano 2

When I learned Ruby on Rails, I found out about Capistrano. This whole automated deployment thing seemed pretty neat. But then my Rails project finished, and I was back to working on a PHP site. There I was, coding along in naive bliss.

Then I started working on voteforchange.com for the Obama Campaign. Nick and I didn’t have the biggest iron or the most … process. But we did have Capistrano for PHP.

A little light bulb went off in my head.

Heather’s sites were a great candidate for Capistrano deployments. I could stick everything in subversion … develop on my PowerBookMacBook Pro and deploy to the DreamHost web server. Professional deployment techniques for a site with an engineering team of one.

One thing was bothering me, though. The VFC Capistrano script was so much longer than the ones I was using for my Rails site. Longer. More complicated. Less elegant.

We were making our own folder structure:

t = Time.now
folder = "#{t.year}"+"#{t.month}"+"#{t.day}"+"#{t.hour}"+"#{t.min}"+"#{t.sec}"

Wasn’t Capistrano supposed to do that for me? Yes, it was. So I started looking around. Everyone was pointing at Jon Maddox’s instructions. Those were a good starting point, but I had to make a few changes. Here’s what I learned.

How to deploy PHP sites with Capistrano 2

  1. Cache your authentication credentials
  2. Configure Capistrano
  3. Run Capistrano’s initial setup
  4. deploy

Cache your authentication credentials

You’re going to want to set up passwordless authentication for both SSH and Subversion. Otherwise, you’ll get prompted every time you check in or deploy. (This also makes using TextMate‘s subversion bundle harder.)

  1. Cache your SSH credentials. Generate your keypair. On your local machine, do this:
    ssh-keygen -t rsa
    chmod -R 700 ~/.ssh
    

    Repeat this on the web and svn servers.

  2. Upload your public key from your local machine to the web (svn) server:

    ssh www.mysite.com "echo '`cat $HOME/.ssh/id_rsa.pub`' >> .ssh/authorized_keys"
    

    Do the same thing from the web server to the svn server.

  3. Often, your username on your local machine is not the same as your username on the subversion server. To tell subversion what name to use, edit ~/.ssh/config, adding lines like these:

    Host svn.mysite.com
          User joeblow
    Host www.mysite.com
          User joeblow
    

    Test this out by typing ssh www.mysite.com. If you still get prompted for a password, make sure the permissions are correct on the webserver (chmod -R 700 ~/.ssh).

  4. On the web server, cache the subversion credentials. Just check out the repository:
    svn co svn+ssh://svn.mysite.com/svn/mysite/trunk

    Enter your password when prompted. Subversion will cache this information in ~/.subversion/auth/. You can now delete the trunk directory.

Configure Capistrano

Normally, you prepare a project for Capistrano by typing capify. You don’t really need to do that for PHP sites, because you don’t need a two-part Capistrano script. Instead, just create a text file called Capfile that looks like this:

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }

set :use_sudo, false
set :home_path, "/var/www/mysitename"
set :checkout, "export"
set :repository, "svn+ssh://svn.mysite.com/svn/mysite/trunk"
role :web, "www.mysite.com"

namespace :deploy do
  task :restart do
  end
end

Run Capistrano’s initial setup

Run the Capistrano setup command: cap setup. This creates the releases/ and shared/ directories on the server.

Deploy

To get the site up, just run cap deploy.

Tips, tricks and notes

  1. Following DreamHost’s Capistrano instructions, I set use_sudo to false. On a shared hosting site, I didn’t have root. Duh. Why is this the default option on Capistrano? Dunno.
  2. You need to disable Capistrano’s restart task. Since we aren’t using Rails, there was no mongrel, and nothing to restart.

    So I tried this:

    task :restart do
    end
    

    I still got an error. It turns out you have to specify the Capistrano namespace:

    namespace :deploy do
      task :restart do
        #nothing
      end
    end
    
  3. What about database passwords for your web site? You don’t want to store those in the subversion repository. As the Cap FAQ explains, stick a configuration file elsewhere on the server, and copy in a post-deploy task.

    task :copy_database_configuration do
      run "cp #{home_path}/config/#{config_file} #{release_path}/helpers/config.php"
    end
    after "deploy:update_code", :copy_database_configuration
    
  4. If you’re developing with other people, having your SSH script prompt for your SSH username can be helpful:

    set(:user) { Capistrano::CLI.ui.ask("SSH username: ") }
    
  5. You can configure your script to do different work on staging versus production deployments. There are probably better ways to do this, but here’s what I have working for me. Suppose you have staging and production on the same server:

    if ENV['PRODUCTION']
      set :home_path, "/var/www/production"
    else
      set :home_path, "/var/www/stage"
    end
    

    By default, cap deploy deploys to stage. To deploy to production, run PRODUCTION=1 cap deploy (assuming bash).

  6. If you’re deploying WordPress, you will want to make sure the uploads directory is writeable. You might also want a special .htaccess file put in place (I use different ones for localhost and production). Here’s how to do this:

    task :after_symlink do
      run "cp #{current_path}/config/show_htaccess #{current_path}/.htaccess"
      run "chmod -R a+w #{current_path}/wp-content/uploads/"
    end
    

    Of course, your subversion deployment will overwrite your existing uploads directory, so this particular example is of limited value.

More details

Clayton Lengel-Zigich’s tips for using Capistrano with PHP and the Capistrano FAQ are very helpful.

HOWTO stop receiving phone books

You can call the following Yellow Pages producers to be removed from their lists:

  • AT&T/YellowPages (formerly SBC/Bellsouth): 800-792-2665 or 800-248-2800
  • Verizon (Idearc): 888-266-5965 or 800-888-8448 or 800-555-4833
  • Valley Yellow Pages: 800-350-8887
  • Dex: 877-243-8339
  • Yellow Book: 800-373-3280 or 800-373-2324 or 800-929-3556

You can also sign a petition to request that the Yellow Pages Association use an opt-in or at least create an opt-out registry.

A site called Yellow Pages Goes Green says they will do the legwork for you. I can’t vouch for them.

Apparently the Yellow Pages folks are really sktechy, hiring lobbyists to quelch opt-out movements.

HOWTO set the default target in Xcode

Your Xcode project has one or more targets. Each target builds something—a command-line tool, a framework or an application.

The Target popup menu lets you determine the active target. The active target gets built when you click “Build” or “Build & Go.”

But what about the default target? What is it, and why do you care? Well, if you build from the command line—using xcodebuild—the default target (and only the default target) gets built.

So how do you set it? I looked around in the help, and it wasn’t obvious. Turns out the answer is in the xcodebuild man page:

By default, xcodebuild builds the first target listed in your project, with the default build configuration. The order of the targets is a property of the project and is the same for all users of the project. The active target and active build configuration properties are set for each user of the project and can vary from user to user.

The default target is the first target listed. In this example, the default target and active target are the same — The “Palm Pre UI” Cocoa application:
before

Suppose we wanted to make the “Shell tool” command-line tool the default target. Simply drag it so it becomes the first item on the list:
during

Now we’re done. The active target is still the “Palm Pre UI” Cocoa application, but the default target is the “Shell tool” command-line tool:
after

gap.com == fail

Store hours? What store hours?
gap-shopping-fail

The Gap web site was clearly not designed by anyone who actually wanted to shop. It might have been designed by people who wanted to sell things, but that doesn’t help me.

So what’s wrong?

  • Store hours are not listed. Anywhere! (I tried calling the Burlingame store, hoping to get voicemail, but instead got nothing.)
  • Search is almost useless. I can search for jeans in my size, but I can’t restrict the search to items in a price range or search by colour.
  • You cannot tell which Gap stores have which items in stock.
  • The store locator is broken. When you search for stores in “San Francisco,” you get this error:

    We couldn’t find your exact address. Please choose a location from the list below or try another address.

    1. San Francisco, California
    United States
    Use this address

    2. San Francisco (county), California
    United States
    Use this address

    Next, you can search for all Gap-affiliated stores. You can also search for specific subbrands (GapKids, babyGap, GapBody, GapMaternity, GapOutlet). What you can’t do is search for Gap stores only, excluding the subbrands.

  • Why isn’t “in-store pickup ($0)” one of the shipping options? It works really well for REI.
  • Why are some sizes out of stock? I can understand that individual stores can’t stock every size-item-colour combination, but the web site (warehouse) has no excuse. If something isn’t in, at least let me order the backordered item.

People, if you want my money, don’t make it hard for me to give it to you.

My iPhone wish list

I’ve had my iPhone for just over a year and a half now.

There are several things it does very well (browse the web, sync with my computer) and some things it does not do (talk to CalDAV servers, record video, wash my laundry).

In the past year and a half, the iPhone OS has been upgraded 12 times. Major new features have been added, including the app store, a scientific calculator, geolocation, ActiveSync and MobileMe push support, additional languages (including two-byte languages) and contact search.

Great. But…what’s missing? If I were in charge, here’s what I’d fix:

  1. Make syncing work over WiFi. Syncing only happens over USB. I rarely remember to plug my iPhone in to my Mac, but they are in the same room at least once a day.
  2. Let me swear. “Fuck” and “shit” are not in the spelling checker dictionary.
  3. Allow forwarding of SMS messages.
  4. Sync notes with Mac OS X Leopard Mail’s notes.
  5. Have iCal To Dos show up on the phone.
  6. A unified inbox. Go to one application to see SMS, email and voicemail messages.
  7. Let me backup, save, or sync voicemails to iTunes.
  8. Use the iPhone as a modem, like you can with a 2001-era Sony Ericsson.
  9. Create the concept of a selection. This means I can delete blocks of text and copy and paste.
  10. Smarter quoted text. When you reply to an email, Mail quotes the entire message or thread, perpetuating the top-posting problem. There is no way to disable or adjust this. (Downloading 20K of useless quoted text on EDGE with two bars is all sorts of no fun.)
  11. Call metadata is lost. It would be great if I could export my call log data to my computer.
  12. There’s no easy way to see carrier billing data. I want a settings panel that shows me the minutes and messages used and remaining in my current billing period.