November 23, 2010 - NO Comments
Usually about once a week I’ll scan job boards to scope out potential customers. If a company is looking to hire someone they either have more business than they can handle or they’re looking to grow. In either case, it makes sense to contact them.
This morning I came across an opening for a position where the duties included “Conduct periodic sales/pricing/performance reviews.” This is a theme that I see time and time again and the reason is that most transportation companies are using a broken model.
They view pricing as a cumbersome process that’s undertaken when you first bid on the freight and then re-initiated at some point a month or a quarter in the future, mostly oblivious to changes in linehauls and fuel surcharges. This would be like a natural gas trader working up a price in August and attempting to trade on that price in October without checking the spot market.
It leaves you fully exposed to the upward pricing pressure of your vendors. Do you re-evaluate your vendors every week when the DOE issues its diesel update? What if one of your draymen uses a very aggressive fuel surcharge scale? Do you re-evaluate your linehauls when the railroads release their simplified pricing tariffs each week?
You need instantaneous pricing so that your operations team can choose the cheapest routing as they move the freight. Not a month from now when you get the invoice.
October 27, 2010 - NO Comments
In the last post I described how to set a custom MIME type when NGINX is your web server, but I just glossed over why I wanted to do it in the first place.
Adding a cache manifest file instructs mobile Safari and probably most Android browsers to store support files (javascript, css, etc.) for a webapp. This is important because it allows for offline execution and in our case, faster load times and less data usage on a cell phone plan.
So, what does this mean if you’re a customer of ours and don’t care about programming?
Turbine used to take around 15 seconds to load on the iPhone when you were on 3G and not Wi-Fi. Now, it takes 3-5 seconds. Which means that if your customer calls you away from the office, you can put them on hold, run a rate, and quote them intermodal and truck in under 45 seconds all from your phone.
With that level of service, would they even bother calling your competitors?
October 26, 2010 - 1 Comment
I’m implementing the HTML 5 offline caching mechanism in the iPhone interface of Turbine and to do that I need to expose a .manifest file. Per the specs, a .manifest file should be served with a content type of text/cache-manifest.
I can check this by submitting a HEAD request with curl and the -I switch:
~ >curl http://your-url/sample.manifest -I
HTTP/1.1 200 OK
Server: nginx/0.7.64
Date: Mon, 25 Oct 2010 21:59:58 GMT
Content-Type: application/octet-stream
Content-Length: 241
Last-Modified: Mon, 25 Oct 2010 21:58:20 GMT
Connection: keep-alive
Accept-Ranges: bytes
Oops, looks our web server, NGINX doesn’t associate a .manifest file with the content-type we need. To change this, you need to update the mime.types file in the conf directory. Depending on how you set up NGINX it could be located under /etc/nginx or /opt/nginx.
After opening the file, you should see something like this:
types {
text/html html htm shtml;
text/css css;
text/xml xml;
...
}
Simply add an entry “text/cache-manifest manifest;” and re-start your server and you should be good to go. Check this again with curl:
~ >curl http://your-url/sample.manifest -I
HTTP/1.1 200 OK
Server: nginx/0.7.64
Date: Mon, 25 Oct 2010 22:17:51 GMT
Content-Type: text/cache-manifest
Content-Length: 241
Last-Modified: Mon, 25 Oct 2010 22:16:13 GMT
Connection: keep-alive
Accept-Ranges: bytes
Much better.
October 15, 2010 - NO Comments
Yesterday’s post on Geocoding dray rates illustrated one way a drayage company calculates their rates to different zones within the same metro. Some calculate the rate based on the distance of the city to each of the zones. Others, like from yesterday’s post tack on a flat fee when the pickup or delivery is out of the way. And others, like the tariff that I’ll be uploading today make no distinction; it’s simply one rate to every ramp in Chicago.
What was missing in the discussion was how perfectly this illustrates the inefficiencies in the drayage market because of the very different rates you could be quoted from different vendors. It could be that all the drivers for one company live close to a far-flung ramp zone. Or that the drayman’s yard is near another ramp. Or, most likely, that it’s a pain to calculate the mileage of every serviced city to every ramp zone.
The reasons are not particularly important. What is important, if you move intermodal freight, is taking advantage of those inefficiencies. Whenever I see draymen from the same metro using very different methods for calculating rates I smile because I know that our customers are going to benefit.
That’s because there’s higher variance in a drayage market where rate calculations are erratic. Take a look at the example charts below.


In the first scenario, rates to each point are clumped together, so choosing between vendors is less important. In the second scenario, while some rates are much higher, some are also much lower, magnifying the financial impact of choosing the correct vendor.
October 14, 2010 - NO Comments
I was uploading a drayage rate tariff to a customer’s instance of Turbine yesterday and I ran into an unusual problem. There are 3 recognized areas of rail ramps in Chicagoland (city, north, and south) and most draymen explicitly set a different price for a given city to each area. So, if you had a pick up in Downers Grove, IL you’d get one rate for the city ramps, another rate for the northern ramps, and a third rate for the southern ramps.
The drayman in question does it a little differently. They provide one rate for the city ramp and then add a flat fee if the pick up is out of the way. For example, if a shipper is south of Chicago you don’t have to pay the extra fee to the southern ramps, but you do have to pay the fee for the northern ramps.
With 400-500 points this posed a bit of a problem. Mapping each city by hand was going to be far too cumbersome so I had to figure out a way to automate the process. Enter Google’s geocoding API. By calling Google’s service I would be able to compare the latitude of each of the cities with that of the two ramp areas.
Whenever I need to do some quick and dirty scripting Ruby is my programming language of choice. And with a scant 24 lines of code I was able to accomplish the task.
require 'rubygems'
require 'net/http'
require 'uri'
require 'crack'
DOLTON = 41.6389236
BENSENVILLE = 41.9550296
def get_latitude(json)
Crack::JSON.parse(json)["results"][0]["geometry"]["location"]["lat"]
rescue
nil
end
result = ""
DATA.each do |city|
sleep 0.75
city.strip!
uri = "http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=#{URI::escape(city)}%20IL"
json = Net::HTTP.get(URI.parse(uri))
lat = get_latitude(json)
result += lat ? "#{city},#{(lat - 0.05) > DOLTON},#{(lat + 0.05) < BENSENVILLE}" : "#{city},-1,-1"
result += "\n"
end
File.open("lats", 'w') {|f| f.write(result) }
__END__
Addison
Aledo
Algonquin
Alsip
...
more cities
...
The first four lines are dependencies. The next two are constants holding the latitude (which I looked up manually) for the two ramp areas; Dolton to the south and Bensenville to the north. Then it's a JSON parsing method that takes the response from Google and returns a hash (or nil if the response isn't useful). Then I declare the result variable into which the output will be stuffed.
On the next line you see DATA which, in a Ruby file, holds the contents of the here document. In this case it includes all of the cities listed after the __END__ statement which get looped through using an "each" block. Inside the loop I added the sleep function because I was getting a bunch of invalid responses without it. Perhaps Google throttles requests that come in too quickly from the same IP address.
After the sleep function, the URI is constructed by escaping the city and hard-coding "IL" since they are all Illinois points. The call is made to the web service and the response placed into the json variable which then gets passed to the parsing method. After that we append the result variable with a comma delimited string of the city and true or false for whether or not the city is north of Dolton and south of Bensenville.
Couple things to note on this line. I padded the points by 0.05 so that cities that are just north of Dolton or south of Bensenville don't get the extra charge. Also if the service can't determine the latitude I use the value of -1 in place of the boolean values. Finally, I create a file called "lats" and write the result to it.
After running this script, I copied and pasted the contents into an Excel spreadsheet and split it into 3 columns. Since most spreadsheet programs treat true as 1 and false as 0, I could just multiply each column by the extra charge and then add it to the original.
October 5, 2010 - NO Comments
The phrase “just saying” at the end of a blog or forum comment has lost whatever charm it may have once held. Not only is it unnecessary, it’s almost always loaded with the implications the commenter claims to be removed from.
Although I’ve seen others lament its usage before, to my knowledge (two pages of a Google search) nobody’s come up with a good answer for it. So I decided to write a little script that removes the phrase from a comment before it’s posted. It’s not really an iron-clad solution, but more of a not-so-gentle reminder to the casual offender.
Put the following in a script tag after linking to the jQuery library and you’re good to go.
$("textarea").blur(function() {
var $self = $(this);
var val = $self.val();
$self.val(val.replace(/just?\s?sayin(g|')?\s?\.{0,3}/i, ""));
});
It hasn’t been a problem on this blog since the spam-bots and I came to an agreement, but feel free to try it out below.
September 20, 2010 - NO Comments
The Wall Street Journal has an excellent article today about how employee productivity affects job growth. I won’t repeat all of what was written, but the gist of it is that productivity soared last year to the highest levels since the 1960s as companies retrenched and became leaner. That rate has slowed this year indicating that we’ve reached a limit to productivity and that companies will eventually be forced to start hiring.
If you laid off some of your workforce last year you might be struggling with the same dilemma. Do you bite the bullet and take on new hires, hoping that the economy has rebounded for good? Or do you look for ways to squeeze out a little more productivity from your employees?
April 27, 2010 - NO Comments
With the release yesterday of first-round guidance of the “TIGER II” program, the USDOT is getting ready to hand out another $600 million. You can assume that, like the first TIGER program, many of the selected projects will further the effort of achieving the 5 stated goals of our national transportation policy; economic competitiveness, safety, state of good repair, livability, and environmental sustainability. To that end, the administration has been making a big push to strengthen intermodal movement of containerized freight.
A couple of months ago, as a result of the first TIGER program, the USDOT gave $52.5 million to the Norfolk Southern Railroad (whose quarterly net income is usually about 6 to 7 times that amount) to help with the construction of another intermodal ramp in Memphis.
Unfortunately, it’s difficult to measure the public good resulting from that ear-mark so we’ll just have to take them at their word when they say that it is worth $575 million annually in “congestion savings”.
Sounds like we got a bargain.
Now, I’m not trying to single out the NS and a shift of our nation’s containerized freight from highway to intermodal is undoubtedly a good thing. There is more than enough evidence of the benefits of intermodal over truck in terms of carbon emissions, fuel savings, and reduced transportation costs.
However, by just throwing money at projects like these, the USDOT is missing a crucial point. The people who ultimately decide whether or not containerized freight moves intermodally or over-the-road are shippers and brokers who operate with imperfect information. And because intermodal shipments are more cumbersome and expensive to price and transact, those companies will be reluctant to aggressively convert traffic.
This is where our software fits into the discussion. Because it tells you in seconds the viability of the intermodal option in a particular lane, it’s not just a killer tool that increases profits, now it appears that it’s also an instrument of the public good.
March 16, 2010 - 5 Comments
Think about the life-cycle of a typical intermodal load. (I’m going to assume that Sales/Customer Service, Pricing, and Operations are three distinct groups, but the example works equally well when one person handles more than one task.)
- 1. Customer requests a rate
- 2. Sales/Customer Service forwards the request to Pricing
- 3. Pricing calculates a rate and returns it to Sales/Customer Service
- 4. Sales/Customer Service quotes the rate to Customer
- 5. Customer tenders load
- 6. Operations checks availability
- 7. Operations re-requests rate if there is no capacity
- 8. Operations checks availability
- 9. Operations re-requests rate if there is no capacity, etc…
For steps 6 through 9, if capacity is available at the rate determined by Pricing during the original quote then it’s just a simple cover and dispatch of the load. If capacity has tightened, however, then extra requests must be made to Pricing until capacity can be attained at an acceptable rate.
Now, think about how long it takes for Pricing to calculate that rate. How’s 15 minutes? Does that sound about right to make sure that linehauls for every possible ramp pair, dray rates, and equipment charges are compiled? For some loads, it could be less, but others could take significantly longer. Think about loads into or out of PA/NJ/NY. There can be 5 or 6 ramps within 100 miles of each other. But let’s stick with 15 minutes. So, in the time it took you to get that rate, your customer probably called 3 or 4 other carriers so that she can compare all of the prices and make the right decision.
At this point, we could assume that you’re an excellent multi-tasker and that after you fire off a quick email to pricing you get right back to your sales calls and reporting duties. But I’m going to suggest that the amount of time it takes to construct the email to pricing plus some back and forth correspondence on the details is going to cost you about 15 minutes, as well.
Let’s assume that your rate or service is the best and your customer tenders you the load three days later. Now, Operations has to determine whether there’s capacity at that rate or not. If there isn’t they have to re-initiate the 15 minute process until they can find a suitable replacement.
Traditional Pricing Model:

So, the true cost of pricing that load is:
15 mins for Pricing + 15 mins for you + (% chance customer gets better rate while she waits * lost margin) + (15 minutes for Operations * number of times capacity changes)
= 30 or 45 or 60 minutes, etc. of employee time + margin on loads you lose
Now, let’s compare that to calculating a rate with Turbine. Your customer calls you up, you banter for 30 seconds while you run the lane, scan the rate and availability of every possible intermodal combination, make sure the drayage consists of capable carriers, and provide a quote. Oh, and you offer her an over the road quote while you’re at it since it’s right next to the intermodal rate.
Your customer decides that she likes your service, the rate sounds good, and she’s too busy to chase other quotes, so she tenders the load to operations three days later and they re-run the lane to check availability. If capacity is loose, they book the load as before, otherwise they take 30 seconds while they glance at the rate of the next available box. If that total puts them over the truck rate, they decide to move the load over the road.
Turbine Pricing Model:

Therefore, the cost of pricing the load with Turbine is:
30 secs for you + 30 secs for Operations IF capacity has changed
= 30 or 60 seconds of employee time
What we’re talking about here are marginal opportunity costs, so you have to multiply these costs by every load you quote. On 100 loads the difference in employee time could amount to the difference between 45 hours and 1.25 hours, or 3,600%.
In an effort to realize top line growth you would have to add significant marginal costs. But not only that, let’s say you make a decision to quote twice as much freight as you did last year. Can your pricing process handle that kind of increase? Or will you have to add fixed costs in the form of additional employee salaries and benefits?
February 22, 2010 - NO Comments
For various geeky reasons I do most of my development on a Mac, but I do have a couple of Windows PCs at home because my wife has to run AutoCAD and non-Windows versions of that software can be buggy. Also, having worked in transportation for the last eight years, I understand that, like most industries, Windows is the dominant OS and as much as I’d like to embrace Open Office’s spreadsheet application it just isn’t as good as Excel.
So when, after a software update, one of our Windows laptops wouldn’t boot I had to figure out a way to recover some data from the hard drive that hadn’t been backed up and I didn’t want to have to physically take it out of the computer. After an hour of Googling, I landed on this page and decided to give it a try. Now, if you’re like most people and think Linux is just for geeks and commies then you might be scared off by what looks like a lot of complexity. Don’t be. It couldn’t be easier. Just walk through the steps exactly as they’re laid out and you’ll be able to copy anything on your hard drive to a USB memory stick or an external hard drive.
When you’re finished, you can take out the Linux CD and restore Windows from a recovery CD or a restoration point. I was so impressed with how easy this version of Linux was that I decided to install it on a partition and create a dual boot machine. Apart from the somewhat painful process of installing a driver for our network printer it’s been a very good experience.
If you attempt any of this and run into problems, leave a comment and I’ll try to help you through it.