Monday, December 31, 2007

Zero! In!

While at DevConnections, I ran into a former co-worker, Dave Esposito.  Late one evening, we tossing back a few beverages and it turned out that 20+ years ago, we hung out on different edges of music scene in Albany.  I tossed out a few names of some musicians and it turned out that we both knew Billy Harrigan. 

I mentioned that Bill always detested me and what I did to his dog didn't help.  It turned out that Dave had heard that story but never knew that I was involved.  It's a fun story to share and n0 animals were harmed.  I briefly mentioned it once before, I think it's time to share the full story.

It's time to set the Wayback machine to 1983.  I was spending my free time hanging out with Jack Nemier.  Jack and his then fiance (and now wife) Judy were renting this tiny, one bedroom cottage in Colonie.  Jack had just joined the band "Operation Pluto" and the band rehearsed at Jack's house.

Operation Pluto consisted of the late Billy Harrigan, Richard Fuller, and Jack.  At best, Bill and Richard tolerated me.  Since it was Jack's house, they had to put up with me. 

Bill and his wife had a dog and a cat and one fine summer day, Bill dropped them off at Jack's house.  Bill's landlord wouldn't let him have pets so the animals had to go.  He asked Jack if they could stay there for a while, while Bill worked on convincing his landlord to let him have the pets.  Jack really didn't want someone else's animals, but he felt that he couldn't say no.

The dog was named "Zero" and was one of those little yappy dogs.  More enthusiasm than brains, if you know what I mean.  Jack pretty much ignored Zero and the cat, so Zero looked to me for attention.  At that point in time, I had no experience whatsoever with dogs, but I played with the dog and he got used to me.  Jack wasn't terribly diligent about feeding the dog or the cat, so I ended up doing it a good portion of the time.

By the time fall came around, Jack wanted the pets gone.  Bill didn't appear to be any particular hurry to retrieve his pets.  And I, not knowing anything about dog training, decided to see if I could teach Zero a trick.

Since Zero was always hungry, it turns out that he was quite amenable to learning new tricks, especially if food was involved.  I had discovered the basic rule of dog training, food.

After a remarkably short amount of time and dog biscuits, I had taught Zero to jump out the living room window on command.  The windows didn't have any screens and the season was warm enough that the windows were usually open.  The living room window was above a couch, and he would use the couch as a launch pad. A similar command would launch the hapless mutt back in through the window.

Zero was just big enough to reach the window sill from outside the house.  It was the funniest thing that we had seen in a long while.  Zero had lots of fun doing this trick and he basked in the attention it brought to him.

The next time Bill came over to the house for band rehearsal, I was already there.  He came in and the first thing he said was "Where's Zero?"  Zero was outside in the yard playing.  I innocently said, "I'll get him" and then yelled "Zero! In!".  About 5 seconds later, the dog comes flying in through the window.

Bill was stunned and more than just slightly pissed off at me.  He said "What just happened?"  I replied, "We've been teaching Zero new tricks.  Zero! Out!".  The dog ran to the couch and jumped out the window.   I then had Zero jump back in once more, so Bill could appreciate the sound of the dog's claws scrambling against the side of house as he jumped up to the window and pulled himself back in.  Needless to say, Bill took Zero and the cat home with him that day.

Bill left this mortal coil back in 2001, but the MySpace link attached to his name up above (and here) has some of his music recorded as "New Shiny Things" and as "Operation Pluto".

Sunday, December 30, 2007

Thoughts on trading the Town & Country for the Odyssey

I was reading Steve Tibbett's post about trading in his Dodge Caravan for a Toyota RAV4 and I started thinking about the last trade in I did.  Back in August, we traded in our '03 Chrysler Town & Country in for a new '07 Honda Odyssey.

We bought the Town & Country just before we adopted Laura.  It was a nice van, but four years later, it was out of warranty and it felt like every time I took it in a for an oil change, it needed a few hundred dollars worth of work for one idiot thing or another.

Anne and I talked about trading it in and we had narrowed it down to the Toyota Sienna and the Honda Odyssey.  Both are very good vehicles, and I was sure we would be happy with either one.  Late last summer, I started pricing both vans with the options we would want.  The Edwards site is great for that sort of thing.  I also checked the trade-in value of the Town & Country so I would have a good idea of what the final cost would be.

We had the luxury of not being in any kind of hurry to trade the Town & Country in.   We could wait for the end of model year sales and try to get the best deal.  We had the time to test drive different models and get a feel of what we liked and disliked.

Last fall, Rennsselaer Honda had a "Hail Sale".  They were hit with a major hail storm and almost all of the vehicles in their lot had suffered minor hail damage.  Because of the damage, they were taking an additional $1500 off their sales price.  We decided to go down an take a look.

The place was mobbed and people were buying cars left and right.  We had to wait nearly an hour just to see a salesman.   While we waited, we walked through the lot and saw that they had 6 Odysseys.  Two were the Touring edition, which was out of the price range that we were looking for.  Two of the others didn't have the options that we wanted.  That left two EX-L models that we would be happy with.  The hail damage was very slight.  A few little dings here and there, you had to look close up at the right angle just to see them.  None of the dings had gone through the clear coat finish, so we were not worried about long term rust issues.

We got one of the old school salesmen, the ones that use the sale tactics that make you hate buying a new car.  He wanted us to take a van for a test drive, while his people looked over my van.  He wouldn't proceed until I told him how much I wanted for my van.  I didn't want to play the numbers game that early, but he was persistent.

I gave him an absurdly high number, $10,000, and he smiled and said that was a  good starting point.  He gave us the keys to the Odyssey that we liked the most and Anne and I took it out for a drive.  While driving I told Anne that I was going to play hard ball with the salesman and to be prepared to walk out with out buying a vehicle.

When we got back and sat down with the salesman, he asked if we were ready to make an offer.  I said "yes" and he then presented to us a sheet with the four squares on it.  The "4-square"  is the how the dealer tries to get you to pay the highest price for the vehicle.

Each square has a number in it.  The first number has the purchase price of the new vehicle, the trade in value of the current vehicle, the down payment, and the monthly payment.  Basically they make it difficult to see how much you are actually paying until you agree the sign the paper work.

Having read the article on The Consumerist web site about how the 4-square works, I declined to play that game (and a similar article was hysterical).  I politely, but firmly, pushed the sheet back to the salesman and said that I didn't need to see that sheet.  I said that I wasn't going base the purchase around the monthly payment figure.  I was going to bring my own financing and we would only discuss the amount that I would be the final purchase price with all taxes and fees included.  The salesman started talking about the trade in value of y van and new van price and I politely (but firmly) cut him off.  I said that I didn't care how the numbers were sliced, the only number that mattered would be the amount on the check.  I told him that I knew what my car was worth, what his car cost, what wiggle room he had and that there was going to be $1500 off for the "Hail Sale"

Once he realized that I wasn't going to play the 4-square game, he asked me for my offer.  I knew that they would turn down any initial offer, so I deliberately low balled it.  I had already figured that $27K would be the fair and reasonable amount to pay.  So I came back with $26K.  The salesman told me that he would have to take it to the business manager and he would be right back.  That's the code phrase for he was going to have a cigarette and make us wait and break our resolve.

He came back with $29K and change and tried to explain why how they came up with those numbers.  I said that was way too high and I asked for the keys for my van back.  He asked for a counter offer and I said $27K and that was final.  He went back to the manager and came back with 28K.  I said that was still too high and I think we would call it a night.  He blinked and asked for a final offer.  I said $27,500 and we were not going to wait another 10-15  minutes for his manager and if they didn't meet that offer, then we were done.  He came back with $27,504 or something like that.  I guess he wanted to say that he picked the final price.  I could care less about that sort of detail, the 27.5 number was close enough that we were comfortable with deal.

They tried to play a few more games with arranging financing and buying all sorts of warrantees, but I declined all of that.

After going through that nonsense, we love the Odyssey.  It feels like a better built vehicle than the Town & Country.  We are getting better gas mileage, that was an unexpected bonus.  There are a few things that the Town & Country had that didn't come with Odyssey, pretty much like what Steve noted on his trade in. 

The big thing was not having a powered rear hatch.  It was one of the more useful luxuries with the  Town & Country.  You could only get that on the Touring model of the Odyssey, but that would have added about $6K to the price tag.  The handling of the Odyssey is much better, you get a real feel for the road.  The Town & Country pretty much insulates you from the road.

Friday, December 28, 2007

Citizens Bank Debit card security worries me

A few weeks ago (on December 9th), I was reviewing my Citizens Bank checking account history online when I saw two transactions that didn't belong to me.  They were debit card (MasterCard) charges from an online grocery store in another state, halfway across the country.  They were posted on 11/27 and 11/28 for about $260 and $11 respectively.  I'm going to be vague about the amounts and the identity of the online grocery.   The online grocery made an honest mistake and did everything they could to rectify the matter with in a day.

I immediately called the 800 number on the back of the debit card.  The customer service rep told me that I needed to file a fraud report.  We could do it over the phone, but since it would need to be notarized, it would be faster to go a local branch office and file the report there.  I then asked to have my debit cards reissued to prevent any additional transactions from going through.

The next day, I went to local branch of Citizens Bank and filled out the fraud report.  I was told that I would get a provisional credit for the amount that was taken out within 10 business days.  It would take 45 days for the fraud report to be processed.

On 12/17, my replacement debit card arrived in the mail.  There was no sign of my wife's debit card.  I called the 800 number again and I was told that only my card was reissued.  I explained why I needed both cards reissued and they said they would do a rush order on my wife's debit card and they would waive the rush order fee. 

On 12/20, my wife's card came in and I went online to verify that we were not being charged the additional fee.  I saw that fee had been applied and immediately afterwards a credit for the fee had been applied.   Then I saw another charge from the same online grocery store, dated on 12/18 for around another $250.  I called the 800 number and I was told that I would have to file a second fraud report.  Since it was in the evening, this would have to wait until the next day.

Since the fraud department at Citizens Bank was not acting fast enough, I decided to start my own investigation.  I found the home page for the grocery outfit and called their customer service number.  I left message that several fraudulent charges had been placed on my wife's debit card and I requested that someone from that company to call me.

A few hours later, I received a call from "Dan" (not his real name), the owner of the company.  He had received the message and wanted to make sure that his company had not charged the wrong person.  I gave him enough information to prove that he had indeed charged my wife's card for three separate amounts.  After some research on his part, we determined that the transactions occurred when his customer transposed two digits of his credit card number when he had placed the order.  The two subsequent charges occurred because the number had been stored in the grocer's system.

I had several conversations with the owner and the directory of finances for this company and they said that they were changing their credit card processing to apply additional checks to accidental or fraudulent use.  They immediately credited back the three transactions to my wife's canceled debit card number.  As of this date 12/28, they have not been contacted by Citizens Bank or Mastercard about these transactions

The next day (12/21), I went to the local Citizens Bank and explained what happened again.  They apologized for the problems with 800 department and called the fraud department while I was filling out the second fraud report.  They told me that the second report would be attached to the first report and I would get the provisional credit to my account that day.  The person at the fraud department had some of the more critical details wrong.  This did not leave me with a warm and fuzzy feeling.  The money was posted back to my account later that day.

I now check that account every day to see if any odd transactions will be posted.  On 12/26, the money returned by the grocery was posted to my account.  Now I had too much money in the account.  I called the local branch and they will reverse the transaction for the provisional credit.

Here's the part that really bugs me.   None of this should have happened.  The grocer should have validated the credit card number.  The name didn't match.  The shipping address didn't match.  And they didn't require the 3 digit Card Security Code from the back of the debit card.  Any of those checks would blocked the transaction from going through.  That was the first failure.

The next point of failure was when the credit card transaction was submitted.  My wife and I had used our debits on the same day the first transaction went through.  Mastercard or Citizens Bank should flagged the grocery transaction as suspicious and called me to verify the transaction.  We have never used our debit cards online and have never set foot in the state where the order was placed and shipped.

The last point of failure was with the customer service department at Citizens Bank that handles the debit cards.  When I made the first request to have the cards reissued, both cards should have been immediately reissued.  I had no way of knowing from my account history of which debit card number had been used, I wanted them both reset.

Right now my concern is that there is nothing in place with MasterCard or Citizens Bank to prevent something like this from happening again. 

Tuesday, December 18, 2007

Externally signing Wise Installation System generated executables

I had a problem with applying an Authenticode digital signature to installer that I had created with Wise Installation System 9.02.  Basically, it was failing with the lovely message:

Could not initialize installation. File size expected=3258503, size returned=3263976

The signature was being applied outside of Wise, through our build process.  We use FinalBuilder to build all of our applications and it has a handy Authenticode action for applying an Authenticode signature to the target you specify.  If I disabled that action, the installer worked.

Wise has the ability to sign it's executables, but that version is hard coded to use Microsoft's signcode executable to handle the actually signing.  Microsoft has deprecated signcode in favor of signtool and I didn't have a copy of signcode laying around.  In all likelihood, the current version of Wise's script based installer would be able to use signtool, but I can't use the current version because they broke other, more important things.

After a fair amount of googling, I found an old copy of signcode on Thawte's site on this page.  I downloaded the file set and extracted signcode and placed it in my \windows folder.  I fired up Wise and went to the "Digital Signature" page in the IDE.  That's when I saw the blindingly obvious setting that I needed to set:

 

On the “Digital Signature” in the Wise Installation System IDE, make sure that the radio button labeled “Add a digital signature externally” has been checked. Once I made that change, everything worked.

Monday, December 17, 2007

Just listened to a great interview with Dan Appleman over on Hanselminutes

That spring, I treated my self to an MP3 player, a Creative Zen Vision:M.  Why I picked a ZVM is food for another post, but it's opened up a new world to me.  The world of podcasts.  My podcast listening typically falls into two categories:  programming related and NPR shows.

One of the programming podcasts that I listen to on a regular basis is Scott Hanselman's Hanselminutes.  His stuff is very good.  He gets to interview a lot of cool people in our world.  I just listened to his 11/29th interview with Dan Appleman.  They talked about software architecture, but they concentrated on the human side of architecture. 

Dan talked about what should go in a software specification.  He mentioned something that I occasionally do and that is that the spec should clearly list what it doesn't do.  A good spec will cover what it will perform, but you usually don't see specs that clearly list what will not be performed.

That makes so much sense.  It's important to list the scope of the spec, but it's just as important to list the limits of the spec.  We all make assumptions, that's just human nature.  I've been in situations where code was delivered and people asked for feature "B".  "B" was never specified, but since the code included feature "A", they had just assumed that "B" came along with "A".  Then you have to go back to add "B" and hope it wasn't too expensive to add after the fact.

When you list what the spec wont do, it forces the client to think a little more about what they want.  If you want something additional, it's lot easier (and cheaper) to add that feature before the code has been written than after.

Tuesday, December 11, 2007

How can you give away a eight year old?

I came across a news article about the Dutch couple who gave up their eight year old daughter, who they had adopted as a baby from South Korea.  They claimed she didn't fit in their life style.  What on Earth is going through these people's minds?  She has been their daughter since she was four months old.  Since when did the disposal of second graders become a life style option?

This little girl has basically had her entire life shattered.  How does a eight year old come to terms with the fact her mommy and daddy don't want her anymore?   I can't imagine what she must be going through right now.  The family has been living in Hong Kong for the last few years, but the girl is still a South Korean citizen.  The Korean community in Hong Kong has stepped in to find her a new home,  but she's going to need some help.  So does that Dutch family.  It's just mind boggling that they could do this.

Friday, December 07, 2007

Converting Delphi enumerated values to strings

It's pretty easy to converted Delphi enumerated types to string and vice versa, but I can never remember the syntax.  The good thing about having your own blog is being able use it as an off-line cranial storage device.  I did the same thing a while back to do the same thing in .NET code.

To convert an enumerated type to a string:

uses typinfo;
function MyTypeToString( value: TMyType ): string;
begin
    result := GetEnumName(typeInfo(TMyType ), Ord(value));
end;

 

To convert a string back to an enumerated type, the following syntax can be used

uses typinfo;
function StringToMyType(const value: string): TMyType
begin
  result := TMyStyle(GetEnumValue(Typeinfo(TMyStyle), value);
end;

 

GetEnumName and GetEnumValue are defined in typinfo, you'll need to add that unit to the uses clause of your code.  This functionality is very useful if you ever need to implement your own object serialization routines in Delphi.

Thursday, December 06, 2007

Little Bobby Tables

Not too long ago, the online comic xkcd ran a strip that just killed me.


(thanks to Randall Munroe for providing the image link for hotlinking)

Our applications make extensive use of a table with a very similar name.  Most of our programmers got the joke and had a good laugh.  Our QA staff found it hysterical.  Had they been drinking milk, it would have sprayed out of their noses.

It does demonstrate quite effectively how easy it is to intentionally damage a database through a SQL injection attack.   The user enters in string literal characters into an entry field and alter the logic of the SQL statement being executed.  In the example displayed in the comic, the insert or update statement that would be been populated from the entry fields has been truncated.  A command to drop the students table would be executed immediately after the truncated insert/update had been executed.

This is an easy attack to block.  You have at least three ways to prevent this attack from going through.

Don't create your insert or update statements directly from the user editable entry fields.  If you use a parameterized SQL statement, that will block the attack.  The injection text will get written to the database as part of the entry field, but the injection SQL will not have been executed.  You get some additional benefits.  With SQL Server, the server will cache the execution plans of parameterized queries, providing a faster execution time when the next insert or update statement is execute.

Don't run the application with database login account that has enough rights to modify the database structure.  If you really want to lock down the access rights, block direct access to the tables and do everything through stored procedures.

"Sanitize your database inputs".  That usually involves the most amount of work, but a well designed application is usually doing some level of field validation.  Just filtering out the ";" from the entry field is enough to block the attack.

Monday, December 03, 2007

I used to use Yahoo...

Steve Trefethen's posting about Yahoo is pretty dead on.  I used to use the various Yahoo apps and services, but I have slowly replaced them with the various services from Google.  I think  the problem was the development team saw too many bright and shiny objects and decided to implement them.

Yahoo's email is an over-developed mess.  It's trying to be the web version of Outlook.  Even Microsoft's web version of Outlook isn't trying to be a clone of the desktop version of Outlook.  With web-based email, I want to get in and read it in as simple a manner as possible.  Thanks to the GMail Manager plugin, I have notifications when email comes into my various gmail and Google Apps email accounts get mail.

I don't want yet another proprietary IM client.  There's nothing wrong with Yahoo's IM, it's just that no one that I IM with uses it.  I prefer to use Trillian, one client to serve them all.

It's kind of sad.  I remember 10, 12 years ago when Yahoo was the only game in town for searching.  It got slower and slower to use and when Altavista came out, I dropped Yahoo for speed and simplicity of a fast search app.  And I stayed with Altavista until Google came out of nowhere and changed the search engine game as we know it.