A Brief Introduction

I’m a married Software Engineer living in Seattle who is originally from Chicago’s western suburbs. I’m a 2007 graduate of MSOE‘s Software Engineering program and recently began a new job on Microsoft’s Exchange team and am working specifically on Outlook Web App. I’m currently working primarily with C#, HTML, CSS, and some JavaScript, but in the past, I’ve also worked significantly with Java applications built on Oracle databases. In my free time, I enjoy photography and more web development with PHP, MySQL, HTML, CSS, Javascript, and jQuery; my largest personal project has been for my dad’s business, DDM Garage Doors.

One of the authors of the Bible, Paul, writes, “If anyone speaks, let him speak as the oracles of God. If anyone ministers, let him do it as with the ability which God supplies, that in all things God may be glorified through Jesus Christ, to whom belong the glory and the dominion forever and ever” (1 Peter 4:11 NKJV). Though this web site is about me and who I am, my greatest desire is not that I look good but that it act as an instrument through whose music God uses me to proclaim Christ, His death and resurrection for the sins of the world, and the truths of His Word. My greatest desire is that my life would say with Paul, “For to me, to live is Christ, and to die is gain.” To learn more, I’d encourage you to read The Only thing in Life that Really Matters.

Please keep in mind that all content on my site reflects my own personal opinions, not those of my employer, Microsoft.

Below you’ll find my blog for posting updates in my life, changes to my web site, or just random thoughts going through my head. All posts since March 3, 2001 are available here. Enjoy!

git push

I’ve spent some time recently messing around with (learning) git. I needed a better solution for tracking changes to the work I do for DDM Garage Doors, Inc., and git seems to be the leading choice these days.

As part of this exercise, I also moved my C++ Examples from high school over to Github. I’m not convinced there’s much value in keeping this code up online, other than nostalgia. In addition to the rather rudimentary nature of most of the assignments, I saw several optimizations I could make to the code and realized that most of my interview questions at Microsoft and Google required more complex solutions. In any case, as the first code I ever wrote in a strongly typed OO language, it holds a special place in my heart.

PayPal Fraud and Poor Customer Service

After several months of inactivity on PayPal, I logged in to my account today to confirm that my address was correct. I noticed that a second address had been added to my profile, one that has not been used in any payment I’ve transacted.

So, I called PayPal support and chose the “fraud” option. The first lady I spoke with was able to identify when the address was added, and that it was added as a gift address, but told me not to worry about it … that I must have added it when making a payment. I explained to her that it was not related to either of my *two* PayPal transactions (the most recent of which was in January). I eventually was able to speak with someone with further insight into my account, who explained that someone had gained access to my account, added the address, tried to make a payment, and they had detected it as fraud. I was advised to change my password and security questions.

Contrast this with the fraud against my Discover Card this past spring. My CC was first denied, they locked down my whole account, and I had to get a new one. The card was denied before Discover had a chance to reach out to me, but I did receive a delayed phone call AND email notification that I needed to contact them about my account, after I had already called in to address the issue.

PayPal, you failed on four counts:

  1. You didn’t notify me that there was fraud against my account, and that I should change my password to avoid it in the future. Instead, I had to notice the issue two months later, and call you.
  2. You let the fraudulent address remain in my account profile.
  3. You blocked the email notification I should have normally received indicating that an address was added to my account.
  4. Your customer service rep … the one I reached when I said I was calling about fraud … told me not to worry about it.

Uploading .htaccess with FileZilla and Zero-Byte Files

I’m running FileZilla 3.6.0.2 at the moment, and just ran into an issue uploading an htaccess file. Every time I uploaded it, it would appear to transfer successfully, but then the server would report a zero-byte file. I tried renaming the file, no luck. Finally, I got the file to transfer by switching my connection mode to Active instead of Passive. Go figure.

FileZilla FTP Settings Dialog

Looks like there’s a FileZilla update. I’ll install that in the hopes of avoiding the issue in the future.

Edit >> Same issue with 3.7.3. Oh well. Active it is. I’d switch to SFTP; Fluid Hosting sent us a note awhile back stating that SFTP was now enabled but every time I’ve tried it, I’ve gotten a connection failure.

Working around Litespeed’s mod_rewrite intermittent 404 Issue

I use mod_rewrite all over the place. Who doesn’t these days? IIS 7 even has a URL rewriting module that will convert your mod_rewrite rules. But I digress.

I noticed a few months back that I’d get an occasional 404 error for a page that I know exists and is handled by a mod_rewrite rule. Within a few seconds, the access logs reported a URL matching the same rewrite rule with a 200 OK response. If I hit the URL myself after receiving notification of the failure, it would work. I concluded there’s some sort of bug in Litespeed and escalated to the Fluid Hosting support folks. They suggested that they are “pretty sure that Litespeed developers are aware of the issue” and that it is a known issue because a Google Search for “htaccess rewrite problem litespeed” yields lots of results. Not so convinced myself; most of those results are people confused about how to configure mod_rewrite. In any case, my problem is still not resolved, and I continue to receive emails when these 404s occur. Probably a few each day. Not only would I like to reduce some of the noise, but I also want to avoid losing business if someone happens across a 404 error. So, this evening, I set out to create a workaround.

The hypothesis I’m testing with this solution is that the 404 error resolves itself automatically within about a second. The gist of the solution is to add a custom 404 error handler that spits out some Javascript that retries the request and, if it receives a 200 response, replaces the body of the page with that content. After a threshold is reached, it will stop trying and display an error message.

I initially tried implementing this retry on the server side to keep the client unaware of what was going on. Although I had a way around it, the risk of infinite recursion (and consuming all the server’s threads) was greater than I wanted to accept. (I.e. 404 error handler calls the target page, which calls my 404 error handler again. Certainly adding a header or query param to the request could help avert this.)

So … I’d share the entire code for this solution but it’s embedded in all the rest of my error handling mess that I’d rather keep to myself for now. I dream of polishing off every little pet project I’ve got, but in reality, I can’t see it happening anytime soon. So, I’ll give you an outline of what I did and hopefully you can adapt the solution to work for your needs. I did this with PHP but these concepts should transfer to any language.

Configure a Handler for 404 Errors

This is as simple as adding the following line to your .htaccess file. If you don’t know what htaccess is, this solution isn’t for you … because you couldn’t have really gotten in this mess without it … unless WordPress or some other tool configured the problematic mod_rewrite for you.

ErrorDocument 404 /404.php

Determine your retry criteria

I don’t want to retry every request. I decided to restrict retries to GET requests matching a certain set of URL patterns that I know are handled by mod_rewrite rules.

function ShouldRetryRequest()
{
	$retryPatterns = array(
		"/blog\/.*/",
		"/errorSimulator/",
	);

	// Only retry GET requests. Is REQUEST_METHOD ever not set?
	if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] != "GET") {
		return false;
	}

	// Only retry if it matches our pattern
	foreach ($retryPatterns as $pattern) {
		if (preg_match( $pattern, $_SERVER['REQUEST_URI'] )) {
			return true;
		}
	}		

	return false;
}

Return 200 OK from your error handler

When you’ve decided you want to retry the request, you’ll want to be sure you return 200 OK from your script. Many modern browsers, when they see a 404 response, will return a “friendly” error message that tries to give the user an idea of what happened but probably only confuses him further. If you’re not retrying this particular request, go ahead and return 404. Returning 200 OK ensures your content will be displayed and executed. The other advantage to returning 200 OK is that if the search engine is the “user” who happens to hit this scenario, it won’t remove the page from its index … then again, it will have totally different content associated with that page, unless it evaluates and execute the Javascript I provide a little further on, so maybe we don’t really gain anything there.

You’ll notice that my Javascript retry code expects an error condition in order to retry; once it sees a 200 OK, it will simply display that content. If that content again is our error page with the retry script, you’ll get stuck in an infinite loop. So, be sure to continue to return a 404 for requests coming from the retry script. I’m simply returning 200 OK only when the attempt query param, added by the retry script, is not present. The web server, because it has reached my script through ErrorDocument, takes care of returning the 404 when the following condition does not match.

$retry = ShouldRetryRequest();

// Original GET/POST params are not passed to the error document, so can't use $_REQUEST
if ($retry && strpos($_SERVER['REQUEST_URI'], "attempt=") === false) {
	header('HTTP/1.0 200 OK');
}

Hide your <body> at page load

I’d recommend putting display:none on your <body> tag. The code below will either replace the content if the 404 issue resolves itself, or remove the display:none to show the error text if the maximum number of retry attempts is reached.

Return the script that will do the retry

Your error document needs to return the code that will do the retry. This is the bit of code I whipped up this evening. Whereas I typically prefer to put my scripts toward the end of the document, I wanted to get the first retry fired off as quickly as possible, so I put this near the top of my <head> tag.

I decided to use jQuery to take advantage of its friendly AJAX APIs, so you’ll want to be sure to include the jQuery script ahead of this one.

var retryCount = 0;
var maxRetries = 5;
// How long to wait between retries, in milliseconds
var retryFrequencyMS = 200;

var theUrl = window.location.href;
var params = { 
	attempt: retryCount, 
	log404: false // This tells my error handler not to do what it would normally do with this particular request
};


function retry() {
	retryCount++;
	$.ajax({
	  url: theUrl,
	  data: params,
	  success: function(html) {
		var newDoc = document.open("text/html", "replace");
		newDoc.write(html);
		newDoc.close();
	  },
	  error: function(jqXHR, status) {
		if (retryCount == maxRetries) {
			params['log404'] = true;
		}
		if (retryCount <= maxRetries) {
			params['attempt'] = retryCount;
			setTimeout(retry, retryFrequencyMS);
		}
		else {
			// Ensure body has loaded
			$(document).ready(function() {
				$(document.body).show();
			});
		}
	  },
	  dataType: 'html',
	  cache:false
	});
}
retry();

Testing the retry logic

I put together a second simple PHP file that simulates the intermittent 404 error. The first time it is hit, it returns our error handling code. Subsequent requests, it will respond with a 404 header, until a threshold is reached.


Success!

Finally, hit the simulated 404 script from your browser. Change the attempt threshold from 2 to a value above your retry count to simulate the behavior in which the server persists in returning 404s for all retry attempts.

http://localhost/errorSimulator.php

So … there it is. I’ve still got to put this code into production; it will be interesting to see if the volume of 404 error reports from this issue go down. I’m also interested in how long it takes for Litespeed to recover from this issue. I’ll provide updates if I find better values for the retry interval and/or maximum number of attempts.

Let me know how this works for you, if I can answer any questions, or if you spot any errors.

An Update…

Saturday, 2:20 pm PST – So, an hour or two after implementing the solution I described above, I got a report about one of these 404 errors. The script retried the page, but the server persisted in ignoring the mod_rewrite rule. Certainly I could introduce a greater delay between retries. But then it struck me … since this issue is occurring really with rules targeting a single script, why not use my error handler to forward requests to the script internally, instead of with a HTTP request. The script exists on the file system, so fake the PATH_INFO server variable, I include the script, and I’m in business.

Will continue to keep an eye on this and see how it works out.

Mt. Rainier at Midnight

Ellen recently suggested I take a picture of Mt. Rainier from our rooftop every day. (Or, on a cloudy day, where Mt. Rainier would normally be visible.) A few nights ago, I was going through the first months’ worth of photos and noticed that I can spot a faint shadow of Mt. Rainier in this shot I took around midnight on July 23rd.

Mt. Rainier is visible even at night ... if you look carefully

Transfer Angry Birds data from iPod Touch to iPhone

I recently (finally?) upgraded to a smartphone. I had been using a basic phone for quite some time and got the additional functionality offered by a smartphone by carrying my iPod Touch with me at all times … after all, I reasoned, WiFi is offered nearly everywhere. Anyway … it’s great to be carrying around a single device (the iPhone 5) that is thinner, faster, lighter, and all around way cooler than my LG EnV + iPod Touch combo. Plus, the iPhone’s GPS and 4G network will be helpful when we move out to Seattle later this month.

But, I was bummed to find that my Angry Birds game data got lost in the transition from the iPod Touch to the iPhone. I had both devices syncing application data to iCloud, but when I loaded up Angry Birds for the first time on the iPhone, it appeared I’d have to start from scratch. When I first got the iPod Touch, I played the series of games quite frequently, so starting over then wouldn’t have been a problem. But now my relationship with the game is more casual, so I didn’t want to have to redo all those levels again. So, today, I set out to find a solution.

After a little research, I learned about a few tools that will allow you to access the iOS device’s file system and transfer data to your computer. After quickly following Angry Birds Nest’s tutorial on transferring game progress, I’ve got all my Angry Birds data on my iPhone.

Sigma 17-70 Lens Profile for Lightroom 3

I went out shooting this afternoon with my Sigma 17-70 f/2.8-4 OS to test it out after getting the AF adjusted to correct a severe rear focus issue I was encountering. It turned out I’d accidentally reset my D90 from RAW to JPEG and when I went to edit the images in Lightroom 3, I discovered that it couldn’t find a matching lens profile. A quick Google search led me to learn that the list of available lens profiles differs when editing a JPEG vs one of the RAW formats. I went back and checked some images I’d taken earlier and sure enough, the profile appeared.

So, for anyone else who is wondering … Several of Sigma’s lenses can be corrected in Lightroom only when you shoot in RAW. Apparently on a Windows 7 PC you can find the list of lenses supported in RAW at the following location:

C:\ProgramData\Adobe\CameraRaw\LensProfiles\1.0\Sigma\Nikon
(replace Nikon with your camera body manufacturer)

Source: Lightroom Forums – Lens profile – Sigma 17-70 F2.8-4.5 DC Macro

Comparing the Nikon D90 and Canon T1i/T2i

Several months ago, I picked up a used Nikon D90 and two lenses to replace my broken Canon G7. I’ve got the 50mm f/1.8 lens and the kit 18-55mm f/3.5-5.6 VR lens.

When I finally decided to get a traditional SLR rather than micro four-thirds, I was trying to decide between the Canon T1i and T2i. Several friends have one of these two and had let me explore: Aaron Eberline and Stan Lemon both have a T1i, my brother and a friend from high school have a T2i, and one of my wife’s bridesmaids has an XSi or XTi. I ultimately picked the D90 over either of these primarily because of a deal I found on Craigslist; I got the camera, lenses, flash, tripod and backpack for $1000 (Sept 2010). I was much less familiar with the D90, but the D90 and the T2i were the two SLRs that my brother had selected from, and a guy at Mike Crivello’s told us that both were excellent cameras, even though the T2i was released much more recently than the D90. Additionally, I found a real helpful review that essentially said they’re very similar in image quality.

After using the camera for a few months, here are some highlights about what I like better about the Nikon:

  • The D90 has two dials, one for shutter speed, and one for aperture, whereas the T1i/T2i has only one. On the Canon if you want to change the aperture, you’ve got to hold down a different button while spinning the dial.
  • On the D90, the ISO can be set in 1/3 stops, while I believe the T1i/T2i only allow full stops.
  • The D90 will display the current shooting settings both on the LCD on the back AND on a small grayscale LCD on the top of the camera, next to the shutter. The extra LCD on top is a handy feature that Canon reserves for the 50D, 7D, and maybe 60D?
  • My brother seems to think many of the less expensive (non-pro/”L”) Canon lenses have a cheap feel to them. He thinks my 18-55mm kit lens is better than Canon’s competition.

But, there are still some things I prefer about the Canon:

  • On the T2i, the camera will still meter with manual focus / non-CPU lenses. On the D90, you can only get some semblance of metering if you’re in Live View. This is really a bummer for me because I was hoping to pick up some cheap used manual focus lenses to play with. You’ve got to move up to the D300 (or maybe the D7000?) if you want metering on these older lenses.
  • The T2i has a much higher resolution than the D90, but if you read the article above, you’ll find that it doesn’t necessarily give it much of an advantage.
  • It seems to me that the T1i/T2i have less grain at higher ISOs than the D90. I’ve got nothing conclusive on this, but some article suggested that they performed nearly the same in low light, up to 1600, after which both were “unusable”. I guess it all depends on your needs.
  • On both the T1i/T2i and D90, the LCD screen on the back shuts off every time I push the shutter half way down (to autofocus, meter, etc.), but on the Canon the display turns back on when you release the shutter. I’ve looked through all the menus on the D90, read through the manual, looked online, and I cannot find a way to configure this differently on the D90. There also aren’t any firmware updates that allow me to configure this.

If I were looking to buy a camera now, I’d definitely look again at the D90 and T2i, but I’d also have to take a close look at the Canon 60D and Nikon D7000. I believe those are both in the same price range as each other but are more expensive than the D90 and T2i.

A few tips for anyone who is looking at buying a DSLR:

  • DPreview.com has lots of helpful reviews and a nifty flash app to compare camera performance side-by-side at various ISOs. (E.g. Compare ISO 800 on the D90 to T2i).
  • KenRockwell.com has tons of helpful reviews, especially about Nikon gear. I’m always reading his review of lenses I find on Craigslist. He makes some interesting observations and camera recommendations.

You can view some of my photos on my Flickr page.