Friday, December 4, 2009

IE8 Blank Page, Can't Browse

After some recent Windows updates, I noticed that Internet Explorer 8 didn't seem to want to browse the web.

I'd open the browser, and it wouldn't even open my home page, it would just sit at a blank screen. I could tell it was doing something; if I clicked Help, the dropdown menu showed Customer Feedback Options as the only available item (ironically enough), everything else was grayed out.

Further, if I opened a new tab and chose Reopen Last Browsing Session, it would at least load my previous session just fine, but any attempts to browse beyond this failed, as if IE8 were just spinning its wheels.

I found a fix here which worked for me. The original forum post includes a modified version of the IEREREG batch file by Kai Schaetzl that works with 64-bit Windows, but the one I'm quoting below works specifically with 32-bit Windows. It has comments describing various symptoms each step intends to address, it's almost like electroshock therapy for Internet Explorer, it re-registers many of the system components it needs in place to function normally.
@echo off
echo.
echo IEREREG Version 1.07 for IE8 27.03.2009
echo by Kai Schaetzl http://iefaq.info
echo installs and registers (if suitable) all DLLs known to be used by IE8.
echo should only take a few seconds, but please be patient
echo.
REM ******************************
echo registering IE files
REM IE files (= part of setup)
regsvr32 /s /i browseui.dll
REM regsvr32 /s /i browseui.dll,NI (unnecessary)
regsvr32 /s corpol.dll
regsvr32 /s dxtmsft.dll
regsvr32 /s dxtrans.dll
REM simple HTML Mail API
regsvr32 /s "%ProgramFiles%\internet explorer\hmmapi.dll"
REM group policy snap-in
regsvr32 /s ieaksie.dll
REM smart screen
regsvr32 /s ieapfltr.dll
REM ieak branding
regsvr32 /s iedkcs32.dll
REM dev tools
regsvr32 /s "%ProgramFiles%\internet explorer\iedvtool.dll"
regsvr32 /s iepeers.dll
REM Symptom: IE8 closes immediately on launch, missing from IE7
regsvr32 /s "%ProgramFiles%\internet explorer\ieproxy.dll"
REM no install point anymore
REM regsvr32 /s /i iesetup.dll
REM no reg point anymore
REM regsvr32 /s imgutil.dll
regsvr32 /s /i /n inetcpl.cpl
REM no install point anymore
REM regsvr32 /s /i inseng.dll
regsvr32 /s jscript.dll
REM license manager
regsvr32 /s licmgr10.dll
REM regsvr32 /s msapsspc.dll
REM regsvr32 /s mshta.exe
REM VS debugger
regsvr32 /s msdbg2.dll
REM no install point anymore
REM regsvr32 /s /i mshtml.dll
regsvr32 /s mshtmled.dll
regsvr32 /s msident.dll
REM no reg point anymore
REM regsvr32 /s msrating.dll
REM multimedia timer
regsvr32 /s mstime.dll
REM no install point anymore
REM regsvr32 /s /i occache.dll
REM process debug manager
regsvr32 /s "%ProgramFiles%\internet explorer\pdm.dll"
REM no reg point anymore
REM regsvr32 /s pngfilt.dll
REM regsvr32 /s /i setupwbv.dll (not there anymore!)
regsvr32 /s tdc.ocx
regsvr32 /s /i urlmon.dll
REM regsvr32 /s /i urlmon.dll,NI,HKLM
regsvr32 /s vbscript.dll
REM VML renderer
regsvr32 /s "%CommonProgramFiles%\microsoft shared\vgx\vgx.dll"
REM no install point anymore
REM regsvr32 /s /i webcheck.dll
regsvr32 /s /i /n wininet.dll
REM ******************************
echo registering system files
REM additional system dlls known to be used by IE
REM added 11.05.2006 Symptom: Add-Ons-Manager menu entry is present but nothing happens
regsvr32 /s extmgr.dll
REM added 12.05.2006 Symptom: Javascript links don't work (Robin Walker) .NET hub file
regsvr32 /s mscoree.dll
REM added 23.03.2009 Symptom: Find on this page is blank
regsvr32 /s oleacc.dll
REM added 24.03.2009 Symptom: Printing problems, open in new window
regsvr32 /s ole32.dll
REM mscorier.dll
REM mscories.dll
REM Symptom: open in new tab/window not working
regsvr32 /s actxprxy.dll
regsvr32 /s asctrls.ocx
regsvr32 /s cdfview.dll
regsvr32 /s comcat.dll
regsvr32 /s /i /n comctl32.dll
regsvr32 /s cryptdlg.dll
regsvr32 /s /i /n digest.dll
regsvr32 /s dispex.dll
regsvr32 /s hlink.dll
regsvr32 /s mlang.dll
regsvr32 /s mobsync.dll
regsvr32 /s /i msieftp.dll
REM regsvr32 /s msnsspc.dll #no entry point
regsvr32 /s msr2c.dll
regsvr32 /s msxml.dll
regsvr32 /s oleaut32.dll
REM regsvr32 /s plugin.ocx #no entry point
regsvr32 /s proctexe.ocx
REM plus DllRegisterServerEx ExA ExW ... ?
regsvr32 /s /i scrobj.dll
REM shdocvw.dll hasn't been updated for IE7 and IE8, it still registers itself for the Windows Internet Controls
regsvr32 /s /i shdocvw.dll
regsvr32 /s sendmail.dll
REM ******************************
REM PKI/crypto functionality
REM initpki can take very long to run and is rarely a problem
REM if there are problems with crypto, SSL, certificates
REM remove the three following REMs from the lines
REM echo We are almost done except one crypto file
REM echo but this will take very long, be patient!
REM regsvr32 /s /i:A initpki.dll
REM ******************************
REM tabbed browser, do at the end, why originally with /n ?
regsvr32 /s /i ieframe.dll
REM ******************************
echo correcting bugs in the registry
REM do some corrective work
REM Symptom: new tabs page cannot display content because it cannot access the controls (added 27. 3.2009)
REM This is a result of a bug in shdocvw.dll (see above), probably only on Windows XP
reg add "HKCR\TypeLib\{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}\1.1\0\win32" /ve /t REG_SZ /d %systemroot%\system32\ieframe.dll /f
REM ******************************
echo all tasks have been finished
echo.
pause

Once I created and ran the batch file I created above, IE8 can now happily continue to force web developers to make absurd accomodations for its nonconformist self. BING!



Friday, November 6, 2009

Getting Off God

Why would God frown upon humans using their bodies in every conceivable way, especially if God created these possibilities in the first place?

Assume for a moment God exists and did indeed create everything.

That means we were created according to Its grand design. This means that some women, for example, are double-jointed and incredibly flexible (Giggity!). It also means that anything conceivable we do to ourselves is enabled by God's design.

Since the cartilage of our ear lobes can be pierced, we can adorn them with earrings. Since our skin holds dye, we can give ourselves tattoos. This also means that since we can manually pleasure ourselves, we can masturbate.

If God indeed created these and so many other possibilities, painful as well as pleasurable, why presume these are wrong based upon the limited vision of those "inspired" by God to write Scripture, which has been interpreted to make many such activities sin?

Wednesday, November 4, 2009

RECAPTCHA the Imagination!

One of my favorite blogs, I AM NOT A ROBOT, specializing in user-contributed images highlighting sometimes wild and zany RECAPTCHA text.








In the immortal words of Forrest Gump, "You never know what you're gonna get." In this case, it can be a wonderfully goofy exercise in creativity.

Saturday, October 24, 2009

Wolfram Alpha - Divide By Too Many Zeros?

I seem to have inadvertently discovered a way to make Wolfram Alpha unavailable to me, at least for a little while.

At first I input a typical divide by zero, 1/0, it returned quickly enough with the expected response.


Then through the miracle of copy-and-paste I input the following into the search box:

1/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0


In response, I eventually got this back:

"This Wolfram|Alpha Server is temporarily unavailable."


I guess as far as Wolfram Alpha goes, if you can't dazzle it with brilliance...

Monday, October 19, 2009

Drive Technology, Make Cars Smarter

I just saw this tragic video detailing the 911 call's final moments of a family whose 2009 Lexus ES350 experienced uncontrolled acceleration, leading to a fatal crash.

According to the original LA Times article, the driver, Mark Saylor, was a veteran California Highway Patrol officer, and a related article states that Saylor and his family "
had taken their own Lexus to a dealer for servicing and been given a loaner Lexus in its place."

I've driven loaner or rental cars for various reasons, either while waiting for my regular ride to be repaired, or for fun, as was the case with a Ford Mustang convertible my wife and I took on a beach trip to St. Augustine. With a new vehicle comes new features. In my case, there was a learning curve in getting to know how to put the Mustang's top down, certainly not for safety's sake, but convenience, and of course fun. I didn't rent the convertible for the privilege of driving a Mustang, despite its heritage (Bullitt fans, represent!).

Should the Saylor family have reasonably been expected to know they'd need to compensate for sudden, uncontrolled acceleration? In my opinion, no; if you're driving a car, you expect it to be fully under your control, especially where speed and drivability are concerned.

If the car has pushbutton ignition as this one does, it seems to raise the bar a bit on what it expects the driver to be able to control. Removing the physical act of turning a key to start or stop the vehicle places the driver into a new paradigm as far as driving is concerned.

As this article regarding Toyota's safety advisory details, the driver must "
firmly and steadily push the button for at least three seconds to turn off the engine".

When I think to myself, could I push and hold my car's start button for three seconds to shut down the engine? Sure, why not? Could I do the same in a panic situation, in the middle of rush-hour traffic? California, specifically Los Angeles rush-hour traffic, trying at once to avoid a collission while at the same time trying to calm my passengers who are probably flipping out as much or more than I am?? Probably not! Therein lies the problem.

I think Toyota would do well to pioneer at least audio and possibly video warnings and introductions to their cars in the rental or loaner role.

If a car is a rental or loaner, perhaps when the driver sits down and buckles in they'd be presented with a little audio-visual presentation on the basic safety features of their vehicle. Only when the user acknowledges and signs off on basic awareness of these features, perhaps by hitting a big OK button on the car nav system's touchscreen or HUD, would they be allowed to actually get on the road.

Of course, given the level of computerization today, you might expect your car to go above and beyond the now trivial "your door is ajar", and do something like, well, prevent the car from entering the runaway acceleration state in the first place.

Why would a car be accelerating uncontrollably for any good reason, particularly in rush hour? If you're a police officer this would be perfectly reasonable to expect, you along with your sirens and flashing lights would weave in and out of traffic at high speed in pursuit of some suspects who have perhaps just robbed a bank or carjacked some poor motorist at a busy intersection. If you're an average joe taking the family out for a cruise, however, there's no reason to expect this, particularly in a rental or loaner.

What should Toyota do to prevent more tragic deaths due to uncontrolled acceleration?
  • TO SAVE LIVES, the car's onboard computer should maintain situational awareness and if necessary disable the engine or otherwise allow the driver to maintain complete control of the vehicle, before an uncontrollable state is reached.

  • TO PROTECT ITSELF, legally, it should enable a rental or loaner "mode" for its vehicles, allowing a dealership or rental company the option of having the car force its driver to OK and acknowledge safety features before allowing the car to be driven.

While I think it is certainly in the scope of driver responsibility to make onself fully aware of a vehicle's basic safety features before driving it, I think it is wholly within the manufacturer's responsibility to make their vehicles smarter.


Friday, October 16, 2009

How To Block New digg.com Ads

Recently, digg has embedded new advertising within its list of news stories, making them easier to click and detracting from what might otherwise be an interesting glance at potentially interesting copy.

You can click Bury to blot the ad out, leaving an "X" and the parting remark, "We'll try to give you fewer ads like that one." Well, gee, how about NO ads instead??

To hide this advertising, you can use Firefox in conjunction with the AdBlock Plus add-on and a companion extension, the Element Hiding Helper.

Here's a screenshot of the digg frontpage with just AdBlock Plus enabled. Note that the third entry from the top is a sponsored ad for weight loss supplements. How annoying!



The Element Hiding Helper lets you seamlessly hide text elements appearing as part of the useful content of the page you're viewing. In this case, the new ad element digg is using is encapsulated by a div tag which resembles this:
     <div rel="digg-ad:xyz" style="z-index: 5;" class="news-summary v img-summary sponsored"> 

I chose to filter the ad based on the rel attribute of the tag, specifically the "digg-ad" portion which is consistent from one of the new digg ads to the next (the xyz is a number which differs with each ad element).

I brought up the AdBlock Plus Preferences, and clicked Add Filter. Then, I input the element syntax like so:

digg.com##div[rel*="digg-ad"]

The digg.com ensures that I'm focusing on filtering these particular elements from digg.com only, while the remaining syntax filters out elements where the rel attribute begins with digg-ad.

Now, the result, no more sponsored ad element:



You'll also notice that in among the preferences list is a new subheading, "My Element Hiding Rules", which are rules specific to hiding elements within the web page itself.




You can find a good explanation here on how to pinpoint and filter elements that you find obscure your browsing experience.

Wednesday, August 12, 2009

One Ring to Rule Them All...

I recently posted an entry on the Cracked.com forums for their photoshop contest, "Movie Plots That Could Have Been Solved In Minutes".

Did I win? Nope. Even make the featured list of entries??! Nope.
Bah!

Here is an unedited version which I'd originally cropped to meet their stingy 550-pixel width requirement.






If you appreciate my sense of humor, I salute you! I raise a virtual mug of mead in your honor!

Wednesday, July 8, 2009

Fake a Floppy That Holds GIGABYTES of "Data"


The venerable 3.5” diskette has become a relic of the past. In high school I remember using them daily to store my documents, images, even some games. Now, system builders will only offer them as an optional peripheral, if at all, in their new computers.

With this little hack you can give that humble little 3.5" disk gathering dust in your closet new life, messing with your friends’ heads a bit in the process. To accomplish this, we use a disk editor to fool Windows into thinking that its file sizes are far from normal!

Stuff you'll need:
  • Windows 2000 / XP / Vista
  • 3.5" disk drive
  • 3.5" diskette
  • a disk editor like Norton DiskEdit

According to this site, your typical 1.44MB, 3.5” floppy can hold up to 224 files in its root directory. What we’ll do first is create 224 tiny text files using a simple batch file.

Create a batch file containing the following line of text in a folder on your C:\ drive, let’s say C:\TEMP. Name the file "MakeFile.BAT" or whatever you like.

FOR /L %%G IN (1, 1, 224) DO ECHO I'm file number %%G. > A:\%%G.txt


Next, open a Command Prompt, change to C:\TEMP, and execute the batch file. After a few minutes, you’ll have 224 separate little .TXT files on the diskette.

Now you need to find a disk editor, which allows you to edit data on a diskette or most any other media at the bit level. For this example I use Norton DiskEdit, a very old but still useful sector editor.

Find yourself a copy of the executable, DISKEDIT.EXE, and save it to C:\TEMP, and then type DISKEDIT and hit Enter. If you’re using Windows 2000 or XP, you’ll likely encounter the following error:

An application has attempted to directly access an incompatible diskette format, which cannot be supported. This may cause the application to function incorrectly. Choose ‘Close’ to terminate the application.


We won’t be looking at the hard drive, so for purposes of this example you can safely click Ignore. From there you should arrive at the main DISKEDIT screen.



My system isn’t rendering this old DOS application’s fonts properly in windowed mode, but regardless you can use the arrow keys to ensure that the ‘3½” floppy’ and ‘Logical disks’ entries are selected and in red. Then, move to highlight the OK button and hit Enter to proceed.

Your diskette drive should whir for a few moments, and one great feature of DISKEDIT will make itself apparent. The next screen will bring you to the FAT of the disk, listing the files you created above.



Now, move the black cursor so that it’s hovering under the Size column on the first row, you can use the arrow keys but hitting TAB will be quicker. Type 9999999999 (ten 9s), and then tap the down arrow to move to the next row. You’ll notice that the file size changes from a humble two digits to a value of 1,410,065,407 which is roughly 1.4 gigabytes.

You can proceed to change the sizes of each of the remaining files, from 220 to 11 as listed above. When you tap the arrow key past the last file, you’ll get prompted to Write, Discard, or Review your changes. Arrow over so that Write is selected, then hit Enter.



Since DISKEDIT is open, it’s got exclusive access to your diskette. To view our handiwork so far, close the program, and then navigate to the diskette in Windows Explorer. The sixteen files we just modified now show themselves as taking up 21 GB of space.



You can either manually update the size of each file, or use a tool like the excellent (and open-source) AutoHotKey to speed up the process.

In the end, you’ll have a disk which, on the surface, says it’s got around 294 GB of data, but which in actuality contains just a tiny fraction.


Some caveats:
  • The files themselves will be unusable. Try to open them in Notepad, for example, and Windows will complain they're too big.

  • Changes you save to the files will override this hack. Save and overwrite any of the files and they'll revert to their plain old file size according to the file system rules.

  • The fake file size can go beyond 1,410,065,407 bytes apiece. Due to a quirk in Norton Diskedit, instead of ten 9s, you could input ten 7s and have each file be around 3.4 GB instead. I just chose the 9s arbitrarily because 9 is just, well, special. That's all, nothing else. Different disk editors may yield different results, and flexibility.

  • This trick won't fool p2p file sharing programs. I tried a few open-source variants using the DC++ protocol and each balked at the disk, wanting to have Windows run CHKDSK to fix the "errors". You'll just have to share those 500 GB of data the hard way to gain access to those l33t servers in Sweden, unless you know of a way to "cloak" the diskette's true nature from the application and the operating system.


Saturday, May 30, 2009

No Internet After Installing Vista SP2

I'd just noticed Vista service pack 2 had become available via Automatic Updates, and decided to take the plunge and update my Lenovo N100 laptop.

Upon rebooting, I was able to connect to other XP machines on my LAN, but not the internet.



I found a helpful newsgroup post where some other users described similar woes following the update, including links to a variety of workarounds for a variety of situations. My laptop connects to the router with a static IP, so cases where DHCP mysteriously failed to acquire an address didn't apply to me. I also don't keep my router on a different subnet, so another possibility gone.

Fortunately, in my case I was just able to uninstall my wireless network adapter, in this case a Broadcom BCM43XG, and have Vista reinstall it.


PROCEDURE
  1. Open Device Manager by holding the Windows key and then hitting the Pause key, then clicking the Device Manager link in the upper left corner of the Control Panel => System screen. Alternatively, you can open it using one of the methods outlined here.

  2. Expand the Network Adapters category in the device list, and then right-click on your wireless network adapter (in my case, its display name is listed as "Broadcom 802.11 Network Adapter"), click Uninstall, and then click OK to confirm. If prompted to remove the device driver associated with the network adapter, do not do so. In this case Vista is the problem, not the device driver.

  3. Right-click the entry at the very top of the device list (indicated by your computer's name) and click "Scan for hardware changes". Vista will find and reconfigure the wireless network adapter and should shortly inform you that it's ready for action.

  4. Use either Vista's built-in wireless network management tools, or a third-party utility (in my case, ThinkVantage Access Connections 5), to reconfigure your wireless connection properties (if you aren't already using a wireless security protocol like WPA, I strongly suggest you implement it).

Given the myriad of notebook and wireless configurations out there, it's not at all surprising that a given configuration will not emerge completely intact from a typical Windows service pack install.

In this case, I think that whatever particulars about the configuration of my wireless network adapter, which incidentally has remained much the same since before Vista service pack 1, introduced a monkey wrench which shot out my adapter's knees under service pack 2.


By uninstalling the adapter and then reinstalling it under the updated "device bureaucracy" of Vista service pack 2, this allowed Vista and the adapter to happily coexist once more.

Friday, March 20, 2009

Transferring Files from an OLD Mac to a PC

A friend of mine gave me his ancient Mac PowerBook 140 and asked me if I could possibly transfer some document files to the PC platform.

"Sure!" I replied, enthusiastically. Little did I know the ordeal that was to come. Now, at least, I've learned from it and can spread the word to other PC people who might've had a Mac dropped in their midst.

I plugged in the old PowerBook's clunky AC adapter and eventually found the power switch on the left-rear panel. The cheesy "BOM BOMMMMM…" greeting tone came through, so far, so good. A grayscale image eventually flickered into view.



I don't know whether the display was responding to solar flares, unclean power, or sketchy connectors from the motherboard to the screen, but it took some effort to get the image to remain stable. The backlight appeared to be on its way out, like one of those ubiquitous fluorescent bulbs in a school or office that's started its death flickers. My initial idea was simply to offload the documents via the PowerBook's 3.5" diskette drive, so caveman-like, I grabbed up a handy diskette, plenty of which I have gathering dust in my desk drawer, and managed to single-click my way to formatting the diskette.

Sadly this was nixed by what the Mac reported as at least several dozen MB of documents and images on its hard drive. Worse, neither network nor USB nor writeable CD were an option with this old Mac.

Undaunted, I flipped off the PowerBook in disgust, then unplugged the sucker and let it sit on a table in my room while other more pressing, and interesting, things took up my time.

Weeks, then months, passed by. Yesterday I revisit the PowerBook, now a fine layer of dust and dog hair adorning its gray exterior. I pick it up and notice the power plug sticking out of the right-rear panel is askew for some reason. I yank the plug out and the metal sleeve is bent at around a 45-degree angle. Whoops! I probably carelessly bumped into it at some point, popping the thing.


I try plugging the AC adapter in, then try carefully squeezing the sleeve back into place, and try working it around like a Q-Tip™ to see if I can get any power. Nope. I try realigning the sleeve again and notice that it's for naught, because the sleeve has been completely sheared away from the rest of the plug assembly.

Clearly if I'm going to get power to this clunker, I need to replace the plug. I dig around my collection of old and unused AC adapters, refugees from years of electronics equipment gone astray, lost to lightning strikes, or given away or sold with the wrong adapter in the package, separating the two forever.

I find one possible candidate, an old AC adapter from a 2400 baud modem, with a similarly shaped plug. I slice off the plug, slice away the broken Apple plug, and splice the replacement, then apply power. No dice!

Frustrated, I start digging around in a drawer where I keep anything from old greeting cards to duct tape to spare change. I find a strip of plugs from a universal AC adapter which has gone AWOL, each has two metal pins which are meant to plug in to a socket in the adapter’s cable. At this point I don’t care about a clean fit, so I grab the largest of the plugs and then go ahead and strip the wires from the Apple adapter and solder them to the pins. Incidentally, I have no idea off hand which is positive and which is negative, but as it happens when I get frustrated, I get impatient, so I opted to take the 50/50 shot at blowing something up.


Success, the annoying "BOM BOMMMMM…" smacks my eardrums!

Now I start poking around on the Mac to try to gather up all the files and compress them. Documents in general are notoriously compressible, so I figure I can get at least a good 70-80% compression on average. The problem, unlike Windows XP, with its default “Send to Compressed File” context menu option from Explorer, this System 7.0.1 doesn’t seem to have any way to compress files, let alone right-click. There is a StuffIt Expander 4.0.1 installed, but it only uncompresses.

Unperturbed, I set out in search of a compression utility. I checked out the latest version of
StuffIt, but it requires the latest and greatest MacOS. I took a quick look, they didn’t seem to have download links for prior versions readily available. I searched around and found references to DropStuff 4.0.1, StuffIt Expander’s counterpart, which would enable me to gasp compress files and folders.

Of course, the StuffIt site didn’t have this file available, so I visited some FTP search sites, ending up finally at
FileWatcher. A forum thread I came upon actually had a post where a user had mentioned the name of an .HQX file, dropstuff_w_ee_4_installer.hqx, which is basically the equivalent of a SETUP.EXE file in Windows. This is what I needed.

FileWatcher provided me with a suitable FTP site hosting the file, so I grabbed it, and on a freshly-formatted diskette, copied the .HQX file. I then inserted the diskette into the Mac’s drive and attempted to execute what should be an executable. I get this error message:

The document could not be opened because the application program that created it could not be found.


So let me get this straight, it’s an executable which can’t be executed, because the Mac tried and failed to find an application associated with it? Strange, too, was the fact that the DropStuff installer icon itself was plain, as if symbolic of an unknown file type. Did the Mac just not know what to do with this file? Did I grab a version of DropStuff which somehow was unreadable by this version of the System OS?

I decided to fall back and punt. I took a break, got a tasty beverage, then did some more research. It turned out that I had naively taken a blurb I’d heard years ago about Macs being able to read PC-formatted disks too seriously. It turned out not to work quite so seamlessly.

Eventually I found and installed the handy utility
TransMac which enables Mac and PC files to be transferred from their respective media. Once I used this utility to create a Mac-formatted diskette on my PC, then copied the DropStuff installer to it, I found to my relief that when I inserted the diskette into the Mac, its own pixellated little icon appeared. When I clicked twice on the icon, an installer opened and began the installation process. At last, I was able to use DropStuff to systematically grab and compress my pal Don’s documents, copy them to diskette, and with TransMac as my Mac-to-PC ambassador, copy the resulting .SIT files to a folder on my PC.

I finally found and installed an old but Windows-compatible version 5 of the StuffIt suite to enable me to uncompress the document files on my Windows machine and migrate them to a writeable CD.


PROCEDURE

  1. Install TransMac on the Windows computer.

  1. Use TransMac to format a Mac diskette.

  1. Locate a file with an .HQX extension for a Mac version of DropStuff or a similar compression utility.

  1. Copy the .HQX file to diskette using TransMac.

  1. Install DropStuff on the Mac.

  1. Use DropStuff to compress files and folders, and copy them from Mac to diskette.

  1. Copy files from diskette to PC using TransMac.

  1. Install a Windows version of StuffIt, and use this to uncompress the .SIT files containing the migrated document files.



Aside from the PowerBook’s annoying lack of a simple eject button to pop the diskette out of the Mac, instead depending on the quaint user interface option of “Put Away” to get it back, things went pretty smoothly!
Now this Mac can go into the dark night of the technology graveyard as many things have and will continue to do.



Monday, March 9, 2009

Top 10 List on 10 Separate Pages?? Uhhh... NO.

I discovered a new old Firefox add-on which is my new favorite. Repagination lets you take many annoyingly spoon-fed articles on the web which are broken up into separate pages and consolidate them as you like.

Increasingly, to get their advertising exposed to as many eyes as possible, content publishers will take anything from a howto article to a top 10 list and break it into individual pages. I think mainly the purpose of this is increase the CPM, which is understandable if someone is publishing content for purposes of earning some money.

Another reason for doing this is to try to regulate how much bandwidth is consumed in viewing the site. One user gobbling up 1 item of a top 10 list at a time uses less bandwidth than a user grabbing all 10 items at once. This is certainly a concern particularly for a forum which might be running with an ISP which charges for monthly bandwidth overage. However, some sites like Something Awful will do stuff like charge users a one-time fee for the privilege of searching their forum. While this is understandable, I find it annoying.

Say you have a favorite thread on a forum which is huge, but unfortunately only shows a set limit of posts per page. This add-on lets you bypass the site's limitation, and lets you consolidate all the posts into a single, huge web document.

In the screenshot below, by right-clicking on the Next link, a Repagination popup menu is present, and the "All" option I choose lets me append to the current page all subsequent pages of the forum thread.


In this example, a thread which is several hundred pages long can, if I like, be loaded en masse in a single browser window. At that point, I can easily search it for references, in this case, to artists or songs I like, or just save the whole mess for viewing later on a laptop if I happen to be somewhere without wireless connectivity (a situation which is becoming increasingly infrequent).

While the popularity of this kind of add-on certainly will open the floodgates as far as your ability to gobble up more of a content publisher's bandwidth at one time, it also will and arguably should send the message that informed users can and will get around attempts to spoon-feed content and advertising to them.

Although this add-on hasn't been updated recently, someone posted an update to this extension here which makes it compatible with Firefox 3.x. I hope that the author will consider an update of his own, I find it an incredibly helpful and useful add-on!

Wednesday, February 18, 2009

When MAX Isn't - Getting the Maximum Value of a VARCHAR Field

A user reported that a UI being fed by a particular SQL stored procedure was returning the wrong dollar amount for a customer account on an invoicing system I help maintain.

The particulars of the (somewhat convoluted) balance calculation aren't terribly exciting, but in a nutshell, a part of the process involves grabbing the most recent customer invoice by its InvoiceNumber, and using a value associated with that invoice to perform other calculations which eventually lead to the account balance.

This is a list of the customer's InvoiceNumber values, in descending order as they appear in the Invoices table.
SELECT InvoiceNumber
FROM Invoices
WHERE AccountKey = '99432'
ORDER BY InvoiceNumber DESC

12345678900902
12345678900901
1234567890507
1234567890506
1234567890505

AccountKey represents a foreign key in the Invoices table representing the customer account. Notice that the result set shows the most recent Invoice at the top of the list, and since the primary key for the Invoices table is auto-incrementing, that invoice possesses the largest key value.

Some years back, a data fix was made to this table whereby the customer account number (in this case, 1234567890) was changed to add an additional digit. Thus, what was once 1234567890 became 12345678900.

Time went by. In the last couple of months, a different data fix was made to a piece of code responsible for calculating account balances, specifically late fee calculations. This turned out to be the crux of the matter, as you'll see here.

The code which calculates the account balance, as I mentioned, needs to obtain the customer's most recent InvoiceNumber. The code used to grab this had been modified to add this section of code as follows:
SELECT MAX(InvoiceNumber)
FROM Invoices
WHERE AccountKey = '99432'

1234567890507

Take a look at the position of this InvoiceNumber in the actual list:
12345678900902
12345678900901
1234567890507
1234567890506
1234567890505

Rhut rho! There's the problem. The InvoiceNumber field is of the SQL data type varchar, and consequently the MAX function is returning what is alphanumerically the largest value, when in fact numerically the one at the top of the list should be returned instead. This resulted in the wrong InvoiceNumber being grabbed as part of the late fee calculation, and this further led to a certain balance threshold not being exceeded, which then altered the balance from what it needs to be.

The fix is easy, just CAST the InvoiceNumber to a decimal within the MAX function.
SELECT MAX(CAST(InvoiceNumber AS decimal(18,0))
FROM Invoices
WHERE AccountKey = '99432'

12345678900902

Modifying this code allowed the process to properly obtain and work with the most recent InvoiceNumber. You might be asking, why not just avoid the hassle, and grab the MAX of the Invoices table's primary key for the given AccountKey value? That would certainly make more sense, and would be more efficient, after all, the primary key field for the Invoices table is an integer, not a varchar(25) like the InvoiceNumber.

However, the code which does the calculations is outside my normal scope, so rather than modify someone else's handiwork to the extent I'd prefer, I'm opting for a less invasive change which will compensate for whatever necessitates getting the InvoiceNumber directly. In resolving this issue, I've left detailed commentary in the work order on our internal helpdesk system, so that whomever stumbles across this code in future will have a point of reference.

Friday, January 2, 2009

Extend Existing XML Parsing to Support Multiple Child Tags

I work on a database which is currently a mix of Microsoft SQL 2000 and 2005 T-SQL code. As part of a project I’m working on, I'm working with a stored procedure which receives a reference to an XML document in the form of an integer variable @idoc, and this XML document’s structure needs to be extended with some additional elements.

I'd prefer to refactor the plumbing which generates the XML in the remote stored procedure so that I can take advantage of the new XML data type in 2005, which would allow me to simply pass the XML as a parameter to my stored proc, but unfortunately time is of the essence, so I need to develop an alternative which doesn't involve refactoring to that extent.

The current XML resembles the following:

<XML>
<AccountInfo
Number="123456789"
Status="Active"
Region="SE" />
</XML>


The new XML will look like this:

<XML>
<AccountInfo
Number="123456789"
Status="Active"
Region="SE" />
<State>
<StateInfo
Name="Florida"
Population="9488294"
AreaSquareMiles="58560"
LandAreaSquareMiles="54252"
WaterAreaSquareMiles="4308" />
<County
Name="Alachua"
Population="277120" />
<County
Name="Union"
Population="14842" />
</State>
</XML>


The stored procedure which I need to modify for my project receives the pointer to the XML document, @idoc, and after extracting values from it makes various other calls to other stored procs.

A new State element is being added, with a child StateInfo element that describes the state in question, and any number of child County elements describing counties in that state. In other words, this XML describes an account, the state it operates in, and however many counties the state contains which are relevant to a given account.

My major challenge with this is in the form of the new County tags. Whereas previously there would only ever be a single instance of any particular tag in this XML, there could potentially be dozens of County tags associated with a given State for an account! For each County I need to be able to iterate through the collection and provide these details somehow to my stored procedure for further processing.

My work is pretty well cut out for me. I need to find a way to:
  • Rebuild the XML document using the @idoc as a reference.
  • Grab the new XML specific to each County tag and serialize the values.
To reproduce the XML in the state my stored procedure will be consuming it, I first needed to generate my own @idoc using sp_xml_preparedocument like this:

DECLARE @TestXML varchar(4000)
DECLARE @idoc int

SET @TestXML = '<XML>
<AccountInfo
Number="123456789"
Status="Active"
Region="SE" />
<State>
<StateInfo
Name="Florida"
Population="9488294"
AreaSquareMiles="58560"
LandAreaSquareMiles="54252"
WaterAreaSquareMiles="4308" />
<County
Name="Alachua"
Population="277120" />
<County
Name="Union"
Population="14842" />
</State>
</XML>'

EXEC sp_xml_preparedocument @idoc OUTPUT, @TestXML


At this point, @idoc is a reference to an accurate representation of the XML structure my stored proc will receive and process.

As I mentioned, the code outside of the scope of my stored proc is SQL 2000 based, but that doesn’t mean I can’t use some of the great new capabilities in 2005 in my code. Thus, here I use the OPENXML command to crack open the XML, in conjunction with the FOR XML PATH directive to build the XML structure.

-- First build the XML to give @idoc a reason to live.
EXEC sp_xml_preparedocument @idoc OUTPUT, @TestXML

SELECT
(
SELECT Number, Status, Region
FROM OPENXML(@idoc, '/XML/AccountInfo', 1) WITH (
Number int,
Status varchar(100),
Region varchar(2)
) AS StateInfo FOR XML PATH('AccountInfo'), Type
),
(
SELECT
(
SELECT Name,
Population,
AreaSquareMiles,
LandAreaSquareMiles,
WaterAreaSquareMiles
FROM OPENXML(@idoc, '/XML/StateInfo', 1) WITH (
Name varchar(100),
Population int,
AreaSquareMiles int,
LandAreaSquareMiles int,
WaterAreaSquareMiles int
) AS StateInfo FOR XML PATH('StateInfo'), Type
),

(
SELECT Name,
Population
FROM OPENXML(@idoc, '/XML/County', 1) WITH (
Name varchar(100),
Population int
) AS County FOR XML PATH('County'), Type
)
FOR XML PATH('State'), Type
)
FOR XML PATH('XML')

-- Eliminate the document.
EXEC sp_xml_removedocument @idoc


Here is the output from execution of the above code. I’m done… right??

<XML>
<AccountInfo>
<Number>123456789</Number>
<Status>Active</Status>
<Region>SE</Region>
</AccountInfo>
<State>
<StateInfo>
<Name>Florida</Name>
<Population>9488294</Population>
<AreaSquareMiles>58560</AreaSquareMiles>
<LandAreaSquareMiles>54252</LandAreaSquareMiles>
<WaterAreaSquareMiles>4308</WaterAreaSquareMiles>
</StateInfo>
<County>
<Name>Alachua</Name>
<Population>277120</Population>
</County>
<County>
<Name>Union</Name>
<Population>14842</Population>
</County>
</State>
</XML>


Hmmm, not quite. Notice that there are separate tags beneath AccountInfo, StateInfo and County. Whereas my prototype XML has the values under these tags in the form of XML attributes, they appear here as tags. Not good!

I found an article by Jerry Dixon which led me to the answer. I just needed to take each item in my SELECT statements and use AS ‘@<attributeName> to tell SQL to output the item as an attribute of the node rather than a separate element.

EXEC sp_xml_preparedocument @idoc OUTPUT, @TestXML

SELECT
(
SELECT Number AS '@Number',
Status AS '@Status',
Region AS '@Region'
FROM OPENXML(@idoc, '/XML/AccountInfo', 1) WITH (
Number int,
Status varchar(100),
Region varchar(2)
) AS StateInfo FOR XML PATH('AccountInfo'), Type
),

(
SELECT Name AS '@Name',
Population AS '@Population',
AreaSquareMiles AS '@AreaSquareMiles',
LandAreaSquareMiles AS '@LandAreaSquareMiles',
WaterAreaSquareMiles AS '@WaterAreaSquareMiles'
FROM OPENXML(@idoc, '/XML/State/StateInfo', 1) WITH (
Name varchar(100),
Population int,
AreaSquareMiles int,
LandAreaSquareMiles int,
WaterAreaSquareMiles int
) AS StateInfo FOR XML PATH('StateInfo'), Type
),

(
SELECT Name AS '@Name',
Population AS '@Population'
FROM OPENXML(@idoc, '/XML/State/County', 1) WITH (
Name varchar(100),
Population int
) AS County FOR XML PATH('County'), Type
)

FOR XML PATH('XML')

EXEC sp_xml_removedocument @idoc


Now my rebuilt representation of the original XML document, reconstructed using @idoc as a reference, is just the way I need it to be:

<XML>
<AccountInfo Number="123456789" Status="Active" Region="SE" />
<State>
<StateInfo
Name="Florida"
Population="9488294"
AreaSquareMiles="58560"
LandAreaSquareMiles="54252"
WaterAreaSquareMiles="4308" />
<County Name="Alachua" Population="277120" />
<County Name="Union" Population="14842" />
</State>
</XML>


The next requirement, how to serialize only the County values tied to each account? I can use some of the code which reconstructs the County nodes, above, and omit the AS and FOR XML PATH(‘County’), Type syntax so that a result set rather than XML is returned:

   SELECT Name, Population
FROM OPENXML(@idoc, '/XML/State/County', 1) WITH (
Name varchar(100),
Population int
)


Here’s the result set output by the SELECT:


   Name          Population

Alachua 277120
Union 14842


I defined a table variable to hold the County values, along with its own autoincrementing ID (just because it’s handy to have a unique identifier for other stuff happening in my stored proc).


DECLARE @County TABLE
(
ID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
Name varchar(100),
Population int
)


Finally, I populate the table variable with the County data I extract from the XML:


INSERT INTO @County (Name, Population)
SELECT Name, Population
FROM OPENXML(@idoc, '/XML/State/County', 1) WITH (
Name varchar(100),
Population int
)


In summary
, I’ve created code which extends the stored procedure so that it can handle multiple instances of a tag, whereas previously it was built to expect only a single instance of each tag. This enables me to properly recombobulate, if you will, the original XML passed by reference from a remote stored proc, then serialize all instances of the new tag and mess with them elsewhere in my code.


___

Special thanks to Greg Houston and his article Format My Source Code For Blogging which helped me compensate for difficulties I had with formatting my code.