2009-03-12

Right-click for everything?

I don't easily remember names. I can meet someone, have an hour-long conversation with them, and completely forget who they are by the next day. It's very embarrassing. When I was younger, I used to daydream about a contact lens or something that would give you a sort of "on-screen display" so when you came up to someone, it would display that person's name.

At the Technology, Entertainment, Design conference, MIT demoed a wearable "sixth sense" computer that would do just about that. And more. Using a camera and a projector, it basically replicates some of the Microsoft Surface technology, except the "surface" isn't a fixed tabletop; it's the world. It's as if you could right-click on anything you could see and be more or less instantly presented with information about it.

Well, and then some. You can also take pictures simply by framing the picture with your fingers, dial a phone by holding out your hand and pushing the buttons that are projected onto it, check the time by holding out your wrist and reading the clock projected there…

The demo video is at the link above, and it's well worth watching if nothing else then just because it's wicked cool.

2009-03-02

Bandwidth for February

Here's February's stats:

22.66GB down, 6.60GB up, 29.26GB total. For being a short month, it comes in barely behind January in total monthly usage. 11.7% of the cap. Since September (6 months), 177.97GB used total, or 71.19% of the allotment for a single month.

2009-02-22

My Answering Machine has a Name -- and a Debt

The random debt collection continues. Recently, I've been getting calls from a machine that go something like this [the names have been changed to protect the nonexistent]:

normal female voice This is an important call for…
deep, robotic voice JAMES WARNER
normal female voice If you are…
deep, robotic voice JAMES WARNER
normal female voice Please press 1 now. If you are not…
deep, robotic voice JAMES WARNER
normal female voice Please press 2 now.

I press 2.

normal female voice If you need some time to get…
deep, robotic voice JAMES WARNER
normal female voice Please press 1 now. If…
deep, robotic voice JAMES WARNER
normal female voice Is not available, please press 2 now.

I press 2, and the normal, female voice tells me how important this call is for (deep, robotic voice) JAMES WARNER, and the call ends. Unfortunately (and, in retrospect, I guess I should've expected such), there was no way to specify that there is no "James Warner" at this number, despite it being a "Warner" residence.

I've been getting a lot of these calls lately, but my answering machine picked up an interesting variant recently. It went like this:

normal male voice This is an important call for…
deep, robotic voice JAMES WARNER
normal male voice If you are not…
deep, robotic voice JAMES WARNER
normal male voice Please hang up now.

My answering machine fails to hang up.

normal male voice By staying on the line, you confirm that you are…
deep, robotic voice JAMES WARNER

The message goes on to offer "James Warner" (the new name for my answering machine) time to get some privacy for this "very important call", and then to tell "James Warner" that this call is to obtain information to collect a debt (surprise), and please call some 1-800 number.

So apparently, my answering machine has now accepted a new name and, by extension, responsibility for a debt. Not that I believe for a second it would hold up in any legal venue.

It'd be almost amusing if my phone wasn't ringing twice a day with these automated calls.

2009-02-12

I don't like all those decimals anymore

So I'm working on a project, and I'm using the SQL Server CE engine as my database. The database engine recently had an upgrade to 3.5.1, so when my client got a new computer and needed to install my program on it, the upgraded database engine was what was downloaded from Microsoft's web site. I didn't think much of it, as I had downloaded it as well, and I hadn't had any issues. However, when he started using the program with real-world data, he got an error:

SqlCeException: 'A parameter is missing. [ Parameter ordinal = 1 ]'

Ok, maybe I goofed. Perhaps in one of my updates, which added a column to one of the tables, I left off a parameter. So I tested the code on my machine, and it of course performed flawlessly.

I went to the client's site and tested it there. Sure enough, there was the error. I copied his database and ran my code against it, in debug mode, and… yes, I finally duplicated the error. Well, at least that told me the error was real.

Then commenced the tedious task of analyzing the SQL command being constructed; ensuring that all parameters were accounted for, all columns were spelled correctly, and all parameter names in the statement matched the names of the parameter objects added to the command; comparing his database to mine to make sure all table columns were accounted for and of the correct types. Everything matched. There were no parameters missing, misspelled, or misplaced.

After I fully convinced myself that everything was in order, I finally went to Google with the full text of the error, and I was fortunate to stumble across a bug reported on Microsoft's Connect site that indicated a problem with decimal values in SQL CE 3.5.1 under "certain conditions". Fortunately, the workaround listed helped me identify those conditions and what to do about them: it has to do with the number of decimal places one attempts to pass to SQL CE.

Fortunately, when building parameters, I pass every value through a function that checks for null and converts to DBNull (I have yet to hear a convincing reason why these must be different), and checks for bool types and converts true/false to 1/0. All I needed to do to fix this was to add code that checks for the decimal type and return Math.Round(value, 4) (although it took a little experimentation to determine that "4" was the correct number of decimals).

All because Microsoft decided they didn't like seeing all those decimal places anymore; and instead of rounding or ignoring them like they did in a previous revision, suddenly they were going to throw a completely incorrect error message (no parameter was missing, and the one it suddenly found "questionable" was not in position 1).

2009-02-11

What are you, Picasso(.Net)?

There is a form in our application that draws very, very slowly. I'm trying to fix that.

In .Net, you have very little control over a border. In many cases (in particular, in this instance, with a Panel), you only get to set whether or not the control has a border, and whether that border is solid or rendered with a 3D effect. If you want more control over the border (such as setting its thickness or color), you have to draw one yourself. Since WinForms.Net has no "Line" control, this means you have to draw the line on the form at runtime by subscribing to the form's Paint event and inserting your line-drawing code there.

You have slightly more control over a background, being able to set the color in most cases; but if you want anything fancy like a gradient, it again requires custom paint code.

It is, therefore, not surprising that we have quite a few Paint event handlers on this particular form.

The layout of our form is as follows:

  • There is data in a couple panels at the top of the form.
  • There are submit and cancel buttons in a panel at the bottom of the form, along with an information panel.
  • In the center of the form is a large area. This area (which is itself a panel) contains one to many user controls.
  • Each user control is designed first as a panel.
  • The panel contains five "header-style" panels and three user controls.
  • The top-most and bottom-most header panels contain summary information — the top being the name of this whole grouping of data, and the bottom being a subtotal.
  • The middle three header panels contain a summary of the data on each of the "sub-user controls", plus a button that hides or shows that user control.
  • On load, the sub-user controls are hidden, so a "collapsed" view of all header panels is shown.
  • The header panels are filled with a gradient fill. This gradient creates a much more visually-appealing division between header rows than solid colors with lines between them would do. (There are lines between them as well, but even with 3pt black dividing lines, solid colors just blend together across those lines in a way gradients don't.)
  • There are drawn borders around each header panel, and around the entire user control itself. There are also separator lines between most of the panels on the form elsewhere.

I thought maybe the gradient fill was just causing too much overhead, but when I replaced it with a solid fill, it had no effect on the overall speed of the form. So, I put debug code in all the Paint event handlers, to see how often the paint events were firing, as I figured this might be the source of my problem. The paint events for each of the panels on the main form fired 2-10 times each (the one panel containing the user controls firing the most often). The paint events for the innermost user controls (the "sub-user controls") fired three times each, which made sense given there were three sets of them loading — except for the first of the group, which fired six times (twice per control).

The containing user control is where things go insane. There are three of them, remember, containing five header panels and three (hidden, at startup) user controls inside. The header panels' paint events fired 5 (for the header itself) to 25 (for each of the sub-controls' headers) times each (which, I suppose, you can divide by 3 to get approximate firings per control). The user control's large panel containing all child controls (header panels and sub-user controls), its paint event fired 651 times, and the paint event for the user control itself fired 747 times!

And that's just when the form is created. I added a button that resizes the form by increasing the width by about 10 pixels, just to see the effect, and I got 153 panel paint events and 168 control paint events.

The maddening thing is, the user control's paint event handler is empty. It does nothing (except for the debug code that notes the firing). Oh, it did do something — it did draw a gradient pattern under the entire control — but since the drawing it was doing was completely covered by all the controls that were placed on top of it, I removed it.

The panel's paint method actually does something — it draws a heavy border around all the subordinate controls. And, aesthetically-speaking, it's really needed. What I can't understand is why exactly it's needed over 200 times per control, especially when the containing and contained controls combined aren't getting painted as often (by a factor of about 7).

So, what's my solution? Well, aside from making sure the paint events did as little work as possible (why is e.Graphics.SetClip(e.ClipRectangle) not automatic in a Paint event?), drawing gradients in Rectangle rect only if (e.ClipRectangle.Contains(rect) || e.ClipRectangle.IntersectsWith(rect)), and then only in the part rect.Intersect(e.ClipRectangle); but I also completely unbound the Paint event handlers in the user control, and instead of drawing a thick border on the panel, just used the default BorderStyle.FixedSingle.

It's still slow, although not as slow as it was (I'm sure those events are still getting fired, just with no custom code to process); and it doesn't look the same with the change in border, but there's enough padding between user control instances that I think I can get away with it.

In short, I didn't solve the problem; I still can't find the cause, and I've only been marginally successful in treating the symptom.

2009-02-08

A Whole New Url

I've had the domain yakkowarner.com for a couple years now. I originally used it when I decided to try out Microsoft's Office Live service. Well, I didn't really have any use for it, so I thought the URL could better serve me elsewhere.

Microsoft doesn't provide an easy-to-find link to instructions for how to grab your domain name, so I tried the back-door approach: I contacted the registrar to request a domain transfer. I got to send my very first international fax, to Melbourne, Australia. Excitement. (I actually had to do it four times. The first one didn't go through, the second one I realized I put the paper in upside down [oops], the third time didn't go through again.) Doing so prompted a tech rep from Microsoft's Office Live team to send me a very helpful and detailed message, with links, with exactly what I needed to do to release my domain so I could transfer it to my control.

So, welcome to www.YakkoWarner.com! It's the same blog with an easier-to-type address. :)

2009-02-06

Live CNN video turns your PC into a P2P server

Here's something I think should get a little more attention. According to Windows Secrets, CNN's live video streaming application turns your PC into a peer-to-peer video server, using your PC to stream the video to other PCs as well.

Personally, I don't find anything wrong with the concept. World of Warcraft uses similar technology to improve the speed of distribution of their software updates. It's what P2P tech is good for. Windows Secrets takes exception to the fact that CNN isn't exactly forthcoming about what is happening, though, and rightly so. If they came out and said what was happening when you were asked to install the "Octoshape add-in for Adobe Flash Player", then it would be less of an issue — people tend to be much more forgiving if you're up front about what you're doing. (Granted, there are other valid concerns about CNN's use of Octoshape posted there, but I won't address those here.)

What makes this such a large concern is that they are using other people's bandwidth, without their notification or explicit consent, at a time where many people's ISPs are capping their usage. The ISPs have declared that we must be conscious of how much data we consume and produce. Having an application that is uploading up to three times as much data as it's downloading, especially without our knowledge, is an issue, when every byte is being counted.

On the one hand, I fully support the concept of new technologies that help to distribute content efficiently. I don't think Blizzard is wrong to use it in distributing WoW patches, and I don't think CNN is wrong to use it in distributing video. (Again, the other issues that Windows Secrets brings up — specifically, "deceptive marketing", "ludicrous license terms", "security vulnerabilities", etc., are worth criticism, but are out of scope here.) However, they're trying to shift the cost to the end users, and we may not have the cost to spare, now that we're being limited.

I know it probably seems odd to hear me complain about bandwidth caps when mine is so large compared to what I use, but as I've said before, knowing I have a limit makes me much more conscious of the throughput I generate, and it makes me much more sensitive to anything that increases that value. Besides, just because I'm fortunate to have a wide use-to-limit margin doesn't mean everyone else is — or that I'll always be, for that matter.

2009-02-01

Bandwidth for January

It's a new month, and a new set of data for my ongoing bandwidth analysis.

There's a big spike around the 9th and 10th. Tech-savvy users may recognize this date as the day the Windows 7 beta was released. I downloaded both the 32-bit and 64-bit releases for testing. (My laptop has a 64-bit CPU, but it came pre-installed with a 32-bit version of Vista. I wanted to test how it would do upgrading to the next 32-bit OS, and how it would compare running in its native 64-bit mode.) If the downloads could've completed within the one day, it would've been the single largest day since I started tracking. As it stands, however, the 9th is only my second-largest day of consumption; the record still maintained by one day in October watching streaming video of my church's general conference.

The total for the month comes to 24.64GB down, 5.44GB up, 30.08GB total. This puts it second behind October, at 37.77GB total. My total data consumption for five months, up and down, is 148.71GB, still under the 250GB cap for a single month.

What's kind of interesting, though, is that there is news that Comcast is about to launch an online backup service. They'll have a tiered pricing plan, where you can purchase up to 200GB of online storage at a monthly rate. But, according to a Comcast representative in the linked article, transfer to and from this service is not exempt from the bandwidth cap. So, they'll be offering a service whereby you pay to use it (a lot more than you could find from other providers, too), but if you use what you pay for, you'll come close to having them cut you off of the internet. <sarcasm>Oh yeah, sign me up for that…</sarcasm>

2009-01-23

Sending email in C# - Maybe there *is* a way

Almost a year ago, I was bemoaning the fact that sending email is hard. Well, recently, my client went from a PC to a Mac, and he needed some help installing the program in the virtual XP session. When I was there, I set up the Outlook Express client so that the PDF statements could be emailed out from the virtual XP world. I figured that, since I know his email client, perhaps I could find something specific to that client for sending email.

Googling around for sending email from C# with Outlook Express, I eventually came across this CodeProject article: Programmatically adding attachments to emails in C# and VB.NET. I took the code and dropped it into my project pretty much as-is. My development machine is now a Windows Vista laptop, but this code worked just fine, starting up a Windows Live Mail window with the file attached.

There were a couple issues. One, if Live Mail wasn't started first, then I'd get an error from the MAPI call — apparently the client needs to be initialized before the call is made. (The MAPI call was starting Live Mail, but Live Mail did not appear to be in a ready state then the email was sent to it.) The second is that the SendMailPopup call (which is the one I want) blocks until the email message is closed (i.e. sent or discarded). The comments in that article, however, mention a method to split that call onto another thread, so I should be able to prepare and open several emails at once.

So I think I will create a configuration parameter that will allow the toggling of attempting to use MAPI. It should work, but it'll be preferable to have something to fall back on.

Incidentally, a discussion thread over at Channel 9 pretty much summed up the problem as such:

  • If you have Outlook, you can do it. (Use Outlook automation)
  • If you have a MAPI profile (e.g. Outlook Express), you can do it.
  • If you have SMTP, you can do it. (System.Web.Mail standard)

To which I'll add:

  • If you don't know what you have, you can try it. (mailto: link, attachments not supported)

Just for kicks, I tried this on my PC at work, which is running XP and has the Mozilla Thunderbird email client installed. It worked beautifully, whether I had Thunderbird running before I called SendMailPopup or not. I don't know if Outlook would also respond to this code or not. (I'll have to try the compiled program on my desktop with Outlook when I'm done.) If so, it could simplify things, as much as they can be considered "simplified" in what seems to be a complicated situation.

At least I'm in the fortunate situation that I'm writing this for a known, single client and a known configuration.

I do wonder why there's not a managed MAPI wrapper though. For my own convenience, I'm gathering emails into a collection of System.Web.Mail.MailMessage objects before I try sending them. Why is there no System.Web.Mail.Mapi.Send method? Maybe a System.Web.Mail.Mapi.IsClientRunning method, and so on.

2009-01-20

The Civility Project

My wife sent me a link to an article about two people with very different political, religious, and ideological views ended up forming a correspondence when one recognized and commended the other for acting courteously towards those who disagreed with him on several television appearances.

The two got together and realized that there is so much anger and divisiveness in America today, particularly about politics and religion. People talk and debate not to share ideas and encourage discussion, but to attack, divide, and belittle convictions and beliefs they don't agree with.

To that end, they came up with The Civility Project, a web site that encourages people to be civil by taking "The Civility Pledge":

  • I will be civil in my public discourse and behavior.
  • I will be respectful of others whether or not I agree with them.
  • I will stand against incivility when I see it.

The site also encourages people to post examples of civility and incivility reported in the media, and to comment on it — an open invitation to civil discourse.

It's a fairly new site, with not a lot of content as of yet, but I do hope it gets more attention. Wouldn't it be nice if people could just talk and listen, instead of berate and attack?

2009-01-12

I know you are listening

Either someone on the Aurora City Council is reading this blog, or it just so happens that that someone else had a similar complaint and was already in the process of changing something I blogged about earlier.

In this post, I suggest that the very large "Speed Limit 40" sign before the end of the school zone is very misleading. It's been this way since I've traveled this road, at least a couple years. And yet, I noticed when I took my kids to school as the school year started up again for 2009 that the very large "Speed Limit 40" sign has been removed, and now a much more normal-sized sign — one of equal size as the "End School Zone" sign — is posted instead, on the same post as the "End School Zone" sign.

Coincidence? Maybe I should test this theory.

You know, I find it annoying that large piles of generic cash don't randomly show up on my doorstep.…

2009-01-09

Bandwidth for December

I almost forgot to check my bandwidth for December — and it shows. Unfortunately, vnstat only keeps the daily stats for the last 30 days, so the daily stats for the beginning of December are lost:

 

However, the total stats for the month are stored: 20,391MB down, 6,449MB up, 26,841MB total. I'm not sure what accounts for the spike in activity on the 30th, but the 31st may have been caused by us watching the Times Square festivities on the internet (which for some reason had a lesser effect than whatever happened the day before).

Worthy of note this month is that I've started watching the online web series The Guild in high-definition on Xbox Live. Although HD, they are short, less than 10 minutes each, so the file size each is only a couple hundred Megabytes apiece, about once a week.

Totals are down about 700MB from last month, with December showing the lowest usage since I started monitoring.

2009-01-07

DTC and Windows Firewall - A Rant

Let me preface this by saying: If you're looking for a solution to getting Microsoft Distributed Transaction Coordinator (MSDTC) working through Windows Firewall, this is not the post you're looking for. No solution exists here.

I'm working on a project that is in three parts — a rich Windows Forms client, a Web Service business and data access layer, and a SQL Server database. The QA guy was having an issue where some web service calls were timing out, causing the application to crash. While I couldn't replicate it, I did notice that the web service calls being made resulted in a spike of read locks on the database. I figured a viable option would be to have that service set a transaction scope with an isolation level of Read Uncommitted. It was a quick and dirty way to get it to read data without locking in a condition where, for whatever reason, it seemed that read locks were colliding. (Doesn't make a lot of sense to me, as nothing was writing to the database at the time, but it's all I had to go on.)

After trying and failing to use the Enterprise Library to create a transaction (it kept insisting the transaction and the command objects belonged to different connections, even when I created them equal), I decided to go with the System.Transactions namespace to manage it. From a code perspective, it would be much, much cleaner anyway.

It did perform much faster, without the spike in database locks, but it revealed another problem. In trying to solve the problem himself, QA guy thought he should try splitting the application up instead of running everything on one machine, so he put the database in a virtual PC. When he got the new web service code, it threw an error about being unable to connect to the DTC service on the database server.

This was a fortunate discovery, as it would've been a problem if we got to a client's environment and found this issue.

I created three VPCs of my own and put the three pieces each on its own VPC. The rest of the next two days, I spent trying to get DTC to work between the web service and the database server.

Everything ran fine when the Windows Firewall was disabled on all machines. First, DTC had to be configured on both the web service server and the database machines by enabling "Network DTC Access" and inbound and outbound "Transaction Manager Communication". Also, the DTC service on the SQL Server had to be started and set to Automatic start. (The web service server would start its own as needed.) Also, since my VPCs were in a workgroup and not a domain, I had to set DTC to use "No Authentication" rather than "Mutual". Quite a bit of extra work, but so far, not completely outside the realm of what we might possibly have to ask a client to do to their own servers.

Turning on the firewall on the client wasn't an issue. Turning on the firewall on the web service server caused an issue with both the servicing of web service requests and database access. The former was relieved by allowing port 80 through, naturally. The latter was relieved by creating an exception for the process C:\Windows\System32\MSDTC.exe, which was recommended by articles I found describing DTC and Windows Firewall (namely, that all machines participating in distributed transactions should have this exception).

Then there was the firewall on the database server. I had to allow port 1433 for SQL Server access. No problem. Doing that meant non-transactional methods worked without a hitch. But from there, for the life of me, I couldn't get DTC to go through. I tried allowing port 135. I tried adding MSDTC.exe as an exception. Nothing. It just wouldn't work.

One or two sites suggested opening up a range of ports that DCOM uses. However, since port ranges are not a valid exception for Win32's firewall, I did not feel adding a series of exceptions for each individual port from 5000 to 5020 was a viable option — not for me, and certainly not for our clients. Not all articles indicated this was necessary anyway.

It just. Wouldn't. Work.

Incidentally, the utility DTCPing apparently works fine (once you enable RPC on both machines through the Group Policy Editor, which I had to do since my VPCs are running XP Pro). This would seem to indicate that it's not a networking issue or even a firewall issue, just a DTC-refusing-to-work issue.

A lot of things bug me about this. For one, setting up DTC requires a lot of extra steps (turn on network access, mess with authentication, start service and set startup option on database server, create firewall exceptions) that can't (easily) be done in an install routine. Two, the fact that DTC was even used at all — the code in question created a TransactionScope object, created a DbCommand, and called LoadDataSet on a Database, before disposing of everything (except the DataSet). This, to me, should not be taking more than one connection to the same database, and therefore it should not require a distributed transaction coordinator at all. And of course the typical "this (apparently) fundamental piece of Windows systems is broken thanks to a new 'security' feature" problem.

Since the only solution was to disable the firewall completely on the database server, and since this is not something we are going to ask our clients to do, I rolled back the change that added System.Transactions to the project. Right now, we're going with the assumption that the timeout errors were a problem with QA guy's machine, as it only happens when everything is running all in the process space of his primary machine. If he moves anything to a VPC (even just breaking it in two pieces, whether the web service ends up with the client or the database), it runs fine; and installing everything on the demo machine (which is actually older, less-performing hardware) also doesn't have the issue.

There go my plans for cleaning up the code, too.

2008-12-28

Focus on the Prejudice

Recently, the evangelical group Focus on the Family was promoting a certain book, The Christmas Sweater, written by Glenn Beck. In a nutshell, at least from what I can gather from the Amazon summary and other news reports, it's a book about Christmas, God, family values, and redemption. One that seems to be quite popular, and one that seems to be in line with what Focus on the Family might promote.

Unfortunately, it was "outed" that the author, Glenn Beck, was in fact Mormon (gasp). From Beck's web site here, which ultimately leads to the story at Mormon Times, an anti-Mormon group posted a release to Christian News Wire calling Mormonism a cult, saying they were not Christian, and condemning Focus on the Family for not calling attention to the "differences" between Mormonism and Christianity, and therefore implying that Beck is a Christian and promoting the "false religion".

Focus is headquartered not far from here, and I have heard of Mormons who have been denied working there because of their insistence on their employees being Christian and their rejection of the Church of Jesus Christ of Latter-day Saints as a Christian church. (Might as well "out" myself here as well; I've heard these reports first-hand from members of my own congregation, being a Latter-day Saint myself.) So I suppose this can only be seen as "corrective" action on their part. It's still fairly disappointing, for apparently it reveals them as being more focused on their prejudice against a religion they don't agree with than the message being promoted.

I think the news wire release contains a couple of particularly damning points of these anti-Mormons that I found particularly interesting, in the one paragraph in which they actually reference Mr. Beck.

While Glenn's social views are compatible with many Christian views, his beliefs in Mormonism are not. Clearly, Mormonism is a cult. The CitizenLink story does not mention Beck's Mormon faith, however, the story makes it look as if Beck is a Christian who believes in the essential doctrines of the faith.

I underlined the things that stood out to me. Why do I find these parts so interesting? Well, first off, they fail to take into account that these social views are influenced by the very religion they're attempting to discredit. Likewise, if the story accurately reported on Beck's views (at least as presented in the particular book), and the results of the story are a set of views that "look like the essential doctrines of the faith", well, then, it stands to reason that Beck's beliefs are comparable to "the essential doctrines of the faith".

Are Mormons Christian? We steadfastly believe so. The name of the church — The Church of Jesus Christ of Latter-day Saints — directly names Jesus Christ, and we study the Old and New Testaments as sacred books of scripture. The subtitle of the "controversial" book of scripture, the Book of Mormon, is "Another Testament of Jesus Christ". Our weekly sacrament service, as the name implies, centers around the partaking of the sacrament, in memory of the Savior and his sacrifice for us in body and blood. We pray in the name of Jesus Christ. "And we talk of Christ, we rejoice in Christ, we preach of Christ, we prophesy of Christ, and we write according to our prophecies, that our children may know to what source they may look for a remission of their sins." So from a very simple definition of Christian — a disciple of Jesus Christ — we certainly seem to pass. But for a more scholarly discussion and research, there exists The Foundation for Apologetic Information and Research, which has collected several articles, talks, and responses to the "you're not Christian" accusation.

In the meantime, I'll continue to follow Christ according to the dictates of my own conscious, love my neighbor, be honest and true to my fellow men, and do my best to be a good husband and a father. If someone thinks that makes me or the church that teaches these principles un-Christian, despite evidences to the contrary, I suppose that's the price of discipleship, but in the end, I'll let God be my judge.

I do have to wonder how Focus on the Family managed to promote this book in the first place. From what I can tell, it didn't seem like Glenn Beck had been hiding his religious affiliation before now, so a very simple bit of fact-checking by Focus's PR department would've revealed this "inconvenient truth" well in advance. Perhaps it was a moment of weakness where they were focused more on the message than the specific religion of the author.

2008-12-19

Don't miss it 'til it's gone

When I was growing up, "humidity" was one of those things that was considered an undesirable thing. It made heat hotter and cold colder. It turned days that were just "warm" into miserable, muggy, don't-want-to-move days.

When I first moved to Denver, one of the things I enjoyed was the lack of humidity in this essentially desert climate. Hot summer days were bearable with just a fan. Opening a window was a viable option. Clothes could actually drip-dry. Even my naturally oily and acne-ridden skin started to clear up for the first time in my life.

When my dad got us a deal on a new furnace for our home (he was working in the industry at the time, so it was a good time to buy), I was somewhat bemused as to the existance of the option of a "whole-house humidifier". Why on earth would you want to add humidity to your house? My wife, on the other hand, a Utah native (where they also have a fairly dry climate) and owner of naturally dry skin, was very excited by this attachment, though.

After a couple seasons, I've gotten to understand this concept. The winter can get very dry, especially with the heater running as much as it does to keep the interior of the house above freezing. The extremely dry air ends up being very uncomfortable — it feels like you're living in a desert. Plus, there's an awful lot of static electricity that builds up in everything. The humidifier helps to make it more comfortable. It also makes it feel a little warmer, and it has the nice side effect of lowering static potential.

This winter has been especially bad. The power outlet attached to the furnace is dead. This outlet is powered by the furnace, so that it's on when the fan is on and off when it's off. So the humidifier hasn't had any power. I hadn't made getting that repaired a priority.

Then I noticed the problems. First, my shoulders would itch terribly. Yes, I, the one with the oily skin, had to start putting greasy gel on my shoulders to moisturize them after my shower in the morning. Then, my throat felt sore, the dry, parched sore of eating sand for two weeks. No matter how much water I drank, it always felt dry, and I would wake up in the morning feeling like it was on fire.

Then my oldest son started having the same throat issues. And my youngest was having trouble breathing at night. My wife broke out the portable cool mist humidifier, and that helped the toddler immediately.

That pretty much decided my course of action. Last night, when I got home from work, I ran an extension cord from a working power outlet to the humidifier. Since we run the fan full-time, it doesn't need to switch on and off, so that wasn't a concern. (That's a trick my dad taught me — if you set the "Fan" switch on your thermostat from "Auto" to "On", it runs the fan continuously instead of just when the heater or A/C is running. This keeps the air in the house circulating and at an even temperature, so you don't have the upstairs at 75° and the main floor at 65° and the furnace still burning fuel because the thermostat set at 70° is on the main floor. You do have to clean the air filter more often, but ours are the metal kind you vacuum out and reuse instead of disposable.)

I then had to run to Home Depot to get a new pad for the humidifier, since the old one from last year was scaly and wouldn't hold water (they're only $12 and typically last a winter season). Switched it on and set the humidity level to 20% (the markings have a recommended level based on outside temperature, but I've found that a constant 20% works ok, even if it means the windows occasionally show a layer of condensation on the really really cold days), checked for leaks, and closed it up.

Already, I can tell a difference. I woke up this morning and my throat didn't feel like it was full of sand.

Still, if you had told me a decade ago, before I had moved to Denver, that I would be voluntarily adding humidity to my own home, I would've laughed in your face.

Interesting side note: before we got air conditioning, we would cool our home with evaporative cooling fans. They actually work on the same general principle as the humidifier — a pump pumps water into a pad, and a fan blows across it. The cooling comes from the water evaporating. They actually work quite well in this climate, where water actually evaporates. I hadn't ever seen them before, which isn't surprising, since I had lived in places where it was more common to see water spontaneously condense out of the oversaturated air than evaporate into it.

2008-12-17

I CAN HAS LOLCODE?

One of the guys in my office showed me a list of "If Programming Languages were Religions". I'm sure I had seen it before, years ago, but it had been updated to include some more recent languages. It was pretty good (I was even able to chuckle at the inclusion of my own religion in there, whose reference was surprisingly tasteful).

One that took us both by surprise was "LOLCODE". I forget to what religion it was compared, but we had to look it up, to see if it was as bad as it sounded.

It is.

Observe the following code samples, starting with, of course, the ubiquitous "Hello World":

HAI
CAN HAS STDIO?
VISIBLE "HAI WORLD!"
KTHXBYE
HAI
CAN HAS STDIO?
PLZ OPEN FILE "LOLCATS.TXT"?
   AWSUM THX
      VISIBLE FILE
   O NOES
      INVISIBLE "ERROR!"
KTHXBYE
HAI
CAN HAS STDIO?
I HAS A VAR
GIMMEH VAR
IZ VAR BIGGER THAN 10?
   YARLY
      BTW this is true
      VISIBLE "BIG NUMBER!"
   NOWAI
      BTW this is false
      VISIBLE "LITTLE NUMBER!"
   KTHX
KTHXBYE

You can read more about it at LOLCODE.COM. Or don't. ;)

School Zones are for Losers

I drive the speed limit. When I see a speed limit sign, I moderate my speed to that number, and I set my cruise control. It's not out of any sense of moral superiority (although I will admit such thoughts do cross my mind when someone starts riding my bumper in an effort to push me above the legal limit); it's simply because I've received two speeding tickets in my lifetime, and I've decided that is plenty. Even if the chances of being pulled over for going a mile or two or five over the posted limit are remote, I've just decided it's not worth any added stress.

Does that mean I sometimes get to my destination later than someone else who might push the pedal down a little further? Sure. I've seen plenty of people speed by me and get rewarded for their transgression by getting through a street light that turns red after they pass but before I do. I've also seen plenty of people speed by me and get caught by street lights or traffic and end up no further ahead for their efforts.

Some people seem to take offense at being forced to follow the speed limit, though. Aside from the aforementioned tailgater who will follow dangerously close when I'm traveling the speed limit (usually when the limit drops or, for some reason, is posted slower than what one would think is necessary for a particular road), is this situation that I encounter each morning:

Traveling left to right (in this picture), I enter a school zone, which at the time of day is almost always active (lights flashing). I approach this intersection after making a left turn on a light from another main street, and it seems the lights are timed such that, after making that left turn and traveling to this point, I nearly always am stopped at this red light (often behind a long line of cars — there are probably about 10 car lengths between the start of the school zone and the light). Shortly after the intersection (just a few yards) is a rather large "Speed Limit 40" sign — however, this is not the end of the school zone, as evidenced by the (much smaller) "End School Zone" several yards beyond it (and the corresponding "Begin School Zone" for the traffic in the other direction at the same point). I have to wonder if the large "Speed Limit 40" sign was placed there with the intent to confuse people and entice them to accelerate to 40mph early — but that's the conspiracy theorist in me thinking.

As I approach the 25mph blinking school zone sign, slowing down is not usually a problem, as, as I've noted, there is usually a long line of stopped cars waiting for the light. Even if there are no cars or the light is green, I can typically slow to 25 without incident, although people in the left lane rarely slow completely to that speed. (I'm always in the right lane, as at the next intersection beyond this, I need to make a right, usually as well as a long line of people that would make trying to push in from the left lane difficult [but not beyond what some people will do to try and save a few seconds].)

What is more common is, after being stopped by the red light, when the light turns green, people will "forget" that they're in a school zone and begin accelerating. I'll get up to 25 and set my cruise control, as people in front pull ahead and people on my left pass me by.

What happens here more often than not is the person behind me will ride my bumper for a while, usually about halfway between the "Speed Limit 40" sign and the "End School Zone" sign. They will then lose patience and speed around me. If they've waited too long (i.e. I've reached the "End School Zone" and started accelerating to 40 myself), they will then slam on the gas to get around me.

And what do they get for their efforts? Well, I've yet to see a cop there in this, my third year of driving this route in the morning, so not even the chance of a ticket. But it does put them in front of me (although pulling away isn't possible — remember the line of people turning right at the next intersection ahead that I mentioned earlier?), and I guess that's all that matters. *sigh*

2008-12-06

Bandwidth for November

Another month, another bandwidth analysis.

The total bandwidth for November was 23,648MB down, 3,843MB up, 27,492MB total. The total bandwidth consumed for November was actually less than that for October by nearly 11GB.

This actually surprised me quite a bit. With the extremely graphic-heavy redesign of the Xbox dashboard, and with what I thought was a lot of videos and demos downloaded over the month, I would have expected a lot more usage. I even watched a couple episodes of South Park streamed from their web site. Sure, I haven't started downloading motion pictures yet, but I haven't exactly been conservative with my internet usage, either.

2008-12-05

PropertyInfo.PropertyType - is it Nullable?

Here's what I learned in school today.

I extended an object in our product with some nullable data types (something that, maddeningly, the previous programmers seemed to have an aversion to using, preferring instead to passing around "magic numbers" to represent null values — nice work, guys). Unfortunately, it bombed in one screen that used reflection to take objects and make datasets out of them.

The offending section of code looked like this:

PropertyInfo[] pInfo = myType.GetProperties();
for (int i = 0; i < pInfo.Length; i++) {
    DataColumn dCol = new DataColumn();
    dCol.ColumnName = pInfo[i].Name;
    dCol.DataType = pInfo[i].PropertyType;
    resultTable.Columns.Add(dCol);
}

The error thrown was that datasets don't support the "System.Nullable" type. Well, technically, they do, in that everything is nullable in a dataset, but that's beside the point. The solution is, I need, when building this dataset, to see if the type is Nullable, and if so, use the underlying type instead. No problem, right?

Not if you happen upon this post by the user "OregonGhost" on StackOverflow.com. He may not have invented the solution, I don't know; I just know that after searching for a bit, his post was the first answer I actually found to my question.

My code now looks like this:

PropertyInfo[] pInfo = myType.GetProperties();
for (int i = 0; i < pInfo.Length; i++) {
    DataColumn dCol = new DataColumn();
    dCol.ColumnName = pInfo[i].Name;
    Type dataType = pInfo[i].PropertyType;
    if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == typeof(System.Nullable<>)) {
        dataType = System.Nullable.GetUnderlyingType(dataType);
    }
    dCol.DataType = dataType;
    resultTable.Columns.Add(dCol);
}

And it works.

2008-12-02

Try...Catch in WinForms Main() method not Catching

Had a really bizarre and annoying error. I had a .Net WinForms app that started with a code block like this:

[STAThread]
static void Main() {
   try {
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);
      Application.Run(new MDIFormMain());
   } catch (Exception ex) {
      using (FormShowException showException = new FormShowException()) {
         showException.Display(ex);
      }
      Application.Restart();
   }
}

The only problem was, after one exception caused a restart (which had a side-effect of detaching the debugger), every other exception would throw a standard .Net "unhandled exception" box. Huh?

The right combination of Google search terms finally brought me to this page. Yes, apparently the above construct is fine running in a debugger, but not so much in stand-alone.

The solution, as described on the referenced page, is instead of using try...catch, bind to the Application.ThreadException event (which works both with and without a debugger attached), like so:

[STAThread]
static void Main() {
   Application.EnableVisualStyles();
   Application.SetCompatibleTextRenderingDefault(false);
   Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
   Application.Run(new MDIFormMain());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) {
   using (FormShowException showException = new FormShowException()) {
      showException.Display(e.Exception);
   }
   Application.Restart();
}

Very simple fix for a very aggravating little problem. Thank you, Craig Andera.