Archived Posts

Displaying posts 11 - 20 of 628

LazyLoad 2.0.0 released

Thursday August 06, 2009 @ 09:42 PM (PDT)

After quite a while without updates, I’ve finally released version 2.0.0 of LazyLoad.

LazyLoad is a tiny (only 1,541 bytes minified), dependency-free JavaScript library that makes it super easy to load external JavaScript and (new in this version) CSS files on demand. It’s ideal for quickly and unobtrusively loading large external scripts and stylesheets either lazily after the rest of the page has finished loading or on demand as needed.

In addition to CSS support, this version of LazyLoad also adds support for parallel loading of multiple resources in browsers that support it. To load multiple resources in parallel, simply pass an array of URLs in a single LazyLoad call.

Downloads

Usage

Using LazyLoad is simple. Just call the appropriate method — css() to load CSS, js() to load JavaScript — and pass in a URL or array of URLs to load. You can also provide a callback function if you’d like to be notified when the resources have finished loading, as well as an argument to pass to the callback and a scope in which to execute the callback.

// Load a single JavaScript file and execute a callback when it finishes loading.
LazyLoad.js('http://example.com/foo.js', function () {
  alert('foo.js has been loaded');
});

// Load multiple JS files and execute a callback when they've all finished.
LazyLoad.js(['foo.js', 'bar.js', 'baz.js'], function () {
  alert('all files have been loaded');
});

// Load a CSS file and pass an argument to the callback function.
LazyLoad.css('foo.css', function (arg) {
  alert(arg);
}, 'foo.css has been loaded');

// Load a CSS file and execute the callback in a different scope.
LazyLoad.css('foo.css', function () {
  alert(this.foo); // displays 'bar'
}, null, {foo: 'bar'});

Supported Browsers

  • Firefox 2+
  • Google Chrome (all versions)
  • Internet Explorer 6+
  • Opera 9+
  • Safari 3+
  • Mobile Safari (all versions)

Other browsers may work, but haven’t been tested. It’s a safe bet that anything based on a recent version of Gecko or WebKit will probably work.

Caveats

All browsers support parallel loading of CSS. However, only Firefox and Opera currently support parallel script loading while preserving execution order. To ensure that scripts are always executed in the correct order, LazyLoad will load all scripts sequentially in browsers other than Firefox and Opera. Hopefully other browsers will improve their parallel script loading behavior soon.

Sadly, Firefox, Safari, and Google Chrome don’t provide any indication when a CSS file has finished loading. In these browsers, CSS load callbacks will execute after a short delay, but there’s no way to automatically guarantee that the CSS has finished loading before the callback is executed. Luckily, there’s a fairly painless manual workaround that you can use to detect when CSS has finished loading, but it’s not possible for LazyLoad to do it for you.

Chase followup: the check's in the mail

Wednesday August 05, 2009 @ 10:16 AM (PDT)

Yesterday marked the end of the seven full business days Chase said it would take them to respond to my claim, but I hadn’t heard a thing from them, so I called them this morning. They said a refund check was mailed today. Assuming they’re telling the truth, it looks like I won’t have to go through the hassle of disputing the ACH transfer with my bank.

Hopefully this will be the last time I ever have to deal with Chase.

Earlier this month I paid off a car loan I had through Chase. You may remember that I’ve had a few problems with Chase before, so I was happy to finally be finished with them. Unfortunately Chase was not finished with me.

According to Chase’s website, my loan was paid off in full on July 6th and the account was closed on the 8th. On July 9th, I received a letter from Chase notifying me that the account had been “fully satisfied”, along with a small overpayment refund check.

On July 21st, 13 days after my account was supposedly closed and 12 days after Chase had informed me in writing that the loan was fully satisfied, Chase withdrew a payment of $687.10 from my checking account (which is at another bank).

I noticed the withdrawal late Thursday night and immediately filed a transfer inquiry via Chase’s website telling them to refund the erroneous charge. Friday morning I received a response saying that the payment was not erroneous and had been submitted according to my instructions. I was told to call a 1-800 number to request a refund.

I called the number immediately, waded through the usual onerous phone menus, and eventually reached an operator only to discover that I had been given the number for Chase’s mortgage division, not the auto finance division. The operator gave me another number, which turned out to be the credit card division. Finally, after realizing Chase couldn’t be trusted even to get their own phone numbers right, I found the correct number on the website and reached a human being.

It was clear as soon as I explained the situation that this was not an uncommon occurrence. The representative I spoke to told me that Chase had withdrawn the payment because I had not deactivated my automatic loan payments after paying off the loan. I pointed out that the automatic payment authorization I had given authorized Chase to withdraw payments “for the life of the loan”, and that since I had paid off the loan and Chase had informed me the account was closed, I expected the “life of the loan” to be complete. I’ve paid off three other auto loans through various banks over the years, and this has always been the case.

She countered that Chase’s interpretation of “for the life of the loan” is actually “for the original terms of the loan”. Since it was a 72-month loan and I had paid it off in 13 months, Chase would continue withdrawing payments for the full 72 months unless I manually canceled the automatic payments.

“So, if you keep deducting money from a customer’s account when there’s nothing for that money to actually pay for, where does the money go?” I asked her.

“It goes into a holding account until the customer calls and asks for a refund,” she replied.

I pointed out that that’s exactly what I was doing, and she said that I needed to fax an explanation and a copy of my bank statement showing the withdrawal to Chase’s research department, which would “investigate my claim”.

“I’m not making a claim,” I told her. “I’m telling you to return the money that you stole from my bank account without authorization. That’s a fact, not a claim.”

She launched into another scripted explanation of the meaning of “for the life of the loan” and how it’s the customer’s responsibility to cancel the automatic payments.

“So you’re saying that because Chase is too cheap to develop working software, it’s Chase’s policy to hold customers’ money hostage until the customer proves, to Chase’s satisfaction, that their money is rightfully theirs?”

“No, you just need to call and ask for a refund.”

“I just did that and you told me I have to file a ‘claim’ with the research department so that they can ‘investigate’.”

“Well…yes…”

I gave up on the conversation, got the fax number for the research department, faxed them the required information, and have naturally heard nothing back. My money remains in limbo and, according to the woman I spoke to, may remain in limbo for seven business days before the research department concludes their “investigation”, if in fact they even received my fax in the first place.

If I don’t hear from Chase within the promised seven business days, I plan to contact my bank and dispute the withdrawal as fraudulent.

Update (2009-08-05): Chase says the check's in the mail.

This post was originally published on Techyard, an internal Yahoo! site. I’m republishing it here (lightly edited) since it’s relevant to this blog’s audience, and since it explains what I’ve been working on for the last few months that’s been keeping me from blogging.

One of the primary goals behind the design of Yahoo! Search Pad was to create a simple structured document editor that was fast enough and intuitive enough that it would be a viable replacement for the desktop apps (primarily text editors and, to a limited extent, Microsoft Word) that many people use to keep notes while doing research online.

To that end, it was important that Search Pad be as responsive as a desktop app while coexisting seamlessly with the web-based Search experience. It was also a strict design requirement that the user not have to install any browser addons or external apps in order to use Search Pad; it had to work perfectly and effortlessly in any A-grade browser.

Since a Search Pad document is really just a collection of notes, our original approach was to store the document in server-based session storage while it was being edited, with changes (new notes, deleted notes, updated notes, etc.) persisted to the server instantly via Ajax. Unfortunately, there were several major issues with this Ajax-heavy approach:

  1. Note changes occur very frequently in typical Search Pad usage, which meant we were firing off a lot of Ajax requests. This put a substantial load on our frontend servers.
  2. The frequent Ajax requests made the app feel very…well…Web-ish. It wasn’t slow, but it certainly wasn’t as responsive as a desktop app.
  3. Users had a tendency to work with their Search Pad documents in several tabs or browser windows at once, which created consistency issues since the document state was stored on the server and the multiple tabs/windows couldn’t be reliably kept in sync without significant complexity.
  4. Due to the stateless nature of HTTP and the fact that two nearly simultaneous Ajax requests might be dispatched to two completely different frontend servers and, indeed, might even be handled out of order, we were faced with the possibility of having to avoid asynchronous requests entirely in order to prevent race conditions and data loss

It quickly became apparent that these technical issues and the user frustration that resulted were simply not going to be acceptable, so we began working on an alternative: using client-side browser storage to store the active document entirely on the user’s machine during editing. This would eliminate the need for frequent Ajax requests and drastically simplify the server-side architecture while also making the app feel more responsive.

There was only one problem: not all A-grade browsers support HTML5 Storage yet. And of those that do support it, not all of them support all of it; since it’s not yet a finalized specification, there are implementation differences. Many web apps make use of Flash storage, Yahoo! BrowserPlus, or Google Gears to smooth out these differences, but since Search Pad could not require any browser plugins, those were all off the table.

Fortunately, while not all A-grade browsers support HTML5 Storage, all of them except Opera do at least support some form of usable client-side storage better than cookies. Since Opera accounts for only a tiny fraction of Yahoo! Search pageviews, we made the decision to go ahead and create a simple JavaScript storage abstraction library that would allow us to support all the major browsers including IE6 and 7. We’re hoping Opera will add support for HTML5 storage soon.

Here are the different storage layers our library uses in order to provide HTML5-like key/value storage on all supported browsers:

  • Firefox 3.5, Safari 4, IE8: HTML5 localStorage; these modern browsers all support the core localStorage functionality defined in the HTML5 draft.
  • Firefox 2.x and 3.0: Gecko globalStorage, a very early implementation similar to HTML5’s localStorage.
  • Safari 3.1 & 3.2: HTML5 Database Storage, because Safari 3.1 and 3.2 don’t support HTML5 localStorage.
  • IE6, IE7: userData persistence, a rarely used IE feature for associating string data with an element on a web page and persisting it between pageviews.
  • Google Chrome: Gears Database API, which is built into Chrome and thus doesn’t require a separate install. Surprisingly, Chrome doesn’t yet natively support any form of HTML5 Storage.

We’ve found that using client-side storage rather than making frequent Ajax requests makes Search Pad feel incredibly responsive, even on ancient browsers like IE6, while also decreasing the load on our frontend servers. In addition, being able to persist relatively complex data on the client between pageviews has opened up exciting new possibilities.

The YUI team and Mint.com’s Matt Snider are currently working on a client-side storage utility similar to (but more powerful than) the one we created for Search Pad. It’s slated for inclusion in YUI 2.8.0, which is currently scheduled for a Fall ’09 release.

The following email arrived in my inbox this morning:

From: Josh Hagen <Josh@lookingtoadvertise.com>
To: ryan@wonko.com
Date: Mon, Jun 1, 2009 at 10:12 AM
Subject: seattlemomblogs.com

Dear Blogger,

We are currently looking to sponsor ads or blog posts on websites associated with mothers. If you be interested in selling ad space or wish to write about an asigned subject, please contact us.

Sincerely,

John Young

I’m not a mom, nor am I a Seattle resident, nor am I a pirate (“If you be interested”?), but I do have a mom, so I guess that means my website is associated with mothers! I was so excited to be qualified for this once-in-a-blog opportunity that I could barely contain myself:

From: ryan@wonko.com
To: Josh Hagen <Josh@lookingtoadvertise.com>
Date: Mon, Jun 1, 2009 at 10:25 AM
Subject: Re: seattlemomblogs.com

Hi John (or Josh?),

I’d love to hear more. What subject would you like me (just call me Mr. Mom!) to write about?

- Ryan

A few minutes later I received a reply. And not just any old reply either; they put so much effort into this reply that it took two whole people to write it!

From: josh@lookingtoadvertise.com
To: ryan@wonko.com
Date: Mon, Jun 1, 2009 at 10:34 AM
Subject: Re: seattlemomblogs.com

Hey Ryan,

Would you be interested in writing about personalized checks from VistaPrint.com?

URL: http://www.vistaprint.com/checks-custom-multi.aspx

Thanks,

John and Josh

I was pleased that John and Josh were undeterred by my male name, and while — to the best of my knowledge — I have no offspring, I suppose the fact that my mom occasionally posts comments on my blog was enough to make J & J consider me an honorary mommy blogger.

This responsibility weighed heavily on me, though. I felt it was my duty to be the best mom I could be, and a mom can’t just endorse any old product. I wanted some assurances that this here VistaPrint was wholesome and educational before I’d give it Momma Ryan’s stamp of approval.

From: ryan@wonko.com
To: josh@lookingtoadvertise.com
Date: Mon, Jun 1, 2009 at 10:51 AM
Subject: Re: seattlemomblogs.com

Hey JohnJosh,

As a mother, it’s very important to me to instill a strong sense of financial responsibility in my children. Can you tell me a little bit more about how VistaPrint’s personalized checks will help my wee kidlets learn good check-writing practices?

Also, do you have any checks with a Sin City theme? My kids and their little friends LOVE that movie, especially the part where Benicio Del Toro gets his throat slit and pretends to be a pez dispenser. They watch it and then run around all day taking turns playing pez dispenser. It’s so cute!

- Ryan

Unfortunately, my enthusiasm for Sin City-related financial edutainment seems to have overwhelmed poor JohnJosh. I never did hear back.

The Adventures of Qubit: Episode III

Sunday May 24, 2009 @ 12:36 PM (PDT)

Vitriol never helps

Thursday May 14, 2009 @ 09:46 PM (PDT)

With the rise of social networking services, a disturbing trend has emerged. Whenever Facebook changes their design or Twitter has a glitch (or removes a feature), users erupt in a spontaneous worldwide ragegasm.

If the change was intentional, they’re pissed because nobody consulted them. If it’s a bug, they’re pissed because it isn’t being fixed fast enough. Half of them are probably just pissed because their friends are pissed and they don’t want to feel left out.

Few of these vitriol-spewing angerballs seem to realize that the companies behind the products they’re pissed about are made up of actual people, and for the most part these people genuinely do not want to make their users unhappy. What’s more, thanks to the nature of social networks, many of these people — real people with real feelings — actually read this hate-filled asshattery and are affected by it.

When Twitter goes down, they’re not playing a cruel trick on you. When they change or remove a feature you like, it’s because they thought they had a good reason. Maybe they’re wrong. By all means, speak up when these things happen, but don’t be a dick about it.

As a developer, nothing makes me happier than going out of my way to fix a problem for a user who brings it to my attention politely. On the other hand, when a user implies that I’m a moron and makes angry demands, I’m not exactly going to feel motivated to respond to that person’s concerns. And it might just ruin my day.

The Adventures of Qubit: Episode II

Wednesday May 13, 2009 @ 10:50 PM (PDT)

The Adventures of Qubit: Episode I

Tuesday May 12, 2009 @ 09:43 PM (PDT)

Larch 1.0.1 released

Sunday May 10, 2009 @ 04:29 PM (PDT)

Larch 1.0.1 has been released. Notable changes in this release include the following:

  • Ruby 1.9.1 support.
  • Much more robust handling of unexpected server disconnects and dropped connections.
  • Added --all option to copy all folders recursively.
  • Added --all-subscribed option to copy all subscribed folders recursively.
  • Added --dry-run option to simulate changes without actually making them.
  • Added --exclude and --exclude-file options to specify folders that should not be copied.
  • Added --ssl-certs option to specify a bundle of trusted SSL certificates.
  • Added --ssl-verify option to verify server SSL certificates.
  • Added a new “insane” logging level, which will output all IMAP commands and responses to STDERR.
  • Fixed excessive post-scan processing times for very large mailboxes.
  • Fixed potential scan problems with very large mailboxes on certain servers.
  • POSIX signals are no longer trapped on platforms that aren’t likely to support them.

To install Larch via RubyGems, run:

sudo gem install larch

Visit Larch’s GitHub page for usage information and other documentation. If you have questions or need help with something, please use the Larch mailing list.

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