nyerm http://blog.nyerm.com Life goes by pretty fast Fri, 24 Apr 2009 02:58:30 +0000 http://wordpress.org/?v=2.7.1 en hourly 1 Fixing git pre-commit hook woes http://blog.nyerm.com/2009/04/23/fixing-git-pre-commit-hook-woes/ http://blog.nyerm.com/2009/04/23/fixing-git-pre-commit-hook-woes/#comments Fri, 24 Apr 2009 02:02:43 +0000 lonnon http://blog.nyerm.com/?p=562 I’ve had something strange occur when attempting to commit changes to a Git repository located on a flash drive. A pre-commit hook, which is a script Git runs before the git commit command does its thing, prevents me from committing files until I’ve removed whitespace characters from the ends of all the lines in the files. Cleaning out such whitespace is good practice if you’re working on a project and you submit your changes as patches; the patch mechanism has a tendency to barf on lines that contain trailing whitespace.

My problem is that not only am I not working on a project where I submit patches, some of the Rails generators create files that contain trailing whitespace (I’m looking at you, RSpec). When I found that the rake db:migrate task adds trailing whitespace to the schema.rb file, I nearly went ballistic. I’d be okay with keeping the whitespace out of my own code, because I’m just OCD enough to enjoy the exercise, but having to fix code generated by automation tools just pisses me off.

To add to the aggravation, the pre-commit hook didn’t seem to run when I was committing to Git repositories on the hard drive of my Mac. I ran afoul of the hook only when committing to a repository on the flash drive or on my Windows laptop.

I got fed up with it enough today to do a bit of digging into the guts of Git. The pre-commit script is created when git init sets up a new repository, and the script is located in a project’s working directory under .git/hooks. The pre-commit script’s comments indicate that it’s designed to prevent trailing whitespace from getting into files destined for patches. The comments also mention the following:

To enable this hook, make this file executable.

Aha! Now we’re getting somewhere. I checked the file permissions, and sure enough, the file is executable in a repository created on the flash drive. However, it isn’t executable in a repository created on the Mac’s hard drive. Digging a bit deeper, I found that the original copy of pre-commit comes from /usr/local/share/git-core/templates/hooks, where the file is also not executable.

It looks like git init loses the file permissions when it copies everything from the Git templates directory over to the flash drive, thereby resulting in files that have full permissions enabled. This makes sense, given that the flash drive is FAT32-formatted; the filesystem doesn’t support Unix-style execution permissions. My Windows laptop has the same problem.

Finally knowing what causes the problem, I defused it by renaming pre-commit in the templates directory to pre-commit.patching. Now if it’s copied with full permissions, it won’t matter, because Git’s looking for a file named pre-commit. I may at some point need to re-enable the hook if I start submitting patches to someone else’s project, but in the meantime, for the majority of work that I do in my own one-man repositories, I’m no longer bothered by an over-protective pre-commit hook.

]]>
http://blog.nyerm.com/2009/04/23/fixing-git-pre-commit-hook-woes/feed/
Deploying a Sinatra app on Dreamhost http://blog.nyerm.com/2009/03/21/deploying-a-sinatra-app-on-dreamhost/ http://blog.nyerm.com/2009/03/21/deploying-a-sinatra-app-on-dreamhost/#comments Sat, 21 Mar 2009 18:32:50 +0000 lonnon http://blog.nyerm.com/?p=548 I’ve been down with the flu and confined to the couch for the last couple of days, so what better way to pass the time than learning a new web framework and deploying it to Dreamhost? Only a brain cooked by fever would think something like this might qualify as fun, but my grey matter is pretty close to hard-boiled by now, and I can only play so much WoW before wanting to shoot myself. So I fired up Google and a text editor and started hacking away.

Enter Sinatra

The most pleasant part of this whole experience was picking up Sinatra, a minimal Ruby web framework that hearkens back to the simpler days of shoving a bunch of Perl into a CGI script and calling it a day. Like the CGI script of yore, you can easily stuff a small app into a single file. Unlike that CGI script, Sinatra lends itself well to MVC separation, test- or spec-driven development, and other modern programming conveniences. It’s ideal for slapping a quick user interface on some Ruby code.

Sinatra’s readme is a great drink-from-the-fire-hose introduction to what the framework can do, but the minimal “hello world” application on Sinatra’s home page is a bit too minimal to be instructive. There are some great tutorials listed on the Sinatra site, though. In particular, I found Building an iPhone web app in under 50 lines with Sinatra and iUI to be just the ticket for quickly getting up to speed on what Sinatra does. As an added bonus, it’s got iPhone stuff in it, which is worth at least two squares in Buzzword Bingo.

Dreamhost, prepare to be boarded

The first step is to make a domain in the Dreamhost panel and configure it to run Passenger. From what I’ve been reading, Passenger isn’t really set up to run apps in a subdirectory (like example.com/myapp), so a new subdomain is the way to go here (like myapp.example.com). Dreamhost lets you define as many subdomains as you want, so this isn’t a problem; just click Add New Domain / Sub-Domain in the Domains > Manage Domains screen.

On the Fully Hosted page that appears, check the Ruby on Rails Passenger box. Then set up the web directory as you would for any other site, but add current/public to the end of the path. We’re using Capistrano to deploy the app, and Capistrano wants to deploy to a directory called current. Passenger expects the web directory to point to the app’s public folder. Combining those two makes a path ending in current/public.

Let Dreamhost do its thing and create the new domain. Depending on how flaky its systems are and the current phase of the moon, you may have a working subdomain in a few minutes or several hours. I failed my saving throw versus Broken Scripts and got the several hours version when I set up the domain yesterday, resulting in the dreaded bad_httpd_conf error. You can sometimes force Dreamhost to rebuild your messed up httpd configuration by going back to the Fully Hosted page and just clicking the Fully host this domain now button. No need to change any settings on the page; apparently, performing this little ritual will kick the scripts into gear, and with luck, you’ll have a working subdomain with Passenger running on it.

When Dreamhost’s scripts get around to creating the domain, they’ll also create its web directory. You’ll need to ssh over to your account and delete the current directory that’s there. Capistrano recreates current as a symbolic link pointing to the currently deployed version of the application.

  > cd ~/sites/sinatra-test.nyerm.com
  > rm -rf current

Vendoring Sinatra and Rack

Though it’s possible to get your own local gem repository working on Dreamhost (and for some gems, like RMagick, necessary), I find it simpler to unpack gems required by the app into a vendor folder and just deploy them with the rest of the application.

As I write this, Dreamhost doesn’t have Sinatra installed at all, and its copy of Rack is version 0.4.0, which is incompatible with the latest Sinatra (0.9.1.1). So, I unpacked both of these gems into a vendor folder. Run these commands from the root of your Sinatra project:

  > mkdir vendor
  > cd vendor
  > gem unpack rack
  > gem mv rack* rack
  > gem unpack sinatra
  > gem mv sinatra* sinatra

Be sure to change the require 'sinatra' line at the start of your application so it requires the vendor copy of Sinatra:

  require 'vendor/sinatra/lib/sinatra'

Capifying and racking

With Dreamhost ready to receive your application, it’s time to get Capistrano in on the action. First you’ll need to create a Capfile so Capistrano knows where your application’s source is and where it should be deployed.

  > capify .

Open Capfile in your favorite editor and replace the sparse default contents of the file with something more like this:

  load 'deploy' if respond_to?(:namespace)

  default_run_options[:pty] = true
  
  # be sure to change these
  set :user, 'username'
  set :domain, 'domain.com'
  set :application, 'myapp'
  
  # the rest should be good
  set :repository,
      "#{user}@#{domain}:git/#{application}.git"
  set :deploy_to,
      "/home/#{user}/#{application}.#{domain}"
  set :deploy_via, :remote_cache
  set :scm, 'git'
  set :branch, 'master'
  set :git_shallow_clone, 1
  set :scm_verbose, true
  set :use_sudo, false
  
  server domain, :app, :web
  
  namespace :deploy do
    task :restart do
      run "touch #{current_path}/tmp/restart.txt" 
    end
  end

I found a number of sites with reasonable instructions for deploying Sinatra to Dreamhost, and my favorite is John Nunemaker’s guide on RailsTips. The Capfile above is from his article, which is well worth a look.

The bits that you might need to change in the Capfile here, aside from the obvious :user, :domain, and :application fill-ins, are the :repository and :deploy_to paths. For example, I keep my personal Git repository in a directory that’s served out by Apache so I can browse the contents. Also, my file structure has an extra sites directory above the web roots, because I don’t like the mess that Dreamhost’s default paths make of my home directory. The appropriate portion of my Capfile looks like this:

  set :repository,
    "#{user}@#{domain}:sites/git.nyerm.com/#{application}.git"
  set :deploy_to,
    "/home/#{user}/sites/#{application}.#{domain}"

The last ingredient needed for deployment to Dreamhost is a rackup configuration file, config.ru. Pop open the text editor again and enter the following:

  require 'vendor/rack/lib/rack'
  require 'vendor/sinatra/lib/sinatra'
  
  set :run, false
  set :environment, :production
  set :views, "views"
  
  require 'hi.rb'
  run Sinatra::Application

Deploying to Dreamhost

Check all your files in and push to the remote Git repository, and you should be ready to deploy with the following commands:

  > cap deploy:setup
  > cap deploy

Assuming you don’t have any typos and Dreamhost is choosing to be merciful, you should now have a Sinatra app running on Dreamhost. On the other hand, if like me you’re not a divine being of pure logic, you might want to enable Rack’s logging middleware so you have some clue what’s not working. Stick the following in your config.ru, and you’ll get something more useful than you’ll find in the Apache logs:

  log = File.new("log/sinatra.log", "w")
  STDOUT.reopen(log)
  STDERR.reopen(log)

Credit where credit is due

I found the following articles helpful when trying to get all this working:

]]>
http://blog.nyerm.com/2009/03/21/deploying-a-sinatra-app-on-dreamhost/feed/
Helipad, now on GitHub http://blog.nyerm.com/2009/03/06/helipad-now-on-github/ http://blog.nyerm.com/2009/03/06/helipad-now-on-github/#comments Fri, 06 Mar 2009 11:38:03 +0000 lonnon http://blog.nyerm.com/?p=541 The Helipad Ruby interface is now available on GitHub in addition to its original home on RubyForge.

There’s no difference at all between the two, apart from the GitHub copy bearing my name, which is GitHub’s convention for preventing collision between identically-named gems. If you wish to install the gem from GitHub instead of RubyForge, you can do the following:

  > gem sources -a http://gems.github.com
  > sudo gem install lonnon-Helipad
]]>
http://blog.nyerm.com/2009/03/06/helipad-now-on-github/feed/
Improved dynamic human-readable RESTful routing http://blog.nyerm.com/2009/02/20/improved-dynamic-human-readable-restful-routing/ http://blog.nyerm.com/2009/02/20/improved-dynamic-human-readable-restful-routing/#comments Fri, 20 Feb 2009 08:58:31 +0000 lonnon http://blog.nyerm.com/?p=513 Earlier in the week I posted about making dynamic RESTful routes in Rails. At the end of the article, I mentioned that the method I was using might not work in a production environment, and after searching Agile Web Development with Rails for the word “restart,” I confirmed my suspicions. Generating routes on the fly from data runs afoul of caching, requiring the server to be restarted to pick up changes to the routing. That rules it out as a reliable way to generate pretty URLs.

To recap, I’ve already used map.resources to generate the usual http://example.com/sections/1 style of REST URL. I want to be able to route a URL like http://example.com/about to the show method of my Sections controller, as well, to improve human readability (and SEO) of the URL.

Fortunately, I’d already thought about how to do this. The solution is to capture the highly variable URL in a route and process it in the Sections controller to figure out where to send it. The following is now the very last route in my routes.rb file:

  map.section_dispatch ':section',
                       :controller => 'sections',
                       :action => 'show'

This route’s location at the very end of routes.rb is no accident. It’s extremely promiscuous, and it will latch onto any URL of the form http://example.com/foo. If it came earlier in the routing, it would prevent many other routes from being triggered, including the http://example.com/sections REST route that calls the index action to display a list of all the sections.

The route captures whatever comes after the domain part of the URL in the :section parameter and sends it along to the show action in the Sections controller, which is where the really interesting stuff happens:

  def show
    section = params[:section]
    if section.nil?
      section = 'home'
    end
    @section = Section.find_by_name(section)
    unless @section
      render :file => "/404.html",
             :status => :not_found
    end
  end

Remember I said the route is promiscuous? Here’s real proof: even a nil :section parameter gets picked up by the route, which means the root URL for the site (http://example.com) is sent to the show action. The check for section.nil? assigns the Home section as the desired target; Home is where I keep any bits of content that appear on the front page of the site.

The show action then looks for a Section in the database whose name matches whatever the route picked up from the URL, assigning the Section it finds to the instance variable @section for use by the Section view. However, if the name in the URL doesn’t match any Section names, a render call sends the browser a 404 Not Found error and renders an appropriate page so the site visitor knows she’s typed in a bad URL. Eventually, I’ll replace the static 404.html file with a new controller and view that can generate a more useful 404 page with a search box and helpful links, but that’s a project for another day.

]]>
http://blog.nyerm.com/2009/02/20/improved-dynamic-human-readable-restful-routing/feed/
Crashing InDesign with bookmarks and hyperlinks http://blog.nyerm.com/2009/02/18/crashing-indesign-with-bookmarks-and-hyperlinks/ http://blog.nyerm.com/2009/02/18/crashing-indesign-with-bookmarks-and-hyperlinks/#comments Thu, 19 Feb 2009 01:17:36 +0000 lonnon http://blog.nyerm.com/?p=506 After generating a table of contents for a multi-document InDesign book, I tried to export the book to PDF. Adobe InDesign CS3 fell right over, presenting me with the friendly “please tell our developers what the hell you were doing that crashed our fine software” dialog.

When generating the table of contents (Layout > Table of Contents), I selected the Create PDF Bookmarks option. If I omitted the bookmarks, InDesign was able to export a PDF without any trouble, but of course, the PDF was missing the bookmarks. Because the book is nearing 100 pages, having functional bookmarks in the sidebar of Adobe Reader, as well as working hyperlinks in the table of contents, is a necessity for navigating this beast.

After trying every combination I could think of in the Table of Contents dialog, I turned to the Export Adobe PDF dialog (Book panel menu > Export Book to PDF) and started flipping switches there. I discovered that the Bookmarks option in the Include section of the dialog didn’t make any difference; whether on or off, InDesign still crashed when producing a PDF.

I turned off the Hyperlinks checkbox, and lo and behold, InDesign continued chugging away and gave me a PDF. None of the bookmark sidebar links worked, nor any table of contents links, nor any other hyperlinks anywhere in the book, but at least InDesign decided to stay with me this time instead of unceremoniously quitting.

On the theory that a logical approach wasn’t working, I started poking at random settings. I got lucky with the first one I tried; turning off Create Tagged PDF not only prevented InDesign from crashing, it produced a fully functional PDF with working bookmarks and hyperlinks. Mission accomplished!

I’m a bit frustrated that InDesign refuses to make a tagged PDF with working hyperlinks. The whole point to tagged PDFs is that they define document structure, which makes them accessible to assistive reading technologies and lets mobile devices reflow the content to better fit tiny screens. This book isn’t likely to reach a huge audience to begin with, but it hurts to think that InDesign might be shrinking that audience even further. Given a bit of googling, it appears I’m not the only one to find problems with tagging in InDesign CS3.

]]>
http://blog.nyerm.com/2009/02/18/crashing-indesign-with-bookmarks-and-hyperlinks/feed/
Dynamic human-readable RESTful routing http://blog.nyerm.com/2009/02/16/dynamic-human-readable-restful-routing/ http://blog.nyerm.com/2009/02/16/dynamic-human-readable-restful-routing/#comments Tue, 17 Feb 2009 03:02:45 +0000 lonnon http://blog.nyerm.com/?p=483 I’m slowly becoming a convert to the RESTful routing model in recent versions of Rails, largely because it builds a pile of useful named routes with a tiny amount of code. If I put map.resources :sections in my routes.db file, I instantly get sections_path, edit_section_path, and all their friends. When coding a controller, it’s a lot nicer to write redirect_to section_path than redirect_to :controller => :section, :action => show.

The only difficulty I have with default routes created by map.resources is that, in some cases, they’re ugly and show too much of the application’s internal workings. For example, the application I’m working on now has a Section model, which describes a major section heading in the site (things like About, FAQ, and Help). Instead of having weird routes like /sections/1, I want human-readable URLs like /about. They look nicer, and they’re better for SEO.

To the rescue: dynamic named routes

To create the pretty section names, my routing dynamically creates a set of named routes based on the URL-friendly string stored in each Section’s name attribute. The appropriate part of routes.db looks like this:

  map.resources :sections
  Section.find(:all).each do |section|
    map.named_route("#{section.name}_section",
                    section.name,
                    :controller => 'sections',
                    :action => 'show',
                    :id => section.name,
                    :method => :get)
  end

The first thing this code does is create normal RESTful routes for the sections:

  map.resources :sections

Creating the usual RESTful routes allows administrative actions, like editing and deleting sections, to have all the benefits of regular REST routing. I can still edit a section at /sections/1/edit, or delete one by sending the DELETE HTTP method to /sections/1. I’m okay with most of these URLs showing off section ID numbers, because they’re all tucked away behind an admin interface that requires authentication to access. What I really need is to create new routes for each section’s show action, which is what the next part of the code does.

Next, the code iterates over the sections in the database, using the standard ActiveRecord find method:

  Section.find(:all).each do |section|

Within this each block, the map.named_route method is used to create a named route pointing to each section’s show method. Normally, Rails creates named routes using a little method_missing magic. This is great when you’re making a named route by hand; it lets you create named routes on the fly, instead of having to call a method on the map object (an instance of ActionController::Routing::RouteSet::Mapper). Unfortunately, this bit of syntactic sugar isn’t as nice to code that needs to create named routes.

Fortunately, the Mapper class contains an undocumented named_route method that creates named routes in a standard method call, rather than relying on method_missing to fill in the blanks. The named_route method takes three arguments: the name for the new route, the URL path that will trigger the route, and a hash full of options defining the properties of the route. In my case, the name for the route is composed of the Section object’s name attribute, with _section tacked onto the end. This results in helper methods like about_section_path and faq_section_url. The recognized path is the name of the section itself, meaning that /about will go straight to the section controller’s show method and display the About page.

Putting in the human-readable bit

One other sneaky thing I’m doing is on line 7 of the first code example, with :id => section.name. Because I’m using short, human-readable names in my section URLs, I’ve changed how the Section model generates URLs. By default, ActiveRecord returns the record’s id@ as a String, resulting in the familiar @/sections/1 style of URL. However, if you override the to_param method of an ActiveRecord model, you can change how it generates URLs. Over in my section.rb file, I have the following code:

  def to_param
    name
  end

This ensures that when the Section model is used to generate a URL, it returns the friendly, human-readable name attribute instead of its numeric @id@.

A drawback: rake gets wonky

There is a downside to this method of dynamically generating routes. Recent Rails versions (probably 2.1 and later) changed the rake tasks framework to load up the entire application’s environment before running any rake task. Unfortunately, this includes the routes.rb file. Because my routing queries the database, a normally innocuous invocation of rake db:create causes problems if the database is missing or empty, producing an error like the following:

  > rake db:create
  rake aborted!
  Unknown database 'project_development'

I can’t fathom why something like db:create would need access to the application’s entire environment, and it’s particularly silly in this case that in order to create the database, there must already be a database. I expect that purists would argue that having a database query in my routing breaks MVC separation, but this method makes it simple to make named routes based on changeable data. The workaround is to comment out the Section.find part of the routes.rb file before running things like db:create, but it’s a poor workaround, indeed.

In addition, I’m not positive that this setup works well under the Rails production environment. It’s been fine in development, but caching and other goodness introduced in a production application could mean that I can’t change the routing on the fly like this, instead requiring the application to restart to pick up any changes to the sections data. I recall earlier versions of Rails requiring a restart any time routing was changed, but I haven’t been able to track down if this applies to 2.2 in production.

A different approach?

Another possibility, which I may settle on eventually, would be to add a catch-all route at the bottom of routes.rb that pipes everything through a dispatch method in the sections controller. It might look something like this:

  map.parse_section ':section',
    :controller => 'sections',
    :action => 'parse'

It could perform the database lookup inside controller code and compare it to the string captured by the routing system, and it wouldn’t interfere with rake tasks. It’s important to note that this route should be at the very bottom of routes.db, else it will slurp up any single-component URL and attempt to process it with the section parse method.

]]>
http://blog.nyerm.com/2009/02/16/dynamic-human-readable-restful-routing/feed/
TextMate as a blogging tool http://blog.nyerm.com/2009/02/11/textmate-as-a-blogging-tool/ http://blog.nyerm.com/2009/02/11/textmate-as-a-blogging-tool/#comments Wed, 11 Feb 2009 22:48:30 +0000 lonnon http://blog.nyerm.com/?p=478 There’s something extraordinarily wrong about this. I just discovered, through Barry Hess’ blog, that TextMate has a blogging bundle. It hooks up to the ubiquitous XML-RPC interfaces sported by modern blogging software (Wordpress, Movable Type, Typo, what-have-you) and lets you use your text editor to create and edit weblog posts.

This is a far more comfortable interface for composing blog articles than any I’ve encountered, including the feature-rich web interface in Wordpress itself. I don’t use the embedded WYSIWIG editor widget in Wordpress, preferring to format my posts with Textile so I can just keep typing instead of trying to figure out what all the little buttons are supposed to do. TextMate does a great job with highlighting Textile, providing just enough coloring and styling to let you know that you’re doing the markup right without getting in the way of the writing.

On top of that, I’ve got the security of knowing that my prose isn’t going to disappear if the browser crashes or my network connection flakes out. Need more time to compose a lengthy article? Just save it locally, as a simple text file, and come back to it later. This is the very definition of “no muss, no fuss.”

Now to see if this bundle works as well in TextMate’s Windows cousin, e, so I can get the same great feature on my laptop that I have on the iMac at work.

UPDATE (2009-02-11 21:03): Yes, indeed, this same power exists in e. I am one happy camper.

]]>
http://blog.nyerm.com/2009/02/11/textmate-as-a-blogging-tool/feed/
Helipad Ruby interface http://blog.nyerm.com/2009/01/08/helipad-ruby-interface/ http://blog.nyerm.com/2009/01/08/helipad-ruby-interface/#comments Thu, 08 Jan 2009 21:25:58 +0000 lonnon http://blog.nyerm.com/?p=451 Spurred by my need to upload a bunch of notes from the now-defunct Stikkit to my account on Helipad, I wrote a Ruby wrapper for Helipad’s XML-over-HTTP API. The interface takes care of all the XML magic, letting you concentrate on the fun stuff: playing with your documents on Helipad.

  hp = Helipad.new("lonnon@example.com",
                   "password")
  source = File.read("cake_recipe.txt")
  response = hp.create(:title  => "Cake",
                       :tags   => "recipe",
                       :source => source)
  puts "Recipe saved" if response.saved?

The Helipad Ruby interface can be installed through rubygems:

gem install Helipad --remote

Documentation is available here:

If you’re interested in the source code and current state of development, you can find the Helipad Ruby interface over on RubyForge:

]]>
http://blog.nyerm.com/2009/01/08/helipad-ruby-interface/feed/
Silly meme time http://blog.nyerm.com/2008/11/24/silly-meme-time/ http://blog.nyerm.com/2008/11/24/silly-meme-time/#comments Tue, 25 Nov 2008 02:19:12 +0000 lonnon http://blog.nyerm.com/?p=445
  • Grab the book nearest you. Right now.
  • Turn to page 56.
  • Find the fifth sentence.
  • Post that sentence along with these instructions on your LJ.
  • Don’t dig for your favorite book, the coolest, the most intellectual. Use the closest.
  • Armadillos: This witty description of the armadillo was produced by the descit environment.

    Alas, the nearest book to me is Leslie Lamport’s ??LATEX User’s Guide and Reference Manual??.

    ]]>
    http://blog.nyerm.com/2008/11/24/silly-meme-time/feed/
    Apache hinkyness http://blog.nyerm.com/2008/10/28/apache-hinkyness/ http://blog.nyerm.com/2008/10/28/apache-hinkyness/#comments Wed, 29 Oct 2008 00:05:49 +0000 lonnon http://blog.nyerm.com/?p=436 I encountered a weird web problem today when adding images to the company website. The new images I’d added wouldn’t appear on their page, and when pointing the browser directly at them, I received a 403 Forbidden error.

    After insuring that the permissions and filenames were all correct, I sat down with the sysadmin to see if a second pair of eyes and a root login could find anything amiss. After spending half an hour of finding nothing in the logfile or permissions settings, we both gave up.

    I returned to my desk, and on a whim, performed the following commands:
    1. cp image-file.gif foo.gif
    2. rm image-file.gif
    3. mv foo.gif image-file.gif
    I can’t imagine why this would have solved the problem, but it did. The implications–that something might be messed up deep within the innards of Apache or the Fedora filesystem–make me worry what other bizarre behavior I can expect from the webserver in the future.

    This isn’t the first time machines have had odd behavior in my presence, which I’ve been able to dispel by performing seemingly unrelated actions. I’m obviously in the wrong business. I should pack my bags and hit the road as a traveling computer faith healer.

    ]]>
    http://blog.nyerm.com/2008/10/28/apache-hinkyness/feed/