The eclectic musings of a bitter software engineer.

Archived Posts

Displaying posts 111 - 120 of 587

Web pages that refer to multiple CSS or JavaScript files often suffer from slower page loads, since the browser must request each referenced file individually. Most browsers will only make two simultaneous requests to a single server. The latency involved in opening multiple requests and waiting for them to finish before making new requests can result in a user-visible delay, and that can make your users sad.

Minify is a PHP library that attempts to fix this problem by combining multiple CSS or JavaScript files into one download. By default, it also removes comments and unnecessary whitespace to decrease the amount of data that must be sent to the browser. Most importantly, it does all of this on the fly and requires only a few simple changes to your existing web pages.

Before Minify:

<html>
  <head>
    <title>Example Page</title>
    <link rel="stylesheet" type="text/css" href="example.css" />
    <link rel="stylesheet" type="text/css" href="monkeys.css" />
    <script type="text/javascript" src="prototype.js"></script>
    <script type="text/javascript" src="example.js"></script>
  </head>
  <body>
    <p>
      Blah.
    </p>
  </body>
</html>

After Minify:

<html>
  <head>
    <title>Example Page</title>
    <link rel="stylesheet" type="text/css" href="example.css,monkeys.css" />
    <script type="text/javascript" src="prototype.js,example.js"></script>
  </head>
  <body>
    <p>
      Blah.
    </p>
  </body>
</html>

Minify takes about 15 seconds to download and install, has no dependencies other than PHP 5.2.1 or higher, works on any web server, and requires only minor modifications to your existing web pages. And it's free!

Visit the Minify website to learn more or, if you're already sold, download it now.

09 F9 11 02 9D 74 E3 5B D8 41 56 C5 63 56 88 C0

As you may have read, I recently lost my wallet. There's a good chance it was stolen. Inside my wallet were my driver license, several credit cards and, unfortunately, my social security card, which was only in my wallet because I was starting a new job the next morning and would need it to prove my citizenship.

Naturally, the first thing I did was call my banks and cancel my credit cards. I then used Debix to file a fraud alert with all three credit reporting agencies.

Last week I got a letter purporting to be from Equifax informing me that they would not place a fraud alert on my account until I sent them copies of several additional documents proving my identity and current address. There are a few problems with this:

  1. I have no way of knowing if the letter is actually from Equifax. Anyone who knows that I lost my wallet could also have guessed that I would file a fraud alert, and could have sent this letter in an attempt to trick me into giving them sensitive information. It's unlikely, but it's a possibility.
  2. The letter insists that I send proof of my current address, but the address it lists is actually my previous address, since I just moved. I can't prove that I live at my previous address, because I don't live there anymore, and if I provide proof of my current address, Equifax won't accept it because they don't know my current address.
  3. I have already provided Equifax, via Debix, with my full name, social security number, date of birth, and my past few addresses. This is more than enough information for them to positively identify me.

According to the Fair Credit Reporting Act, Equifax seems to be on shaky ground here:

§ 605A. Identity theft prevention; fraud alerts and active duty alerts [15 U.S.C. §1681c-1]

(a) One-call Fraud Alerts

(1) Initial alerts. Upon the direct request of a consumer, or an individual acting on behalf of or as a personal representative of a consumer, who asserts in good faith a suspicion that the consumer has been or is about to become a victim of fraud or related crime, including identity theft, a consumer reporting agency described in section 603(p) that maintains a file on the consumer and has received appropriate proof of the identity of the requester shall--

(A) include a fraud alert in the file of that consumer, and also provide that alert along with any credit score generated in using that file, for a period of not less than 90 days, beginning on the date of such request, unless the consumer or such representative requests that such fraud alert be removed before the end of such period, and the agency has received appropriate proof of the identity of the requester for such purpose; and

(B) refer the information regarding the fraud alert under this paragraph to each of the other consumer reporting agencies described in section 603(p), in accordance with procedures developed under section 621(f).

When Debix contacted Equifax, they were acting on my behalf, they asserted in good faith that I had a suspicion that I would become a victim of fraud, and they provided Equifax with more than enough identifying information for Equifax to positively identify my credit record.

Unfortunately, the FCRA doesn't actually define what constitutes appropriate proof of identity. However, since the other two credit agencies accepted my filing and activated fraud alerts, that would seem to imply that they thought I provided enough proof.

Why are Equifax's requirements more stringent? How does this protect consumers in any way? Their strictness doesn't provide any additional protection for consumers. What kind of identity thief would actually want to activate a fraud alert? And even if they did, what good would it do them?

The identity thief would get a phone call the next time I tried to open a line of credit and they would be able to allow or deny the creation of that account. If they allowed it, they'd derive no additional benefit (since they already have my identity). If they denied it, I would instantly know that something was wrong and could contact the credit agency to get things sorted out.

The only thing Equifax's refusal does is cause me more inconvenience and increase the risk that an identity thief will be able to get away with committing fraud using my identity while I'm trying to figure out how I can possibly give Equifax more proof than I already have.

Thanks Equifax.

T-Mobile's cell coverage sucks

Friday April 27, 2007 @ 10:31 AM (PDT)

I've been a T-Mobile customer for five or six years now. I've bought several phones from them and renewed my contract several times. While I'm generally pleased with their prices and customer service, their coverage absolutely sucks.

Even in some heavily-populated urban areas, I often have trouble getting a signal. Until recently, I thought this was perhaps just a problem with their Oregon coverage. Beaverton and Hillsboro, where I spent most of my time, aren't exactly huge cities, and I tended to live on the outskirts of town.

And yet, since moving to the San Francisco Bay Area, the coverage hasn't gotten any better. The Bay Area is teeming with people. San Jose, where I spend most of my time, is the largest city in Northern California, and yet, in many places in the city, I'm lucky if my phone's signal indicator shows a single bar. At Yahoo!'s Sunnyvale campus I usually can't get any signal at all.

When the iPhone was announced earlier this year, I was disappointed that I would have to switch to Cingular if I wanted one. Now I'm really looking forward to it.

In part 1 I showed you how to speed up page rendering by moving a remote JavaScript include (a Flickr badge in the example) into a hidden <div> at the bottom of the page and using a few lines of code to drop it into the desired location once it it's loaded. In this article, I'll show you how to use the Yahoo! UI Library's Animation Utility to make your dynamically-loaded content fade in smoothly so your visitors aren't distracted by its sudden appearance.

First we need to load the YUI libraries. To do this, we'll add the following lines just above our hidden "fakeflickr" <div> from part 1:

<script src="http://yui.yahooapis.com/2.2.2/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script src="http://yui.yahooapis.com/2.2.2/build/animation/animation-min.js"></script>

<div id="fakeflickr" style="display: none;">
  <script src="http://www.flickr.com/[...]"></script>
</div>

This will load the necessary libraries from Yahoo!'s own servers, which are so fast I heard they once did the Kessel Run in less than twelve parsecs.

Next, we'll need to add a teeny bit of CSS to give our "flickr" <dd> element a fixed height. This will keep the page layout from having to adjust when we populate that element with the Flickr badge content.

To figure out what height you should use, I recommend using Firebug to inspect the element and see what its height is once the badge is loaded. Then use that number in the CSS below, which you can either put inside a <style> tag in the page header or add to an external CSS file:

#flickr {
  background: url('loading.gif') no-repeat 48% 48%;
  height: 161px;
}

Notice the background image? You can grab that from ajaxload.info. It'll clue our visitors into the fact that the content in that area is being loaded in the background, so they'll be less surprised when they see it fade in.

Now all we need to do is make a few modifications to our JavaScript snippet from part 1 to make the Flickr badge fade in:

<script type="text/javascript">
  var flickr     = document.getElementById('flickr'),
      fakeflickr = document.getElementById('fakeflickr'),
      anim       = new YAHOO.util.Anim(flickr, {opacity: {to: 1.0}}, 1,
          YAHOO.util.Easing.easeBoth);

  YAHOO.util.Dom.setStyle(flickr, 'opacity', 0.0);
  YAHOO.util.Dom.setStyle(flickr, 'background', 'none');

  flickr.innerHTML = fakeflickr.innerHTML;
  fakeflickr.innerHTML = '';

  anim.animate();
</script>

And we're done. Easier than you thought it'd be, wasn't it?

Lots of social services like Flickr and del.icio.us provide JavaScript snippets that you can include in your web page to display your latest photos or bookmarks or what-have-you.

Unfortunately, if you want to place the snippet near the top of your page, this means that the rendering of the entire page gets held up until the snippet finishes loading, which can be a big inconvenience if the remote server tends to be slow to respond (I'm looking at you, Flickr).

I recently got fed up with this and decided to do something about it. Here's how you can keep your Flickr badge (or any other JavaScript include) from slowing down page rendering with just a few lines of code.

For the sake of this example, let's say we have a very basic web page like this one:

<html>
  <head>
    <title>Bob's Ninja Page</title>
  </head>
  <body>  
    <div id="page">
      <div id="sidebar">
        <dl>
          <dt>Flickr Photos</dt>
          <dd id="flickr">
            <script src="http://www.flickr.com/[...]"></script>
          </dd>
        </dl>
      </div>
    
      <div id="content">
        <p>
          Ninjas are awesome.
        </p>
      </div>
    </div>
  </body>
</html>

Since the Flickr badge is being included early in the page, it'll slow things down and annoy our readers, who are very eager to learn about ninjas. To prevent this, we'll add a new hidden div at the very bottom of the page, just before the </body> tag, and we'll put the Flickr JS include inside that div so that it won't load until after the rest of the page:

<div id="fakeflickr" style="display: none;">
  <script src="http://www.flickr.com/[...]"></script>
</div>

Now we've solved the performance problem, but there's no way for visitors to see our Flickr badge since it's hidden. We'll fix that with a bit of JavaScript, which we'll add just after our hidden div:

<script type="text/javascript">
  var flickr     = document.getElementById('flickr'),
      fakeflickr = document.getElementById('fakeflickr');

  flickr.innerHTML = fakeflickr.innerHTML;
  fakeflickr.innerHTML = '';
</script>

This works because the browser won't execute that snippet until after it executes the Flickr include, so by the time our code runs, we know that the hidden div contains the badge HTML. All we need to do is move that HTML into the real badge container, and voila, problem solved.

Of course, this will result in the Flickr badge suddenly appearing in the sidebar out of nowhere, which might be a little distracting if the visitor has already started reading about ninjas. As you may have noticed, I've tried to minimize that distraction on wonko.com by having the Flickr badge fade in gradually.

Tune in tomorrow for part 2 to learn how to add this animation to your own pages. It's easier than you might think.

I happened to be looking at the raw headers of an email today and noticed something weird. The message had been sent to me from a local user on my server, so it had never actually left the server; however, SpamAssassin had given the message a couple of spam points because it said the SPF verification had failed. I double-checked the relevant SPF records and there was nothing wrong there, so I began to suspect there might be a bug in SpamAssassin's SPF verification routine.

I tried sending an email from my server to a Gmail address (this is a good way to test SPF records, since Gmail adds headers to messages indicating whether the SPF verification succeeded). Sure enough, Gmail's SPF verification succeeded. I also sent messages to a few standard SPF test services, and they all indicated success as well. Furthermore, mail sent from Gmail to my server didn't result in an SPF failure, so SpamAssassin was verifying Gmail's SPF record correctly, but not mine.

Finally, after staring at the email headers for a few more minutes, I realized what was happening. SpamAssassin wasn't buggy; it just didn't have all the information it needed.

When a local user on my server sends mail to another local user, the mail server only adds a single "Received" header to the message, and the "from" IP in this header is the user's IP (in this case, a dynamic Comcast IP). If the email had originated from an outside mail server like Gmail, it would have had at least two "Received" headers—one for Gmail and one for my server—and SpamAssassin would verify the SPF record by checking that the handoff from Gmail to my server came from a valid IP. But since this message appeared to be originating from a dynamic IP, SpamAssassin had no way of knowing that the message actually originated on the local server, because it had no way of knowing that the user had been authenticated via Postfix SMTP auth.

As it turns out, all I had to do was tell Postfix to add a header indicating that the sender was authenticated, and then SpamAssassin was happy. Putting the following line in Postfix's main.cf file did the trick:

smtpd_sasl_authenticated_header = yes

I spoke too soon

Wednesday April 18, 2007 @ 09:16 PM (PDT)

You know what I said before about broadband sucking in the Silicon Valley? I take it back. Comcast turned on our connection yesterday, and while they advertise it as 6Mbps/384Kbps, I'm actually seeing speeds as high as 12Mbps/1Mbps!

Maybe I just have good Internet karma.

I find it highly ironic that the most residential bandwidth I can get for a reasonable price in the heart of Silicon Valley is 6Mbps/384Kbps for about $65 a month from Comcast. In Oregon, I was paying the same amount to the same company for a blazing 12Mbps/768Kbps.

I love E

Wednesday April 11, 2007 @ 01:15 PM (PDT)

E is my new favorite text editor.

It's been around for a while, but it just recently started gaining a lot of momentum when the author made it his mission to turn e into TextMate for Windows.

In addition to supporting TextMate themes and bundles, e has an unlimited, branching undo buffer and built-in support for personal revision control, both of which are impossible to do without once you start using them.

If you write code in Windows, you owe it to yourself to try e.

Copyright © 2002-2008 Ryan Grove. All rights reserved.
Powered by Thoth.