2009-06-26

The importance of keeping good records

I'm a bit of a pack rat. Ok, I'm very much a pack rat. I don't like to throw anything away on the off chance that someday, I might have a need for it. It's especially bad when it comes to financial information. I have receipts dating back to the 1900s — which used to sound much more pathetic than it is, but considering they were 9½ years ago, I think we can safely upgrade that statement from "sounding pathetic" to "actually pathetic" now.

Regardless, I finally am able to reap the rewards of not throwing papers relating to money away. I got a letter from the IRS a couple weeks ago that I had been selected for an audit (What, I didn't mention that in my "pity party" post? Hmm, probably should've; it definitely qualifies) and that I needed to gather information about my charitable donations for 2007 (what fellow Geezer Gamer "SlapShotSal", who does taxes for a living, tells me is a "substantiation audit").

I knew the bulk of my donations for the year would be to my Church, so I got the statement I received from the Church for 2007, which had a list of all donation dates and amounts for the year. Then I pulled a report in Quicken for that year and found the check numbers that corresponded to those dates and amounts. With that list, I went to all my bank statements for the year and found the statements they appeared on and the dates they cleared. I figured these dates would be important to get the images of the canceled checks from my bank, since to see old checks, I usually have to select the statement they were on. This could've been a tedious process of having to download each statement from my bank, but I keep copies of my statements on my home network for easy reference. (It worked, too; it was very easy to reference all those old statements.) Yes, the pack rat trait applies to digital files as well — probably even more so.

Now that I had a list of check numbers and dates, I logged on to my bank for what I dreaded would be the most tedious part of this whole process — having to find each check on the old statements and get the images, one by one. Maybe I would take them into Paint.Net (my favorite free image editing program du jour) and stack three or four of them on a page to save paper.

I found the link to prior statements, but much to my disappointment, they only went back 18 months, the earliest one available being January 2008. So that wouldn't work. But there was another link for searching for transactions that indicated check images were available as far back as 2005. (Glad I didn't get audited for any years prior.) I entered a date range of the whole year, a check number range from the lowest to highest number I had, and selected "Check" for transaction type.

I couldn't believe what I saw. There was a list of all the checks, with a checkbox by each one. At the bottom of the list were two options, one to select Large or Small images, and one to select Front only or Front and Back, and a button marked View Images.

Actually, the search results were limited to 100, so I had to do the first half of the year and then the second half, but big whoop. There it was, exactly what I needed. Select the checks I needed to see, and hit View Images to see just those checks.

When I viewed the images, it showed me two checks at a time, with front and back images — so four images total — with some simple navigation at the bottom to move to the next pair of checks. Since the site's not in a frameset, I couldn't tell my browser to just print a single frame (i.e. the one with the images), and I didn't want to print the navigation links (or the rest of the webpage for that matter), so I figured I'd still be copying images from the screen. Just for kicks, though, I called up the Print Preview to see what would happen if I tried to print.

They thought of that, too. Apparently there's a printing stylesheet in place that turns off everything but the content, because in the Print Preview, the only thing visible were the check images. No navigation, no links, no tabs or corporate logos or anything extra.

Here I thought I'd be at this for days, or at least hours, gathering images and printing them out one by one, and all I had to do was click "Next, Print, Next, Print, Next…"

I'd love to publicly praise this bank for their extremely useful website, but at the same time I don't necessarily want to advertise to the rest of the internet where I keep my money. I did make a point of sending a message of thanks to their customer service inbox, though.

So, with that out of the way, now I can go back to playing my Xbox. Except that is currently on its way to a repair center in Texas and probably won't be back for a couple weeks.

Yeah, I guess I forgot to mention that, too.

2009-06-18

The hits just keep on coming

It's a pity party, and you're all invited.

When I picked up my son's medication as we got him out of the hospital, the total bill was close to $500 for a month's worth. I figured they were just having issues with insurance and I'd just need to resubmit the claim later. In any case, it wasn't something I could worry about or negotiate at that time — the treatment required keeping the level of medication in his blood stable, and we needed the pills then. Well, I finally got around to calling my insurance carrier to see what was up.

Here's what's up: that medication isn't covered. The price, unfortunately, is what it is.

D'oh.

A couple weeks ago, a tornado passed really close to our house. We didn't have any damage from the twister, thankfully (in fact, it did surprisingly little damage for touching down in the middle of a shopping mall, causing no injuries). However, there was golfball-sized hail. We have an insurance adjuster coming to look at our roof to inspect for hail damage on Monday. If repair work needs to be done, it's covered, just with a $1000 deductible. Which could be a lot worse, but it's an expense when I don't need any more expenses.

And, my glasses broke this morning. I got these frames that were supposed to be made of this indestructible flexible alloy, and the frames have in fact held up well. The problem is, the screw on the hinge is held in place by this flimsy piece of wire that's barely soldered on to the indestructible frame. This same hinge actually broke twice on me. The first time, it happened so quickly as to still be under warranty that I could have the frames replaced. Not so, this time.

Fortunately, my older pair is still in great shape, and my previous prescription isn't that much different, so getting a new pair is something that doesn't need to happen immediately.

And, I just got a call from my wife, who is right now taking my son (the one with the $500/month medication) to the doctor's office with sharp, stabbing pains in his stomach.

2009-06-15

Wait, what about The Social?

A year and a half ago, I looked at this "Zune Social" thing, and I wondered if it would be possible to "jump in" with just my desktop PC. Having a Zune Card that was just like my Xbox Live gamercard, with a running history of the music I listened to, sounded kind of cool. Gimmicky, sure, but cool. And the fact that I already had a Zune Card simply by virtue of having a gamercard meant the cost of entry was eliminated. (I suppose this is also related to me being a sucker for features, as I had access to this feature that I wasn't using.) But in order to use it, you had to use the Zune Media Player, which, compared to Windows Media Player, was pretty lacking.

I posted a comment in the Zune forums, suggesting it might be nice just to have a WMP plug-in that updated my Zune Card with my stats from WMP. The responses I got back were rather disparaging, saying they couldn't do everything the Zune Media Player did in a mere plug-in. It was also the prevailing opinion that the Zune Social was for Zunes, and it didn't really matter what I played on my PC. (Ok, never mind the fact that I could play things in the ZMP and have it update my Zune Card.)

Back in September, they released a software update, and I decided to give it another look. In short, nothing had changed. I came to the conclusion that the Zune Social was a Zune-only club, and I would just be anti-social until I somehow acquired a Zune of my own.

Two weeks ago was E3, and Microsoft announced that Last.fm would be coming to the Xbox 360. I hadn't really looked at Last.fm before, so I signed up. Not only does it offer streaming music, but it (to quote its home page) "recommends music, videos and concerts based on what you listen to." And how does it know what you listen to? Well, obviously it can track the songs it streams to you and the ones you flag as tracks "loved" or "blocked". But it can also track songs played in Windows Media Player using a plug-in.

So here you have this third-party service that is doing exactly what I was asking for from the Zune Card. And Microsoft is integrating that service into the Xbox 360.

Oh yeah, they did also say that the Video Marketplace on the Xbox 360 would become the Zune Marketplace. But so far, they've only announced that for videos. Not music.

I don't get it.

2009-06-10

I'll handle any key you want... except that one

Here's one of those that makes a little more sense when you think about it, but it still leaves you scratching your head until you figure out what's going on. And then you think about it some more and realize, no, it doesn't make sense at all.

When you want to capture keypresses in a control on a Windows form, the "best" place to do that is the KeyDown event. It gives you the ability to capture keys, the state of the modifier keys (Control, Alt, Shift), and to mark that keypress as being "handled" so the key does not continue on as actually being typed. It also provides access to capturing unprintable keys (like Escape or Insert).

However, one thing it does not do is let you capture the Tab key. This is because the control doesn't even get a KeyDown event when the Tab key is pressed. (Indeed, Microsoft considers it a bug when it does trigger a KeyDown.)

You can sort of rationalize this behavior when you realize that the Tab key is "special". The form uses that key to determine when to move from one control to the next. So, in that way, it would make sense for the Tab key to not even get to the control. However, you can easily debunk that rationalization with two controls: a DataGridView and a TextBox. A DataGridView, with its StandardTab property set to the default of False, will, when a Tab key is pressed, take it upon itself first to move the active cell through the grid, and only when the last cell is reached then let the form move focus to the next control. Likewise, a TextBox that has both Multiline and AcceptsTab properties set to True will take any Tab keypresses and add a tab character to the input, never passing that keypress to the form.

In any case, it seems that, for whatever reason, the Tab key is handled by the form sometime after these possible control overrides, but before the KeyDown event could get fired.

Solution? Well, it turns out, there are two.

The first one I found is to override the form's ProcessCmdKey method. Start by calling the base ProcessCmdKey method, which returns a boolean that indicates whether the key was handled. Then, check to see if this.ActiveControl is the control for which you want to trap the Tab key, and if the keyData parameter passed in to ProcessCmdKey contains the Tab key ((keyData & Keys.Tab) == Keys.Tab). If so, do whatever it is you wanted to do, and set the boolean return value to true, indicating you've processed the key yourself. At the end of the method, return the boolean. (I found a simple example here.)

The annoying part is, if you were trapping for more than just the Tab key in the control's KeyDown event, you now have your logic split in two different methods (control_KeyDown and form override ProcessCmdKey). Also, if you are doing this for multiple controls (as I was for, coincidentally, a DataGridView and a [single-line] TextBox), you have to copy and combine the logic from the other controls' separate KeyDown events into the ProcessCmdKey method, testing the ActiveControl to make sure you know which control you're in.

The advantage, however, is that you only have to test the cases you're interested in. If, for instance, you want to catch a Tab, but still allow a Shift+Tab to default to the standard form's handling, you just test for an un-shifted Tab and do your work, and let the Shift+Tab condition "fall through".

The second solution is to bind to the controls' PreviewKeyDown event. This one fires in that sweet spot before the form claims it as a "command key". The event gets the parameter PreviewKeyDownEventArgs e. If you want to handle the Tab key in the KeyDown event, just check to see if e.KeyCode == Keys.Tab, and if so, set e.IsInputKey = true.

The disadvantage to this method, however, is that now you are responsible for moving the focus as appropriate — you can't just let the handling "fall through" to the form, because it won't handle it anymore. Depending on how confident you are on the structure of your form, you can either call another control's Focus method or the form's SelectNextControl method (and don't forget to set the Handled property in KeyDown, otherwise the new control might receive the same Tab keypress as well, or it might try to type the Tab as input into the old control — either way, the results might not be pleasant).

Personally, I like the second solution better. Although there is more logic required to do what should be standard Tab handling, it means the logic for my non-standard Tab handling is in one place per control, not split across two different events.

2009-06-05

Bandwidth for May

Whoops, forgot to grab the data for the beginning of May. Daily numbers are missing, but the monthly totals are accurate.

Total for May: 19.98GB down, 4.54GB up, 24.52GB total. Not quite a tenth of the cap. This month has the second lowest total since the cap, coming in just ahead of March.

If it weren't for the impending medical bills, I'd sign up for Netflix, if only to see what it would do.

2009-06-04

A sucker for features

Yeah, so a few people have noticed that, despite my general disdain for "social networking" services as a whole, I finally got suckered in and signed up for both Twitter and Facebook.

I was a long-time user of Microsoft's MSN Messenger service. (I even had a "charter membership" to the Microsoft Network, for whatever that's worth. Remember when we didn't have "internet service providers", but signed on explicitly to companies' dial-up networks?) Anyway, eventually I got a job where their "standard" messenger client was AIM. I didn't want to have to run two distinct messenger clients because of the combined resource usage, so I looked for a client that would connect to both services in a single client. The one I selected was Trillian, which I installed and started to use.

When I got it up and running, I noticed there were little icons that lit up with each service to which it connected, and only two of its four lights were lit. I felt like I was missing something, because I was using a program but not all of its features. So I entered my credentials for my almost-forgotten ICQ account, and on came another light. What was the fourth one? Yahoo Messenger? I didn't know they had a client, and I certainly didn't know anyone on it. But I wanted that last light to light up. So I signed up for a Yahoo account, and finally my program was complete.

Now you might understand a bit what feelings went through my head when I heard about Microsoft's E3 press conference this week. Felicia Day (who has a very cute face, but dang that girl needs to eat before she blows away) announced that the Xbox 360 would be integrating with Facebook, Twitter, and Last.fm this year.

New features? On my 360? And I don't have access to use them? Well, I'd better sign up, then!

Of course, I had to be a touch creative with my account names since I waited so long, but fortunately I was able to get away with just adding a "1" to my alias and calling it good. (Except for Facebook, which demands a real name. What do you mean, "Yakko" isn't a valid first name?)

I don't know if my Facebook page will see much action (we all know how infrequently I update my own blog as it is), but I've already found that Twitter is fairly useful for those really quick thoughts I think might be nice to jot down but don't think are worth a whole blog post. (So far, I've resisted the temptation to reply to the tweets of celebrities who will never know I exist, but we'll see if I can maintain that resolve.)

And after listening to the '80s Tag station on Last.fm most of the day yesterday, I already can't wait for this to be turned on in the 360.

They hyped up Netflix again, and I started to feel tempted again. That one, though, costs money, and signing up for another entertainment service right before medical bills start rolling in sounds like a really bad plan.…

2009-05-27

The fundamental interconnectedness of all things

It seems when my son is admitted to the hospital, my laptop reveals a new problem.

Now, my HP Pavilion tx1420us is failing to power on after any kind of software shutdown state. This includes: failing to resume from sleep, failing to power on after hibernate, and failing to power on after shutting down from the menu.

Fortunately, I'm able to get around this by shutting it down with the hardware switch. When I power up the computer and notice it's not starting (the audio and wireless lights both remain orange instead of turning blue, there is no disk activity, and the screen remains dark), I can press and hold the power switch in the "off" position for a few seconds until the system shuts off, and then power it back on. Sometimes, though, I have to do this twice.

Also fortunately, I'm using the Windows 7 RC, and Windows 7 includes a feature called "hybrid sleep". The short of this is, when the system goes to sleep, it also writes the hibernation file; so even though I can't wake it up and have to force the power off and wipe out the sleep state in memory, when I power it up it is able to resume from hibernation.

This could indicate that the wireless failure was not directly a fault between the system and the Wi-Fi card, but just a symptom of a general failure.

More so, though, I see this as a failure on my part for trusting HP to produce a laptop that would last beyond its warranty period.

2009-05-26

Haven't we been here before?

I got a call while I was in a meeting today, from my wife. She's the only person I'll accept calls from when I'm in that situation, and I answer the phone in the same way, with a whispered, "Hi, I'm in a meeting, is everything ok?" Almost always, she'll say everything's fine, and just call her back when I get out.

Not today.

My son was having a really bad day today, having emotional outbursts and not fully processing what was going on or where he was. Since he's on a high-dose steroid, he's been fairly moody and irritable lately, but never to this extreme. Still, it didn't seem like anything more than just a really bad case of frustration and mood swings. My wife finally got him calmed down enough to take a nap, figuring that would do him some good (he has typically been taking a long nap in the afternoon anyway), but after maybe a half hour or so, she happened to look over at him and notice that he wasn't exactly napping — his eyes were open and twitching. She called the doctor, who then advised her to call 911. When he was on the ambulance en route to the local hospital's ER, she called me.

I excused myself from the meeting, grabbed my coat and backpack, and met her there. He was having a mild seizure. They gave him some medication to stop the seizure, and then they did a CAT scan to rule out the possibility of a stroke. The scan came up normal. Of course, I predicted as much — the entire 5-week stay in the hospital, every lab test they could think of came up negative; he just wasn't well, had ferritin levels higher than they'd ever seen, daily fevers over 104°F…

Anyway, with the seizure under control, they transferred him back up to Children's Hospital. I parked in the same parking lot and went to the front desk. I couldn't just flash my wristband and walk in this time, though; I actually had to stop and find where they brought him in. The desk clerk found that he was brought to the ER and offered to walk me there. I was about to object, since I knew the way there, but then I remembered that there is a card-access lock door from the main hospital leading to the ER, and I'd need someone to let me in anyway.

It's sad that I know this.

The primary doctor here in charge of his case was aware of this possibility. The medications he's on, the cyclosporine in combination with the steroid, can raise blood pressure, and the increase in blood pressure can trigger a seizure like this. In fact, he noted this at my son's visit last week. The day after he saw my son, my son had an appointment with the cardiologist, and the doctor said he saw today the blood pressure taken at that appointment and was very disappointed that the cardiologist didn't call him. Although the blood pressure taken wasn't extremely high, it was high enough that he could have prescribed some blood pressure medication to keep it down and prevent this seizure from being a possibility.

It's the doctor's initial opinion that, once we get his blood pressure back to normal and he recovers from the seizure, that he'll be good to go home again, just with some blood pressure meds as well this time. Unfortunately, he's also running a fever now (his first in over two weeks), so they're checking for infection (dollars to donuts they don't find one, again), and hopefully this fever is just a temporary thing that doesn't keep us from going back home tomorrow.

It's really depressing to be back here. On Sunday, we actually started to get close to normal. The whole family was finally able to attend church together. He slept through our sacrament meeting, but he attended his Sunday School classes and was smiling and laughing with his friends. He's even started to get himself up and down the stairs at home. And now… here we are again.

2009-05-24

Why didn't you do what we wouldn't let you?

So while I was in the hospital watching over my son, I signed on to CitiCards.com to pay my Master Card bill. Imagine my surprise when I see a message, saying my account information has been compromised, and for my security web access to my account has been disabled, and a new card is being sent to me.

In the meantime, fortunately, my card still worked for purchases (even online), so I wasn't completely without access to my credit. I just couldn't sign on to my account online.

Now, this did concern me a bit. After all, the reason I was signing on was because I needed to pay my bill. And this was how I paid my bill. Since I signed up for "paperless billing" — a service they provide and encourage — it was also the only way I had to pay my bill. And here they were, disabling access to my account and the means for paying my bill. But surely they wouldn't hold me responsible for not being able to do something they were keeping me from doing, right?

I finally got my replacement card. I lost count, but it was a few weeks later. So I was finally able to register my new card for online access, check my account… and see that finance charges and a late fee had already been assessed to it.

I guess CitiBank got tired of waiting for their bailout and decided to take it out on their customers.

2009-05-14

It's good to be home

After five weeks and a day, we finally took my son home from the hospital yesterday. The doctors with all their tests were able to rule out enough of the major diseases to decide it was safe for him to be at home, and all the medications and treatment he was on could be safely given at home.

Now, granted, he's still not 100% well. He's on a few different medications, and his immune system is still recovering from being sick (and some of the treatments he was on). And he still has a PICC line in his arm, since we'll be making repeated trips back to the hospital for blood tests and checkups. But just the fact that we're all home is a huge relief to all of us.

He is definitely getting better, though. As it so happens, for about the last week, he was no longer getting his daily fever spikes, and without the fevers to drag him down, his appetite and strength has been coming back. If I had to make a guess, I'd say there was an infection (secondary to the Kawasaki disease they did manage to diagnose) they couldn't find, but when they happened to give him a final dose of antibiotics as a precautionary measure while they switched medications that affected his immune system, it probably finally wiped it out and let everything else fall into place.

We did get our first taste of the medical bills, though, when we had to pick up the prescriptions. We're hoping that insurance just didn't get billed properly, but three prescriptions ended up costing us close to $500 (and we had to make a trip back to the pharmacy in the hospital, as the drugs aren't carried at any branch close to home). The cashier actually apologized as she rang it up.

One thing at a time, though. At least we're home, all under one roof, sleeping in our own beds.

2009-05-08

Name them one by one

So with all the crap hitting the fan over the past 4½ weeks, maybe it's time to stop and count my blessings.

  • My son is alive, and is getting his symptoms cared for (even if they can't cure the disease).
  • We live in the suburbs of the city that has one of the best children's hospitals available. (We've met people from as far away as Hawaii, who are staying in the Ronald McDonald house while their child gets treatment here. While we may not be spending much time at home, we can at least go home every day to get clothes, supplies, check on the pets, …)
  • I am employed full-time (not on hourly contract), at a small technology company that has been more than accommodating to my very unpredictable schedule, including my rather reduced hours (although I intend on working some this weekend to catch up on some work, they've accepted my 6- and 7-hour days without complaint). (I'm sure it helps that I'm still meeting deadlines and getting work done.)
  • My job is only a few blocks from where my kids go to school, and so it is very easy for me to pick my older son up and bring him here, where he can do his homework and play his Nintendo DSi until it's time to go. Additionally:
    • my workplace is ok with this arrangement
    • I have an office, so I have space for him to be in
  • My church has been there to provide meals for us, and to take our toddler off the hands of my wife for the day, so he's not confined to the hospital room every single day.
  • GeezerGamers.com — I've been a part of this community for a little over four years now, and the outpouring of support and prayers from these people have given me a huge morale boost I didn't realize I needed. And on top of that, they've also sent me and my son some Amazon gift cards and a care package that included a new Xbox memory card (to replace the one that "mysteriously" disappeared from the hospital room this past weekend). They've been an awesome group of friends, more than I ever expected or ever thought (or hoped, at least in this way) I'd need.

Hopefully the hospital stay is coming to an end. Although the doctors still haven't figured out The Problem for which they can prescribe The Cure, they have at least eliminated enough major issues that they're considering sending us home. He'll still be on medication (they've started switching his IV-based medicines to pill form), and as long as he shows he can eat and drink enough to sustain himself without IV supplements, if his white blood cell count recovers from one of the medicines he was on, and if nothing else major comes up, we may be taking him home next week (a "mere" 5 weeks after he was admitted).

Sure, we'd still need to bring him in for some tests rather regularly (and they may leave his PICC line in while he is coming back for tests), but even if we had to spend, say, 4 hours a day every day going back and forth to the hospital for tests, that's still 20 more hours a day he'd have at home than he has now. And that's another blessing worth counting.

2009-05-01

April in Review

April sucked.

  • Middle son ends up in the hospital for an extended stay. (Resolution: none yet, still there.)
  • Friend and client busted by SEC for running a Ponzi scheme. (Resolution: none. Have had little time to process this myself, let alone follow the case; see above.)
  • Youngest son splits head open at hospital. (Resolution: glued shut, healed fine.)
  • Snow storm kept us at home away from hospital. (Resolution: worked out; my mother had flown in for the weekend and was already there with my son.)
  • Master bathroom toilet seat split. (Resolution: none, haven't been home long enough to fix.)
  • My wife was rear-ended on the way to the hospital one morning. (Resolution: n/a, occurred at such a low speed the only "damage" done was dust in the shape of the offender's license plate that wiped away clean.)
  • My laptop's wireless card died, due to an extremely common problem with this model of HP laptop. HP wants $100 just to look at it before they'll decide what to charge me to fix it, even though they repaired the identical problem on the identical laptop (my wife's) a few months ago. (Resolution: bought a $30 USB Wi-Fi adapter.)

Yes, I know, everything worked out, and some of these are really minor things. It just seemed like everything came crashing down all at once, and especially when you're dealing with something major like having a kid in the hospital and are spending better than 12 hours a day there, it all seems like a lot.

Even when this is all over, it won't be; I have a feeling we'll be paying for this for months, if not years to come. My hospital stay for my appendix cost thousands, and that was only for a couple days.

But that's something to worry about later. Right now, the most important thing I want resolved on the list is still there. My son is still in the hospital, still not getting better to the point where he can come home. My wife and I have spent the night in the same bed precisely three nights in the past 24 (when my mother showed up for the one weekend and sent us home). And what sleep I do get during the week is definitely not quality, considering the inch and a half of foam on a sheet of flat plywood that qualifies as a fold-out bed here.

I know, things could be worse. I just want to know when they're going to get better.

Bandwidth for April

You can see the spike on the first weekend where, again, I watched the streaming video of my church's general conference broadcasts. There are two 2-hour sessions, with two hours between them, during which church news is broadcast. Although we didn't watch for six hours straight, I did let it keep streaming the video, partially because I didn't want to have to restart the stream (I put my laptop up on a high shelf when I connected it to the TV for output and didn't want to climb back up to get it), and partially to see what would happen to my bandwidth numbers. (Sunday, I actually did stop and restart the stream when I found my bluetooth mouse worked as a suitable remote control.)

Although I haven't been home to do a lot of Xbox gaming this month (spending most nights in the hospital with my son), I still use my home network connection quite a bit as my own personal proxy server. I've used this from work for over a year now, mainly to prevent any misunderstandings that might occur if I were to happen to hit the wrong website at the wrong time. I'm also using it from the hospital, since they have an unsecured wireless connection that is also a tad overzealous in filtering out websites that "might" be "unsafe".

Anyway, the total numbers: 27.06GB down, 5.32GB up, 32.38GB total. This month is the second highest, ranking behind the last general conference month (October).

2009-04-30

You uncultured flu bug!

Well, this is highly inconvenient.

I show up at the hospital with my oldest son, to trade places with my wife for the night. I go to enter the hospital, and a security guard stops me. "He can't go in," he says, indicating my son. "The hospital is on lockdown. Parents only, no siblings."

"When did this start?"

"About an hour ago."

Apparently, because of the swine flu, they are closing down access to the hospital to necessary personnel only, and that means only parents, no siblings or other visitors.

I call my wife, who is up there with my middle son (the patient) and our youngest son (the terror that flaps in the night). She hadn't heard about the lockdown yet. I told her she needs to meet us downstairs to do the swap.

As I'm waiting, I realize just how inconvenient this is going to be. When my wife comes to relieve me in the morning, she will be unable to bring the toddler with her. And because I have to work, that means he'll need somewhere to stay pretty much all day. So I talk to the security guard to ask about the nature of the lockdown and how long it'll last. The security guard, after assuring me that there is no instance of flu at this hospital, says they don't know how long. Could be a couple of days, could be a week, could be a month.

My wife calls me soon after. She of course had the same thought, and she was talking with the charge nurse to discuss our options. (The security guard also suggested I could try talking to the charge nurse for the same reason.) Apparently, in talking with the nurses inside the hospital, she learned there was a case of swine flu detected in the hospital. It wouldn't surprise me if the security guards at the entrance were told (or instructed to tell people) there wasn't, but it also wouldn't surprise me if the "fact" that there was wasn't just a rumor that was going around the nurses' stations.

My son (the patient) had just been coming down with a cough and congestion. Wouldn't it be just our luck if it was him who had come down with the swine flu, on top of whatever else had brought him there in the first place? My mother had, after all, just come back from a trip to Mexico before she came to spend a weekend in the hospital with my son.

2009-04-28

WordPad: "Picture" = "End of File"?

There's this annoying bug in WordPad in XP that I'm surprised I couldn't find very much about. But it's hit me on more than one machine (and I never seem to remember it until after it happens, of course).

Whenever I create a document and I paste a picture into it from the clipboard (usually copied out of Paint, as that's a convenient way for me to get an image on the clipboard in a hurry), the picture and any text after it is not saved with the document.

This time, naturally, it happened to be on my set of release notes for a product release, where I happened to add a picture to the beginning of the document. Entire document, gone.

It seems to be a function of WordPad itself adding the picture to the document. If I open a document that already has a picture (e.g. by creating a document with a picture in Word and saving it as RTF), I can do just about anything to the document, including cutting and pasting the picture to other locations. It's just the act of initially adding that picture to the document that makes WordPad stop processing.

Why use RTF at all? Well, RTF is a very convenient format for creating simple text files that have a little bit of formatting. They're also extremely portable — whereas Word documents (or documents saved in "Word-compatible" formats) can sometimes display oddly in different versions of whatever you're using to view them, there's so little in an RTF that you're almost always guaranteed you'll see the text and its formatting as it was intended, without any attempt to dictate margins or other unimportant stuff. It makes it very handy for distributing a simple document to clients that look decent, don't require any extra software to display (they will at least have WordPad, if not something bigger; I can't guarantee they'll even have a PDF viewer, or a DOC viewer for that matter), yet has just enough formatting to be "professional" (as opposed to plain text). It can also be embedded in a Windows Installer, which is part of my goal here.

Why use WordPad when I have Word installed? Well, my goal is to have a very simple file, without extra garbage or formatting codes. Creating a particular file in Word, which includes a single 24x24 picture, and saving it as RTF resulted in a 53kB document, which, if you look at in a plain text editor, you can see over 7k of format codes defining (among other things) fonts that aren't even used in the document, before the first line of actual text. Merely opening that file in WordPad and saving it (which has the effect of stripping out all the garbage, taking it down to the bare necessities) results in an identically-formatted file that is 15kB. (Unfortunately, it doesn't replace Word's "smart quotes" with standard ones.)

I remember taking a Word 2.0 document, opening it up in Word 6.0, and saving it, with no changes, and noticing the file size balloon to four times its original. So the inefficiency in Word's file formatting comes as no surprise.

Workaround: I played with this a bit before publishing this post, and I figured out the solution. If you go to the Edit menu and select "Paste Special…", you can paste the image as a Bitmap, a Picture (Metafile), or a Device Independent Bitmap. It seems the default, Bitmap, is the one that causes the problem, as selecting either other option works fine. Of course, the Edit menu is the only place this "Paste Special…" option is available, as right-click only shows "Paste" and Ctrl-V/Shift-Ins use the default option.

I tested this in Vista and the public beta of Windows 7. Copying a picture out of Paint in Vista, the default Paste in WordPad worked just fine. Paste Special showed "Unidentified", "Picture (Metafile)", and "Device Independent Bitmap", and all of these worked. I was able to get "Bitmap" as an option in Paste Special by taking a screenshot, but that, too, worked without a problem. Windows 7 had almost the exact same results, except that Paste Special with what was copied from Paint actually listed "Paint Picture" as the first option. Everything else worked pretty much the same (except for having to deal with that annoying "ribbon" toolbar in both Paint and WordPad).

So, I guess, the fix for being able to paste bitmaps in WordPad without losing the rest of the document, is to upgrade to the latest version of Windows.

2009-04-20

Fixing the DataGridView's CalendarColumn sample

In a DataGridView, it is sometimes convenient to have a column that is a DateTime that allows a user to use the standard DateTimePicker control for choosing dates. Microsoft has a code sample for a CalendarColumn class that does this, and it's more or less the standard.

Except if you actually try to use it in a WinForms application, you'll find it has two rather glaring flaws:

  1. If you try to type in a date, and you don't type in a full two digits for the month or date or four digits for the year and then tab out of the control, your change won't be committed.
  2. If you type in a date or part of a date and tab through to the same column in the next row, and you start typing, the first field highlighted (month, date, year) will be the last field highlighted when you left the last row. (Example: you type in "04/04/2009", tab until the next row's date column, and start typing "04", you'll find you're editing that date's year.)

I found this forum thread that addresses the first concern. ALight's answer involves adding an event handler to the DataGridView's CellValidating event. Because we use grids all over the application, it would've been very inconvenient to alter every grid and add this code. Instead, since our grids are built dynamically, I did it by adding this code to the CalendarColumn class (that inherits DataGridViewColumn):

protected override void OnDataGridViewChanged() {
    base.OnDataGridViewChanged();
    if (this.DataGridView != null) {
        this.DataGridView.CellValidating += new DataGridViewCellValidatingEventHandler(CalendarDataGridView_CellValidating);
    }
}

protected void CalendarDataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
    if (sender is DataGridView) {
        DataGridView dgv = (DataGridView)sender;
        if (e.ColumnIndex >= 0 && e.ColumnIndex < dgv.Columns.Count
            && e.RowIndex >= 0 && e.RowIndex < dgv.Rows.Count) {
            if (dgv.Columns[e.ColumnIndex] is CalendarColumn && dgv.Columns[e.ColumnIndex] == this) {
                if (dgv.EditingPanel != null) dgv.EditingPanel.Select();
            }
        }
    }
}

When the CalendarColumn is added to the grid's Columns collection, its DataGridView property is updated, and this routine fires to bind the method to the grid's CellValidating event. Multiple columns will cause multiple event handlers to be bound, but the dgv.Columns[e.ColumnIndex] == this part of the if statement should ensure that only one instance will run the code for any given column. (Note that I have not tested this in cases where columns may be removed from the grid. It should probably work fine, as the event will still be bound and still fire, but the column will never match.)

To solve the second problem, I did some experimentation with the existing control methods. In Microsoft's sample, there is a comment in the CalendarEditingControl's method PrepareEditingControlForEdit that reads "No preparation needs to be done." I found this to be not quite correct. The following change resets the control so, when you start typing, you start editing on the month, like you'd expect:

public void PrepareEditingControlForEdit(bool selectAll) {
    if (selectAll) base.RecreateHandle();
}

Seems to work so far, anyway.

2009-04-19

When ya gotta go, ya gotta pay

Another old post I for some reason never got around to publishing. I was talking to my mother about her experience flying out here (she was able to fly out for the weekend and give us a break from spending time at the hospital, where my son still is with an unknown diagnosis):

The idea that this is even a question to be considered is reason enough to swear off flying.

Flying out here, my mother did of course have to pay extra for something extra she brought us that she had to check. Compared to a flight down to Mexico she had not two weeks earlier, when they didn't charge for extra weight per person (one of her party did have an overweight bag, but they averaged the weight of all bags for all fliers in their party, and they didn't have to pay), meals on the plane, or even alcoholic beverages for the passengers.

It reminded me of a comment I read on someone's blog a while ago. They wondered when airlines started to charge extra for just about everything and hid behind rising fuel costs as the reason, that, if fuel costs were to go back down, would these extra costs go away? Well, I know I'm back to paying under $2 per gallon of gas, and airlines are still charging for whatever they can get away with.

I know I've said it before, but it's a large part of the reason why, even when gas prices were at their highest, my family and I drove out to California instead of flying. If it's just me for a weekend trip, I might consider it. For my family, no way.

MAPI FAIL

This was an old post I started to write a couple months ago. Not sure why I didn't publish it, but considering the project in question has come to an end, I can pretty much call this issue "closed as unresolved".

I thought I was close in finally being able to send an email with an attachment using the default email client in C#. The code that I found worked great when I gave it a quick test on my work machine with XP Thunderbird. It also worked on my development machine running Vista and Live Mail. But when I set up a vanilla XP virtual machine for testing, Outlook Express failed with a message "One or more parts of this message could not be displayed".

Well, at the very least, I could insert the code, and make it a configurable option so I could switch back to the old crap way of using a mailto: link if it doesn't work for the client.

Just my luck, the client recently replaced his old desktop PC with a Mac, and he had his own vanilla XP virtual machine for running Windows software. Sure enough, the mail code failed just as spectacularly in that version of Outlook Express as it did on mine.

Your mouse has moved. Reboot now?

So, to "fix" the problem with my HP tx1420us laptop that sucks in that it no longer recognizes the fact that it has a wireless network card installed, I went out and bought a USB Wi-Fi adapter. I found some online for about $20, so when I went to Best Buy, that was my target price. Unfortunately, they didn't carry any that weren't under $50. Wal-Mart, however, had a Belkin 802.11g for $30, and that was close enough for me. (The one installed in my laptop is 802.11n, but my access point is only a "g" anyway.)

I first installed it in my Windows 7 beta partition, and the installation went very smoothly. Unfortunately, though, I still had to re-configure my wireless settings — apparently, Windows 7 binds wireless configurations to the adapter, so my home WAP's configuration bound to my Broadcom card was not accessible. Not a big deal, though.

Then, I figured I'd better install the software on my Vista partition as well, before I put the CD away. One of the things they tell you to do is to install the software from the CD first, and then plug in the USB device. So I pulled the adapter out, rebooted into Vista, installed the software, and plugged in the adapter again when it prompted me. Again, I had to reconfigure my wireless settings — the binding of settings to adapter must've been a Vista thing that Windows 7 inherited.

That finished, I rebooted into Windows 7. The network adapter was detected, but it did not automatically connect to my WAP. When I pulled it up, I saw that "Belkin USB Wireless Adapter #2" did not have any wireless configurations assigned to it. Apparently, what happened was, when I was installing it in Vista and re-attached the adapter into one of the two side-by-side USB ports on the back of my laptop, I plugged it into the one other than the one I had first used for Windows 7. When Win7 booted, it found the adapter not in port #1, but in port #2, and therefore it assumed it was an entirely different adapter. (Funny, these things are supposed to have unique hardware addresses; it couldn't detect it was the exact same adapter, just moved?)

So now, when I reboot into the other environment, I have to remember to switch the USB ports for my wireless stick. Or just define the same profile for "Adapter #2". Either way, it just seems obnoxious.

2009-04-15

No more HP laptops

My wife and I got matching HP tablet PCs a year ago. (The HP Pavilion tx1420us, in case you were curious.) They sure seemed like a good deal at the time, at half the price of most other tablets. At first, I thought the only reason for the price difference was the screen — these Pavilions used a "passive" touch screen instead of an "active", so they didn't track the stylus; you had to physically tap the screen for anything to register. Unfortunately, it seems the cheaper cost has more to do with the quality of the components.

Apparently, there are compatibility issues with the components used such that, after some time, the computer will simply refuse to detect the existence of the Broadcom wireless card. Trying to find it in the device manager, it's completely gone. My wife's was the first to go, and fortunately it happened quickly enough that it was covered by warranty. Mine held on quite a while longer, until just after the warranty expired.

Since I dual-boot between Windows Vista and the Windows 7 beta, I can pretty definitively confirm it is not a software issue — the wireless card disappeared from both OSes at the same time.

A quick trip through the HP support forums revealed that this problem is far from uncommon, with this and similar product lines, and HP is somewhat less than forthcoming with support, especially after the warranty period.

I did find a support bulletin that seemed to address this problem and offer extended support, but of course it did not include my exact model. They say there is a BIOS update that will help protect against it if you don't have the problem yet. The speculation in the forums is, this will only postpone the problem until it is out of warranty, not fix it. I take that with a large grain of salt, but my own experience does make me suspicious. I tend to keep my hardware more up-to-date with drivers and patches (except for the video driver, which for some reason seems to make things worse on this machine when I try to update). So, my laptop is already running the most current BIOS. My wife's was not. Her wireless NIC failed in-warranty, mine waited until it was out of warranty. It's certainly a suspicious coincidence.

I did give HP support a chance. Two identical notebooks, purchased at exactly the same time. One's wireless card failed after six months, one at 13. The one that failed at 6 months was repaired under warranty, and the one that failed at 13, they want $99 to repair it.

"No, I'm not going to pay to repair it," I told the US customer service rep with the thick southern Asian accent. In fact, this will be the last purchase I make from HP.

Incidentally, this post was made on a 5-year-old IBM ThinkPad T40p that was at one point dropped on a hard tile floor. Had to replace the battery after that, but it still runs great. :P

2009-04-14

At least he didn't have to go far

So while I'm in transit to the hospital to meet my wife, I get a call. "We'll be in the ER." Apparently, while they were waiting for our son to get prepped for another CAT scan (after one week in the ICU, they still have not been able to positively identify the source of his illness), our toddler slipped, hit his head on a counter, and cracked his head open.

Considering he doesn't have a "slow" speed setting, I had always pretty much assumed it wouldn't be a matter of "if" for him, but "when". I suppose there are worse places for something like that to happen than a hospital.

And maybe it would teach him to slow down and behave? Pfft, not by a long shot. My wife reported that, while they were in the ER waiting room, with his bleeding head bandaged and waiting to be sealed up, he was still running around and climbing all over things.

2009-04-09

Looks like I picked the wrong week...

Well, this week has certainly been… "interesting."

My second son came down with a fever last Thursday. When he had a sore throat, we took him to his doctor, who checked for strep, but didn't find anything. When he broke out in a rash over the weekend, we went to the doctor again, who diagnosed it as a rash that sometimes occurs when the fever breaks — indeed, his temperature had dropped that day. By Monday, though, he was still feverish (his temperature kept randomly spiking), and he had barely eaten or drunk anything since the fever first hit, so I called a friend to assist me in giving him a priesthood blessing. On Tuesday morning, he started having severe stomach pains, and my wife took him to the doctor. She then called me at work to say, "Can you meet us at the Children's Hospital ER?"

We spent most of the day in the ER. They did X-rays and a CAT scan to check for appendicitis and any other internal injuries that might have required surgery, but everything came up negative. Eventually they decided to check him into a regular hospital room, but at some point before admission they changed their minds and checked him into the ICU instead so they could monitor him more closely.

I spent the night at the hospital with him there, and the next morning my wife came to switch places with me while I went back to work. His blood pressure was dropping, so they decided to operate to install a more direct blood pressure monitor. In the meantime, we decided to get him a Nintendo DSi to try and help him get through his stay. After the operation, the DSi lifted his spirits, but only temporarily. He had such difficulty coming out of the anesthesia that he couldn't even hold the stylus.

Later in the day, they ended up putting him in an incubator with a breathing tube and another IV, so they could administer antibiotics, blood pressure medication, nutrients, and sedatives (they say it's common to have to keep kids sedated, since being hooked up to all those tubes is very traumatic; considering how high-strung my son is, I don't doubt they're needed here).

That's pretty much were he is as of now — in the incubator, sedated, on medication, closely monitored. They're pretty sure it's a bacterial infection, but they don't have an exact diagnosis yet. His fever keeps spiking from time to time, but they do a culture every time and find no new growths. At least they're able to gradually reduce his blood pressure medication as that stabilizes.

In other news, I was supposed to help out an old friend tonight with some computer problems. I called to ask if we could reschedule, since I'll probably be in the hospital tonight. He of course said that would be fine. Then he asked if I had heard about a mutual friend of ours. "…What about him?" I asked. He said he was having some personal problems, and that I could google it. I thought that was kind of odd, since I didn't expect to see someone's personal problems on Google. I didn't think I knew anyone who would garner wide internet recognition. Yet when I googled his name, there came up several stories about him being investigated by the SEC, pictures of his home and "assets being seized", etc.

Not only was it a shock to hear this about him personally, but it was also a little unnerving to realize how close I was to the situation. I do some freelance computer work, and I wrote for him an account management program which basically automated some of the tasks he was doing in spreadsheets. As I'm reading these news stories, they mention account statements sent to clients with bad information, and I realize that it's my program that generated these very statements.

I don't expect any harm will come my way. The allegations against my friend have nothing to do with my program directly — my code only took the information he fed it, made calculations based on his specifications, and showed the results; and the allegations are solely based on factors outside of that. I never even received any money for my services — being too much of a perfectionist, I guess, I didn't want to bill him until I felt the product was "finished", and it seemed there was always just one more thing I didn't feel was quite right. So far, no one has contacted me to make any requests for information, but if they do, I can always provide the entire source code for the application and demonstrate that it only works to track the values it's told, not to independently audit or track investments.

It's a good thing I don't smoke, drink, or do drugs, because if I did, this would be the wrong week to try to quit.

2009-04-05

Bandwidth for March

Nothing terribly exciting to report for March, so here are the stats: 15.78GB down, 4.07GB up, 19.84GB total.

As of the writing for this blog post, which is just after another weekend of our church's general conference (probably about 10 hours of streaming video — two 2-hour sessions on Saturday, two on Sunday, and we let it stream video for the two hours in between Sunday sessions as well instead of stopping and restarting), the "all-time total" stands at 221.05GB. Over seven total months, and I still have not reached the limit for a single month.

Of course, I don't do a lot of high-bandwidth activities. Maybe I should torrent this "Bee Ess Gee" show that everyone's been talking about for the past couple years...

2009-03-26

Heavenly Father, I thank Thee for this day...

Got up, drove the kids to school (which happens to be very close to work). The sky was overcast and there was a dusting of snow on the rooftops; nothing that would've even made me think to wonder if school was canceled today. It was. "There's a blizzard coming this afternoon, so they canceled school," the guy there told us.

So I drove the kids all the way back home, and then all the way back to work. (It's about 25 minutes each way, made more annoying by the fact that my work and the kids' school are nearly across the street from each other — so it didn't just feel like back-and-forth, it was.)

Got to work. A big software upgrade that I was working on has been put on hold, but I need to get some new features and bug fixes out soon, so I had to copy off and roll back my changes. Except I slipped and clicked the "check-in" button. Fortunately, it was after I made a list of all the files I would be copying, so I spent all morning going file by file rolling back changes where needed. (Some changes I wanted to keep anyway, since they were themselves bug fixes. As it is, I'm not sure my mistake really set me back much.)

In the process, the promised blizzard rolled in. Our office decided to close at noon and send everyone who could work from home, home. I'm fortunate that I can. But I had to finish my check-out, check-in undo thing, since I wouldn't have access to the network from home. Plus I had a support call that kept me tied up for part of the morning. So I didn't get out until 12:30 — which, all in all wasn't too bad.

Got outside and decided to put chains on my car. This turned out to be the smart move of the day. Although it meant I didn't get started until 1, I didn't slip or slide at all on the entire drive home in my lightweight hybrid. The same could not be said for the rear-wheel drive cars that ended up blocking traffic on the main road — two of which I ended up helping push out of the way. One of them was a rear-wheel drive SUV. I didn't even know those existed. I also saw a rear-wheel drive extended-cab pickup truck slide off to the side of the road at one point.

It took me an hour to go the two blocks from my office's parking lot to the main road (the two cars I helped push happened to be blocking my turn onto that main road, which I'm sure was part of the delay — although how long they were there and/or if they replaced other cars that were stuck there moments before, I couldn't say). It was very slow going down that road. (Interesting side note: normally three lanes, there were four lanes of traffic heading in my direction. Amazing what happens when no one can see the lines.)

I finally got home at 3:30, took about a half hour fighting with my laptop before I gave up connecting it to my wireless network and took it upstairs to plug it in to my office network hub, when my oldest son came up to tell me that his younger brother had thrown up on the couch. Since my wife and the toddler were down for a nap, I went downstairs and started cleaning.

However, except for one kid who's a little sick (no fever), everyone's home and safe. And for that, I thank The Lord for a good day.

2009-03-14

Well, that was painless... mostly...

I noticed that Debian had released version 5.0 Lenny. Considering I was still running my server on Debian 3.1 and had completely missed 4.0, I decided that it was probably time to upgrade.

I went to Debian's site, followed the handy link to the release notes (that was in the sentence "If you are upgrading from a previous version"), went to the chapter about upgrading (chapter 4, if you were wondering), and followed the step-by-step instructions.

When I rebooted my system, I did so directly from the machine itself, which was good, because installing the new kernel did not select it as the default in grub. I also noticed that iptables did not load its rule set, and I quickly discovered it was because I had recompiled the previous kernel myself to include a "TARPIT" rule that didn't exist in a stock kernel image. Updating the rules to just go to a "drop" rule seemed to work, except my wireless subnet was having difficulty connecting. Long story short, I didn't need the extra drop rules (basic ones already existed), and once I removed them, all was right with the world.

I was even able to upgrade PHP to version 5 and finally get the graphs working in the vnstat PHP front-end. (They're still limited to the rolling 30 days that vnstat records, so I'll still be using my own graphs for my reports, though.)

All in all, it was a pretty painless process, most of it I was able to do from the comfort of my laptop.

[edit] Um, mostly. It seems that about a third of my packets between the internet and my wireless subnet are just getting dropped. Figures; it couldn't be that smooth.

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.