19
Jan 11

Using regular expressions? The Devil is in the details.

Recently, I ran into a little roadblock as I’ve been cleaning up some bugs for one of my applications. I rely heavily on cross pollination of data between sites to drive traffic across my network. In this particular situation, a simple collection of linked image thumbnails accomplishes this task.

One of the helper methods that I use returns the file name of a supplied post object. To do this, I perform a regular expression match against the post’s URL and return the result.

# post.url(:icon) = id/10/icon/foo.jpg
# returns "icon/foo.jpg"

def filename_from_post(post)
  return post.image.url(:icon).match(/icon\/.*\.jpg)/)[0]
end

That worked great until my application would randomly throw a NoMethodError. I spent a while scratching my head, looking over my code, checking my SQL queries, and so on and so forth. Finally, I figured it out…I had forgotten to specify a case insensitive search!

# post.url(:icon) = id/10/icon/bar.JPG
# returns nil

>> post.url(:icon).match(/icon\/.*\.jpg/)
=> nil

>> post.url(:icon).match(/icon\/.*\.jpg/i)
=> #<MatchData "icon/bar.JPG">

I guess what they say is true…the Devil is in the details.


08
Jan 11

A few shots from Thunderhill with ACGG

What a fun event, thanks to ACGG for everything! I had some car trouble so I only got to run a few sessions in my car on Saturday, luckily my buddy Oliver let me drive his car the rest of the weekend. For the record, anybody who tells you a Stage 3 B5 S4  is no fun has never driven a car with no traction control and a LSD!

Since the temps on Saturday were in the low 30s and my Direzzas had literally 0 miles on them I decided it would be best to run with my street wheel and tires. Surprisingly, 20″ Works with 255/30/20 Falken 452s handle quite well!

Here are a few shots of me in my car, and in Oliver’s B5 S4.


29
Nov 10

Getting around ext3 inode limitations using MD5 file paths and Paperclip interpolations

I really wished somebody had suggested I use a hashed file paths when I was planning out my application. Let me be that guy.

Anybody building an application that allows file uploads should seriously consider use hashed file paths. Why? Everybody dreams of their app becoming the next big thing, but what happens when that dream turns into a reality? It may not happen overnight, but there is a limit to the number of files you can fit into one directory.

A few weeks ago I woke up to an inbox full of emails from my Rails app titled, “Errno::EMLINK (Too many links)”. After some quick research I learned most Linux distributions use the ext3 file system which has an upper limit of 32,000 links per inode. At the time of my little meltdown I had been storing user uploads in one directory. Apparently I’ve reached the limit’

Further research revealed that the most painless solution to this problem was to use hashed file paths. Instead of saving files to “files/1/resized/image.jpg” files would be stored in “files/cdd/01d/2cf/resized/image.jpg”.

I ran the idea by the guys at my data center and it they agreed that it was the correct course of action. Wanting to further understand how a hashed file path would be different than my current method, I did some more digging. Here’s how Nick, one of the data center guys explained it:

“If I understand the way an MD5 hash operates, it will use the first few hex numerals to make the first folder, then the next few for another, and do a couple of nested layers. The idea being that while each md5 sum itself is unique, there are far fewer than 32,000 combinations for each pair, triplet, etc of hex digits, so you don’t have to worry about hitting the directory limitation. For example, if you have 10 files that all start with “1c”, let’s say, they would go into the same directory, and their nested directories would be based off of the next characters in the md5. This way, what is 10 folders in a pure :id system have just become one.

In order to hit that limit again, you’d need to have 32,000 uploads that all share the same X number of characters in their md5 sum (where x is however many are being used to generate the hash), and the chances of that happening are extremely small.”

Anyways, on to the code! As I codeviously stated, I have been using Paperclip in my Rails application. Using Paperclip interpolations we can easily create a hash path and make it available to our models. First, we need to create a file named “paperclip-md5-file-paths.rb” in config/initializers/.

If you’re using an older version of Paperclip, try something like this:

Paperclip.interpolates :hash_path do |attachment, style|
  # set the FINAL_POST_ID_BEFORE_MD5_HASH to be the ID of the existing latest attachment at the time of transition.
  return "content/#{attachment.instance.id}" if attachment.instance.id < FINAL_ID

  hash = Digest::MD5.hexdigest(attachment.instance.id.to_s + 'secret')
  hash_path = ''
 
  3.times { hash_path += '/' + hash.slice!(0..2) }
  hash_path[1..12] << ''
end

If you’re using a newer version of Paperclip, this may be more useufl:

Paperclip::Attachment.interpolations[:hash_path] = lambda do |attachment, style|
  return "content/#{attachment.instance.id}" if attachment.instance.id < FINAL_ID

  hash = Digest::MD5.hexdigest(attachment.instance.id.to_s + 'secret')
  hash_path = ''
 
  3.times { hash_path += '/' + hash.slice!(0..2) }
  hash_path[1..12] << ''
end

The first line of code determines if the current PID was before, or after our migration to the hashed file paths. This was necessary in order to support the codevious 32,000 files; you may or may not need something like this. The next block of code takes the MD5 hash of our current PID with an optinal secret word, then converts the result to a string. Finally, we iterate over the hash and slices it into three pieces. The result is our “cdd/01d/2cf” path.

Now we have a :hashed_path available to us…let’s do something with it! In your model, you can now access this new path like so:

has_attached_file :image,
  :url => "/content/:hash_path/:style/:basename.:extension",
  :path => ":rails_root/public/content/:hash_path/:style/:basename.:extension",

Why this isn’t a default configuration in Paperclip is beyond me. Enjoy!


27
Aug 10

Lotus Club Golden Gate at Thunderhill

Video 1/2

Video 2/2


11
Apr 10

The numbers are in: 402AWHP and 370ft/lbs


Horsepower in blue, torque in red, and air fuel in black.

At the last Audi Club event I won a dyno gift certificate; with all this supercharger hate going on I decided to made a quick trip up to 034Motorsport to get some numbers on an independent dyno. In addition to being local, one of the perks of having 034 dyno the car is that they’ve tuned a large majority of the Audis in the area. Many of the parts I have on my car have been been run on the dyno so we can make reasonable comparisions between modifications and cars.

034 uses a relatively conservative Land and Sea dyno.

My run plotted against a B5 S4.


10
Apr 10

A quick visit to the recycling plant

Here’s a few of the photos I took after I weighed the car.


05
Apr 10

Two tons of Audi

After the recent product launch, I had the first weekend to myself for a long time.  I found a weigh scale near my house that’s open 24 hours that I could actually get my car onto. I talked my roommate into coming out with me and got some offical numbers.

With a full tank of gas the car weighs in at 3,920lbs, almost two tons of Audi. I thought that seemed a little high considering most of the parts I’ve installed have been lightweight. Thinking backwards I was able to come up with a list of potential weight additions.

  • full tank of gas: ~160lbs+
  • supercharger, intercooler, hardware: ~75lbs
  • roll cage, harnesses, and hardware: ~75lbs+
  • subwoofer, enclosure, and amp: ~60-70lbs
  • coolant for supercharger: ~12lbs+

That’s almost 380-90lbs of static weight that I’ve added. Taking that into consideration I’m more than happy with the ~3,540-50lbs before the extra parts!


03
Apr 10

The Podi gauge pod and VEI gauges have arrived

The new Podi G2, dual gauge pod has arrived! Winston at Podi was accommodating enough to send me a preproduction pod and anodize gauge’s trim bezel black to better match the interior of my car. The gauge pod sits on top of the steering column and offers excellent visibility of both the aftermarket gauges and the OEM speedo and tach.

Each gauge displays two sensors worth of information, the gauges themselves are made by VEI Systems. The left gauge displays boost pressure and the air/fuel ratio using Innovate Motorsport’s (Bosch’s) wideband sensor. To the right I have my oil temperature and pressure.


30
Mar 10

Audi Club Golden Gate – Laguna Seca

On March 18th and 19th I had the opportunity to attend Audi Club Golden Gate’s “Quattro de Seca” at Mazda Raceway Laguna Seca. An interesting and unfortunate fact about Laguna is that it has a 92dB sound limit which is measured on the passenger side coming out of turn 5, going up the hill. If you break that limit and are identified you’ll receive a black flag…three black flags and you’re done for the day. That being said, I wasn’t sure my car would pass sound.

I called up the guys at One Stop Race Shop and rented a Spec Miata for the the event in case the S4 didn’t pass sound check. Three laps around Laguna yielded 89.5dB the second session of the day. Perfect. After my sound check, I parked the S4 and spent most of of the event in the Miata.

The handful of sessions that I took the S4 out, I was very impressed with the power delivery. The car is able to get up to speed quickly and it continues to deliver predictable power throughout the powerband. With ESP off, the car would easily break traction coming out of a corner. The only issue I had with the car was the brake pad selection, the STaSIS supplied Carbotech Bobcats are definately a street pad; a few high speed stops quickly cooked the pads. The general consensus has been to use either the Ferodo 2500 or 3000s.

This was my first time at Laguna in a car and wow, this track is fun, but I still think I like Thunderhill more. There’s something unnerving about cement walls, angry rumble strips, and uneven run off.

Spec Miata Montage

Early session in the the S4



06
Mar 10

My impressions of the car, thus far

I’ve had the car for almost a month now and have had the opporutnity to drive the car nearly 2k miles…and guess what, I love this car!

While I’ve yet to get the car on a dyno, I can tell you that it’s substantially more powerful than in stock state (one would hope, right?). There’s been lots of speculation regarding the actual gains that a supercharger provides versus a car with bolt ons, while I can’t speak towards gains from a supercharger only install I do believe that before anybody should even consider a supercharger, they should have the supporting mods.

Anyhow, I digress.

JHM’s lightweight flywheel and crank pulley allow the car to rev freely, this is especially important with the supercharger since you don’t really get into the boost until you’re around 3k RPMs. Under 3k, the car is completely and totally civilized; once you get past 3k the car just wants to take off. The car pulls quickly up through redline, I’m sure the JHM headers are helping up top.

That brings me to braking: what good is going fast if you can’t stop? Boy, can this car stop! We did a few 85mph to 20mph stops back to back…I’m not sure if getting up to 85 was more fun that slowing down! High speed braking requires minimal pedal pressure and the feedback is very linear.

Overall, both myself and those who have driven the car are pleasantly suprised with the overall package.. The car can be daily driven to work and taken to the track on the weekends. Anyhow, regardless if you’re driving or a passenger some form of giggling is guaranteed to ensue.




Here’s a quick video of my friend and his first time in the hot seat. More to come!