Thursday, December 23, 2010

Merry Christmas, Sauron!





Friday, December 3, 2010

Roamatherapy!

Ahh, Christmas, the time for presents, tasty food, and ruminating on the memories of days when Santa Claus really existed outside mere childhood imagination.

For the cheapskate who's always wanted to dabble in aromatherapy, and because "road aromatherapy" or "road rage smells like Christmas" didn't seem catchy enough, I present ROAMATHERAPY


TRY THIS

  1. Go to your local live Christmas Tree seller. This might be your local supermarket with trees and wreaths out front, or some guy selling these out of a tent along the roadside.

  2. Grab a discarded sprig of Douglas Fir. You also could ask nicely, but I doubt the seller would mind if it's already fallen away from the tree.

  3. Using Duck™ tape, a chip clip, or a convenient crevice between the vent and the dash, secure the sprig so that hot air from the vents wafts across it.

  4. Turn on your car's heater. Akin to the principles used by various aromatherapy diffusers, the pleasant aroma of the Douglas Fir is expressed from the plant material into your car's interior.

 

If your memories of Christmas are gloomy or nonexistent, hopefully this will bring you some of the Christmas cheer I associate with the holiday that is far more enjoyable than its rampant consumerism.


 

Thursday, December 2, 2010

String Concatenation and Implicit Conversions

I needed to modify a SQL function to strip some leading zeros in order to concatenate a string. Part of this process involved dealing with pluralization of the number of cents (I'm picky that way).


SELECT
 CASE
  WHEN CAST(CAST(CONVERT(decimal(18,6), 0.30) * 100 AS float) AS varchar(10)) = 1 THEN ''
  WHEN CAST(CAST(CONVERT(decimal(18,6), 0.30) * 100 AS float) AS varchar(10)) > 1 THEN 's' 
  ELSE ''
 END
 

The idea is that if the value (0.30 representing cents) translates into a number greater than 1, the resulting concatenated sentence will read something like "The discount is 30 cents." If the value equals 1, however, it would read "The discount is 1 cent."

When the above is executed, I get an error:

 Msg 245, Level 16, State 1, Line 1
 Conversion failed when converting the varchar value '0.03' to data type int.



At first this baffled me. Data type int?? I wasn't trying to obtain an integer value, I was ultimately trying to obtain a varchar for this string I'm building.

Then it hit me, SQL is performing an implicit conversion when it is comparing the value resulting from the conversion first to decimal, then float, and finally to varchar, with 1.

Lesson learned, when attempting to compare two varchar with numeric values, make sure that if the value being tested is decimal, that the static value being used to compare it against is also decimal.

I made the following changes and now it works flawlessly.


SELECT
 CASE
  WHEN CAST(CAST(CONVERT(decimal(18,6), 0.30) * 100 AS float) AS varchar(10)) = 1.0 THEN ''
  WHEN CAST(CAST(CONVERT(decimal(18,6), 0.30) * 100 AS float) AS varchar(10)) > 1.0 THEN 's' 
  ELSE ''
 END
 





Saturday, November 27, 2010

Pretty Formatting for XML or HTML

Sometimes it's helpful to pretty up XML or HTML in order to more easily analyze it. Many tools create machine-readable XML or HTML, which is well-suited to being parsed by computers, but whose formatting can be painful for a human to wade through. 

You might think, why do humans need to be able to work with machine-readable text, anyway? Well, if you happen to be the new guy on the job and get stuck with having to debug some code that spits out some XML or HTML you've never dealt with before for some complex data transformation processing, you can see why it might be necessary, particularly if something changes between the sender and receiver and the XML, as produced, no longer does the job.

In Notepad++, one of my favorite text editors, I can utilize the TextFX plugin to take a given chunk of XML or HTML and clean it up, neatly indenting the nodes and attributes for easier examination. I paste the text into the editor and select TextFX => TextFX HTML Tidy => TiDy clean document - wrap. Finally I select Language => XML or HTML to enable syntax highlighting.

Prior to discovering Notepad++, I had discovered the freeware MoreMotion XML Editor a few years ago when I was having to dissect some XML being output by a tool whose XML output I needed to clean up. Provided the XML was well-formed, I could very quickly pretty it up by clicking XML => Pretty Format, or even more easily with a quick key combo, Shift-Ctrl-P.

BEFORE: Messy, messy XML!


AFTER: Ahhh, clean, legible, structured XML.

Unfortunately, the original download URL for MoreMotion XML Editor appears to be defunct, leading to a parked page rather than the actual file. You can download MoreMotion's more comprehensive XML application suite here, but if you just need relatively simple XML editing provided by the older (and much smaller, around 1.3 MB) freeware tool, this working download link fits the bill. The ZIP file contains the EXE, which can be copied to a convenient folder and run.

A few caveats, however. MoreMotion seems to have a few editing issues with extremely long lines of text; you may notice keypresses on such lines may take a long time to register. Also, whereas Notepad++ will do its best to deal with poorly-formed XML or HTML and log any errors it encounters, MoreMotion will not allow you to proceed until the errors are resolved, and in my experience some of these errors can be difficult to pin down.

Nevertheless, for relatively small chunks of well-formed XML or HTML, MoreMotion XML Editor makes cleaning up XML or HTML just a few steps quicker than Notepad++.


Friday, November 26, 2010

Dell Latitude E6410 Sound Problems

The time came a few months back at my workplace to replace my venerable Dell Latitude D800 with something newer, better, faster. That replacement arrived in the form of the Dell Latitude E6410.


Dell Latitude E6410


Featuring an Intel Core i5 64-bit CPU, 8 GB of RAM, and Windows 7 Pro, I expected great things, and in many respects, I got them. Performance was leaps and bounds ahead of my old D800; tasks that my D800 plodded through like building and debugging an ASP.NET / C# website or searching through thousands of files in my local source repository proceeded many times more quickly. 


Unfortunately, I was dismayed to discover that the sound provided by the onboard IDT HD92xxx device, utilized by the NVIDIA NVS3100M video hardware, stuttered frequently. Whereas my old D800 never missed a beat, literally, even through the most challenging tasks, this brand-new, supposedly state-of-the-art machine couldn't play MP3 audio without hiccuping many times throughout any given track!

Apparently this is not an isolated issue. One thread on Dell's support forums described many users' similar issues with erratic sound. Various other posts online that I found blamed the IDT hardware, such as the first review listed for this related IDT product, followed by a couple of other reviews for same which immediately reminded me of good old Baghdad Bob...

"good, and very nice"

I decided to take a reverse shotgun approach, meaning rather than pump a few satisfying rounds of buckshot into my employer's laptop out of sheer aggravation, I'd run through a short list of steps based on research I'd done into the problem so far.

To visualize the problem, I downloaded and ran the DPC Latency Checker, which represented the stuttering issue in the form of the big, ugly red lines representing relatively huge latency leading to stuttering audio.


If I were typing the way the audio stutters, it miiiight look liiiike ttttthhhis.

Dell Latitude E6410 driver download page
on Dell's support site was my first stop. I downloaded the latest available drivers and installed them, including those for audio, video, chipset, and even the touchpad. Following the experiences related by others in the Dell support forum, I also updated to the latest BIOS.


Updating the BIOS, as described in the Dell support forum thread, helped things somewhat, but the stutter was still recurring intermittently. I also completely uninstalled Dell ControlPoint System Manager, which I noticed made the stutter markedly worse when active.

I also tried using PowerMizer Manager, a free utility which lets you control and, if desired, prevent your video adapter from downshifting performance based on demand, which can cause undesired latency.

Most recently, though, after installing the latest drivers supporting the NVS 3100M from NVidia's driver download site, I've found that the stutter has improved significantly. Now, the DPC utility shows that latency is overall much improved, but still the stutter occasionally rears its ugly head.


Definitely better than before.




In summary, here are some suggestions if audio stutters on your Dell Latitude E6410:




Thursday, November 4, 2010

A Thousand Words Isn't Enough

They say that "a picture is worth a thousand words". Personally, I think the value of photos is overrated.

No photo, digital or otherwise, carries the essence of the memories in real life that photo captures. As we travel down the river of time, our motion through it is like watching a film with the afterimages remaining in our trail behind us, kind of like light painting.

These "pictures" are one with the space-time continuum, and only someone with the ability to encapsulate this and peer inside could see the entire span of all these images across all time, somewhat like looking into a peephole from outside our realm of existence.

It is truly mind-boggling to think of the data storage requirements for that kind of recording, for every moment of motion of every iota of matter all across the universe for all time. If I were some Q-like being that could freely travel across time and make such observations and manipulations as an outsider, I'd probably go back to my physical life like a universe-scale photo album or video and play it back, in all aspects.

Alas, I don't have that power, but it's not like snapping a photo will do any better than my brain's comparatively feeble but nevertheless serviceable chronicle of my life. Whether a photo, a video, or the final, frantic firings of the synapses of my brain at death, "All those moments will be lost in time... like tears in rain."







Friday, October 22, 2010

Windows 7 Haunted Command Prompt??

I encountered a weird situation on my Windows 7 x64 machine where the command prompt window couldn't be closed.

I'd logged on to my domain account, and out of (admittedly bad) habit, I tried to right-click on the command prompt in the taskbar and close it. Usually, it goes away in moments, but this time it decided to hang around, and it was impossible to remove. 

I looked in Task Manager, and although I could see the instance of the command prompt in the Applications tab, and even right-click on it and choose Go To Process, when it shifted me to the Processes tab, it selected nothing, or if I'd clicked on any other process in the list, it prompted me to end that process rather than whatever process remained which maintained this errant command prompt.

I would've liked to use a utility like PSKill to terminate the process (as described here), but if I can't find the process ID, that isn't an option.

I did notice one thing unusual in the list of processes, there were three separate instances of an executable named conhost.exe (Console Window Host). When I selected the first instance and clicked End Process, the command prompt finally closed. 

 

I also ended the other two instances, as these don't normally hang out in my process list. I'm guessing that I might've thrown a monkey wrench into whatever this command prompt had been executing when I tried to close it, causing some process it might've been waiting to close to hang out in limbo.



Friday, October 15, 2010

Hammering A Stored Procedures vs Dynamic SQL Debate

While looking for differing viewpoints on stored procedures vs dynamic SQL, I discovered an article by Frans Bouma from a few years ago, wherein he passionately criticizes elements of a post by Rob Howard.

At the time of Bouma’s post I’d had some experience with Microsoft SQL 2000, but I was at a stage where I was doing the SQL equivalent of meatball surgery on databases rather than design. My tasks mainly involved adapting existing code to suit new or revised business logic. As a result, I can relate to aspects of where each person is coming from.

Bouma and Howard both make strong cases for their arguments. Howard, clearly in favor of stored procedures, maintains that a balanced approach should be taken to designing the data access layer to optimize data interchange, and cites stored procedures as an effective tool to abstract the data and improve efficiency and performance. Bouma, a dynamic SQL convert, strongly advocates that paradigm, favoring SQL code emitted by high-level objects to creating discrete stored procedures for specific data management tasks on the fly. He also cites some deep technical details specific to Microsoft SQL which he uses to question some of Howard’s suggested implementations of stored procedures.

At face value, each person argues strongly for their viewpoint, but whether stored procedures or dynamic SQL are in and of themselves superior depends on the design and implementation of whatever system will be hitting the database. As I read each person’s arguments I got the distinct impression that each is somewhat mired in the advantages of their preferred paradigm.

The gist of this argument from years ago can be summed up in each author’s words. Howard states, “Embedded SQL script is very brittle; small changes to the database can have severe impacts on the application.” Bouma says in response to one of the comments in his blog post, “True, it requires some work to get a dynamic query generator right, but once you have one, you don't have to recode it again.”

Both these statements ring true… under a given set of circumstances. If I need code to grab values from a static lookup table, which do I use? Probably either, since unless something major changes in the design, I won’t need to touch the query frequently to modify it. However, what if I need to do something more exotic, like process a payment or mine some data based on input variables that might differ from one query to the next? Again, either methodology could be used for these purposes. It depends I think on how effectively the tools are built to deal with the data, and whether they meet the needs of the design.

Quite frankly, it seemed to me that the authors were each getting too wrapped up in their respective favorites, and arguably from two extremes of the IT spectrum. Howard’s argument seemed somewhat less technical and more geared towards an executive’s ear, with buzzwords about efficiency and performance, whereas Bouma’s deep technical knowledge describes a quintessent engineer, quite eager to implement some project with the tools he is comfortable and happy with.

A hammer is great for driving nails into wood, and for yanking nails out of wood with its secondary nail-removing end. It’s streamlined and clearly purposed for its intended use. Would it be appropriate to use a hammer to spackle a hole in the wall, or break pieces of tile into neat square shapes?

Sure, you might manage to adapt the hammer to the task, using some duct tape to secure a credit card or other stiff piece of whatever to more effectively spackle, or try to direct the blows of the hammer to snap the tile into shape without shattering it.

Would it be efficient? Absolutely not.


Tuesday, October 12, 2010

Capture the Flag FAIL

Back in the days of Jedi Academy for the PC, I enjoyed playing capture the flag (CTF) games with a passion.

One game had me in pursuit of the enemy flag carrier, a guy named Skooby. As the screencap below shows, I loosed a blaster bolt at him just as he's inches away from capturing the flag.

The result...?!

Wednesday, September 29, 2010

Why You Need TeraCopy.

It's late, and you need to copy a bunch of files from one folder to another, one drive to another. Whatever the case, you select your folder, copy it (Ctrl-C is my favorite), then navigate to the destination and paste (Ctrl-V, here). 

Then begins the waiting game. 

Windows Explorer, in all its minimal uselessness

If you're copying thousands of files in thousands of folders, and the process stops somewhere along the way, you're stuck digging through all those files, all those nested folders, trying to find out where to resume.
 
Enter TeraCopy.

TeraCopy is without a doubt one of the best utilities I have ever used. It easily enables you to copy a large number of files and folders with the ability to verify whether the copy process completed successfully or not for each and every item in the list. Furthermore, it lets you retry any failed items individually or en masse.

TeraCopy can optionally show you the entire list of files as they're being copied.

Another feature I enjoy is that TeraCopy dynamically adjusts buffers while copying to speed up the copy process, making Windows Explorer crude in comparison. It even provides you with a live view of the data transfer speed in the title bar!

The thing I like most about TeraCopy, though, is that once installed it can completely replace Windows Explorer for all your file and folder copying needs. Given that I can copy and paste a huge number of files, and then be met, say, the next morning with a detailed report showing me details about any items that failed to copy, it really does help me sleep easier.



Wolfram Alpha on Sarah Palin

Almost a year ago, I managed to confound Wolfram Alpha with a long series of consecutive divide by zero calculations.

This time, in a process known colloquially as dicking around I found a way to confound Wolfram Alpha with a secret weapon. Sarah Palin.


"Computation timed out."


The input consists of an HTML hyperlink extracted from Amazon.com's product page for Sarah Palin's semenal work. I'm certain Wolfram Alpha wasn't intended to handle such input, but it's interesting nevertheless to see how it reacts when you throw something so absurd at it.

Wolfram Alpha also cheekily notes that the ISBN of "Going Rogue" is "an odd number." Indeed!

Friday, September 24, 2010

Use AdBlock Plus in Firefox to Block Wibiya Toolbar

I'm increasingly finding Wibiya with their annoying toolbar overlay appearing on sites I visit, complete with a bouncing alert message revealing to me that I can update my status on multiple social networks at once. Wow.



Note the pastel coloring, gee, guess what that reminded me of?

I Need To Jump Into The Nearest Volcano And DIE!

On the bright side, a double down arrow lives on the far right end of the overlay, past some Olympic hurdle-style links to the Wibiya RSS feed (useless), a Share link (useless), YouTube (redundant), Blogger (redundant), and a "Powered by Wibiya" link (I... could... care... LESS). On the dark side, clicking the double down, while it does hide most of the overlay, still leaves an irritating little tab.

A quick search revealed this post which describes using the Firefox add-on Adblock Plus to prevent the Wibiya overlay from appearing. The first suggestion in the post to add just "toolbar.wibiya.com" to my AdBlock Plus configuration didn't hide the overlay for the site I was visiting, but a closer read at an update to the original post based on another visitor's comment revealed that adding the base Wibiya URL, "http://*.wibiya.com/*", effectively blocks the Wibiya overlay, including the tab, from appearing.




I'm among those who finds absolutely useless the links to the various social networking sites which Wibiya's overlay provides. It's not so much that I'm antisocial, but see, I use tabbed browsing, I can just keep whatever site huddled among my tabs and not clutter a specific page I'm trying to read with a toolbar-like overlay.

Even if the bouncy, bubbly cartoon bubble vanishes after my first visit, the rest is quite useless. To me, it's a mystery why anyone thinks this would be a popular, let alone useful way to interface with social networking. I can understand finding a given blog post or other site interesting enough to want to share on Facebook or Twitter, I grant them that, but why not use a much less obtrusive, static button for those respective services?

Anyway, kudos to Firefox and AdBlock Plus yet again for providing an easy, flexible means to disable annoying Wibiya tools which, to me, are as useful as bicycle to a fish.

Monday, September 20, 2010

Annoying Coworkers!

If your own annoying coworker story evokes sympathy in me, compels me to go to a convenient corner and huddle in a fetal position, or just makes me laugh out loud and point at you mockingly for your plight, I might send you a $20 Amazon Gift Card* in return!
 

---
In my career as a software developer, I once had an office mate (let's call him Jork) who had this habit of making the office we shared all dark and womb-like before I'd arrive in the morning, meaning he'd turn off the lights and close the door until it was just barely open.

This, in itself, was no problem. The problem was the smell. Jork was a large guy, and sweated fairly profusely. Also he used way too much laundry detergent, so it was a stifling wall of laundrysweat for me to encounter every morning. Usually when I'd arrive I would open the door and go grab some coffee just to let it air out a little.

He also had this loud, tittering laugh, like some freakin' obese goblin, whenever he'd read something funny or be watching some amusing video.

He was also flatulent like a motherfucker. Once he let one loose, turned to me and with a half-assed laugh said, "Heh heh... was that you?" What the fuck, Don Prudhomme, you can't hear yourself fucking fart??

Once when a buddy and I were in the office and Jork was still out to lunch, we happened to notice one of his desk drawers wasn't quite closed, so we took a peek inside. Hanging out in the bottom was a big bottle of Vaseline™ Intensive Care lotion.

Every few days the guy would ask me when I was leaving for the day. He would frequently work late, and he mentioned he didn't have broadband yet because his home was in the middle of bumfuck nowhere. I wish I could unimagine what I imagined after hearing that.

Wage slaves, you very likely have come across someone whom you would never choose to interact with outside the workplace.

Tell me your story! 


*RULES

  1. Be creative, but please, be original. Make sure you're sharing your own tales of coworker woe.
  2. This is NOT a contest, and a recipient of a gift card is NOT guaranteed to be chosen. I'm simply offering to brighten the day of one or more people who are willing to share their story.

  3. By participating, you agree not to sue me for any reason whatsoever. This agreement remains in effect forever and ever, so help you God, Allah, FSM, Satan, or whomever / whatever you believe in.

Thursday, September 16, 2010

User Stupidity Tolerance



Here are 3 tips I'd suggest to enable you to save your MP3 player if it falls into water. 
  1. Turn off the power and disconnect the battery as soon as possible after immersion. The less water gets inside the circuitry of the device, the better!

  2. Let the device air out in a warm, dry environment for at least 24 hours before trying to use it again. A hot, dry attic or an area with a steady flow of warm, dry air helps speed the process.

  3. Find a belt pouch or ideally a waterproof MP3 player pouch and use it anytime you plan on being near a big body of water. If you manage to save your old player, it'll thank you for this, but if it dies, safeguard your replacement.


Here are the gory details. A few years back, I purchased a Sansa e250 MP3 player and later a pair of Blockade Noise-Isolating Earbuds, both via WOOT

I haven't at all been into the hype surrounding iPod, Zune, nor any other big-name players, I just wanted an MP3 player that was very portable, could store at least a few gigs of my music, and had good battery life. For these the Sansa definitely delivers.

Now the model is discontinued, it no longer even appears on the Sansa Music Players and Accessories page. Yet, despite it fading into the distance with countless other technology products into the proverbial sunset, I must sing its praises for one peculiar reason: user stupidity tolerance.

My wife and I went fishing this past week at Lake Panasoffkee. Beer and fishing certainly go well together, and as my bait lay in wait for some hungry fish, I sipped my third beer on an empty stomach, and pushed play on my Sansa and sat lazily outside, enjoying a cool morning breeze coming in from across the lake.

Ideally, my yanking on the earbud cord would've had the MP3 player leap out of my pocket, do a loop in midair, then land neatly in my palm with the controls ready for my commands. Beer, unfortunately, tends to knock the likelihood of an ideal situation down a few orders of magnitude.

Instead of landing in my outstretched palm, the tug of the cord caused the player to somersault up, over my hand, and like some hapless mountaineer getting a handhold at the worst possible moment, the plug popped out of the socket, and the player splashed down into the water. As I looked into the depths, I could see the bright blue LED of the volume dial glowing happily from beneath about two feet of tannin-stained lake water.  

As beer would have it, my judgment was impaired, so I wasted precious seconds dumbfounded at what had just happened. I lay down and tried in vain to reach for it with my hand, too far. I tried grabbing a bucket and getting the player up and in, and nearly lost my breath and the bucket in the process, water plus sand plus MP3 player is a lot of weight at that awkward angle. 

Finally I threw off shoes and socks and jumped in, grabbing the player. I did what I could to shake excess water off and out, and hit the power button. I ran inside our room, found a knife, and removed the screws fastening the back cover. 



A few shakes revealed that some of the lake water had indeed infiltrated the case, but surprisingly not a lot. I guess the designers anticipated it needed to at least be somewhat water resistant in case someone was using this MP3 player while jogging or otherwise sweating profusely. So much the better!

I quickly disconnected the battery and rinsed the inside of the case with tap water (tap water like lake water has electrolytes swimming around that might short out the electronics, but since I had no distilled water handy, I figured with the power off it would be better than nothing).

I decided to let the player air out near the space behind the fridge, since hot air is almost constantly being pumped out I figured it would help dry out the circuitry. I guess it did, because now, the player is back to its old self.





There's a good reason why I've featured the song "Amazing" by SEAL on the resurrected Sansa's playlist, I'm amazed it survived its brief underwater encounter, and thankful that it no longer swims with the fishes.


Saturday, September 11, 2010

Headache Help

I don't typically suffer from headaches, but today I've got one that I liken to an icepick through the eyeballs. Here are some remedies for headaches that work for me, which you may find helpful, and don't require drugs.



  • Headache nerve pinch. Using the thumb and index finger of one hand, grasp the webbing between the thumb and index finger of the other until you feel pain, and hold it with firm pressure for up to one minute. This will distract your brain pain, and hopefully take your mind off the headache.

  • Juice it. Using a Magic Bullet™ or at the very least, a blender, create some juice with some fresh carrots and a hunk of fresh ginger root. Ginger is notoriously good at laying the smackdown on a headache, but by itself it's a bit difficult to stomach. Blending it with carrot juice makes for a sweet, tasty headche remedy.

  • Go outside. If you've been in a stuffy office all day, your headache may be a hint from your body that you need a break. I find that walking outside and getting some fresh air and sunlight can help combat a headache.



Pharmaceutical companies would have you believe that their drugs are the ultimate solution to headaches, but there are at least a few reliable home remedies that can relieve headaches without popping pills. Hopefully these will help you as they've helped me.

Thursday, September 9, 2010

Adobe Flash Player Download

-= UPDATE =-


Nice try, Adobe. I notice that now the links depicted in the image below now simply refer you back to the main install page for Flash and other players.

Click below to obtain the installers for Flash without the Adobe Download Manager.






Adobe also provides links to previous major releases of the Flash player, and a link to a Flash uninstaller for those times when it needs to be manually removed.




We can't live without Flash, now can we??








Friday, July 16, 2010

Optimizing SQL Views Profit++, Fun--

While working feverishly towards meeting a looming deadline on some SQL code, a problem arose. A particular UI that relies on a particular stored proc to perform a particular task was bombing. 

I brought up SQL Profiler and retraced the user's steps, and found the culprit, a convoluted view I was joining to as a step within the update seemed to be taking way too long to retrieve data.

The view started out relatively simple, a SELECT over several busy tables joined together along with a few scalar function calls and a very few subqueries nestled within some CASE statements. It evolved, thanks to lack of time and impatience and poor choices on my part, into a bit of a behemoth; it took roughly 1:30 to return the full result set. This didn't seem like a big deal at the time, however, because I planned to use it to pluck out specific entries, for this purpose it returned results in less than a second or two, which was acceptable.

Using it in a join though was a relatively new, hastily chosen design decision, and apparently it was proving a very poor choice since it was causing the UI to time out. I began by optimizing the view, minimizing the interaction with the busy tables as much as possible, avoiding subqueries unless absolutely necessary, and creating some new scalar functions to replace previously funky logic. No joy, however, as this only shaved around 10 seconds off the runtime for a SELECT, too little, I thought.

So began the quest to create a table-value function instead, full of optimizations like stuffing frequently used values into variables and creating a subset of the main tables in a table variable (impossible from within a view) and minimizing the use of scalar functions and even resorting to applying the WITH (NOLOCK) and eliminating string searches wherever possible...

It turns out, however, that the entire two paragraphs of chronicled woe were completely unnecessary. Here's a SELECT from within the stored proc which joins with the aforementioned view, notice anything odd?
SELECT TOP 1 @Fruit = 
        
  CASE 
      WHEN v.Operation IN ('APPLE', 'BANANA', 'GRAPE') THEN v.Operation
      ELSE NULL
  END

FROM dbo.ViewOfPain v
WHERE v.ID = ID 
ORDER BY v.InputDate DESC
  

Let's see, looks like I'm just trying a simple SELECT from the view with a CASE statement, checking the ID against the ID, yeah, that looks fi-- O SHI

Notice the missing '@' sign before the ID in the where clause??! I did, after spending a few hours writing a table function that I turned out not to need. The problem wasn't with the view, but with this bit of code in the stored proc, it was doing the equivalent of a SELECT on the entire view plus a bit more overhead to assign a value to the @Fruit variable. I ran this statement by itself in query analyzer, and indeed, it took well over 1:30 to execute!

Below is the code as it should've been, which returns almost instantaneously.
SELECT TOP 1 @Fruit = 
        
  CASE 
      WHEN v.Operation IN ('APPLE', 'BANANA', 'GRAPE') THEN v.Operation
      ELSE NULL
  END

FROM dbo.ViewOfPain v
WHERE v.ID = @ID
ORDER BY v.InputDate DESC


I'd spent hours optimizing and then finally creating a new table function to replace a view that turned out not to be the culprit. If I'd spot-checked my syntax in the stored proc, it's likely I could've picked out this omission of the '@' much sooner, but I was so tired and far gone into troubleshooting that I was getting increasingly desperate. 

The moral of my story is, take a break, unhook yourself from the problem, and review it again later with a fresh mind.

Wednesday, June 16, 2010

Long Live the Classic Start Menu!

At work, I have finally received a brand-spanking new Dell Latitude E6410 laptop, complete with Windows 7 Pro.

I'm certainly loving the speed so far. As you might expect, stuff that seemed to take ages with XP goes blazingly fast under 7.
 

But, what's this?? Where's my beloved CLASSIC START MENU???

Apparently, Microsoft believes that since time marches on, all Windows users shall march in cadence with it. Some fanboys, too, wonder why all us holdouts don't simply drop the crude old Classic start menu altogether.

Absurd!

While I'm certainly happy for those who've enjoyed the new start menu, I for one would much rather keep the venerable Classic menu. I'm accustomed to it, I'm comfortable with it, and frankly, I don't really see a real need to switch.

Classic
works for me.

Along those lines, I've found ClassicShell. The creators of this add-on compatible with Windows 7 allows users to once again have their Classic start menu available.

Please, don't get me wrong, I'm certainly all for innovation and efficiency. However, is it truly more efficient to force users to become accustomed to a new start menu, and eliminate one that a significant number of users have been comfortable with for years? 




Isn't it more innovative to allow users to maintain their own customizations and preferences, despite changes in the underlying operating system? Personally, I'd like to keep my grubby paws on the Classic start menu as long as I can, because frankly I don't care to explore the new start menu which Microsoft slaps upon Windows 7 users.

In my humble opinion
, Microsoft would do well to ensure that their underlying OS works like a charm, and leave users to enjoy the preferences that they have come to enjoy, nay, expect, from their products.

Saturday, May 15, 2010

Transferring a Windows Application to Another Computer

Let's say you want to migrate a Windows application from one PC to another. Not the entire hard drive, not your MP3 collection, but just one application.

Maybe for whatever reason you like the application, a lot, and don't want to fork over money for another license, nor do you want to compromise and purchase a replacement that does what you need it to, but makes you long for some quirky goodness your old app offers.

Utilities like Laplink PCMover and Move Me let you migrate applications, settings, files and all from one PC directly (via USB cable) or indirectly (via external hard drive) to another. There's also the excellent Acronis True Image, which enables you to clone your hard drive and copy every bit of data. Another possibility is a tool like the freeware Application Mover, which lets you move an installed application along with its files and registry settings to a new path on the same hard drive, or a new hard drive entirely.

Of these utilities, arguably the first few do the best, since they not only a working application, but most if not all data in the source and migrates it en masse to the target. If you wish to only transport one app, however, you're practically out of luck.

You could try simply copying the application folder, updating registry settings and all that manually, and it might work, but it's rather hit-or-miss. What if some crucial file the app needs for a very specific task wasn't copied over? What if a very old app has some stupid bug that didn't emerge when it lived in an old 8.3 naming system, but does once you try to stick it into a folder under "C:\Program Files"?

Thankfully, a solution exists, in the form of a utility included in the Symantec Ghost Solution Suite called Client Migration. As this article mentions, one of its features includes the ability to create installation packages for installed applications.
  "Client Migration 3.0 by Symantec migrates data and application settings to a new computer. It enables you to
  create application packages for the purpose of updating or installing applications on the new computer..."



Being able to simply migrate a single application can be handy by itself, but the ability to create an installation package is even better, for several reasons.
  1. Portability. If you enjoy a particular application, and don't want to give up its usefulness, you can just install it on new hardware and enjoy.

  2. Licensing. Rather than being stuck with buying another license for a program you already bought, you can simply move it to a new system.

  3. Comfort. You love PhotoShop, but in the far future it becomes abandonware and is eclipsed by DodoShop, yet you just loved PhotoShop's way of doing things. Migration capability enables you the comfort of extending the usability of this one app that may no longer be available for purchase, let alone for download off some random site.

There can, as with everything in life, be a few pitfalls. 
  • If the app you're migrating has any low-level conversations with your hardware, these peculiarities might translate with difficulty, if at all, to a new system with updated hardware and firmware. The app itself might not function, or worse, might cause your system to crash.

  • If the operating system evolves to the extent that certain OS-specific resources the application depends on to do it's thing are no longer present in the current OS, you might need to enable any compatibility features (e.g. Windows ability to run applications in compatibility mode), or use something like Microsoft Virtual PC to emulate the desired operating system environment.

Clearly, there are advantages and disadvantages in preserving a very useful old application. At least the Symantec product described above gives you the valuable option of being able to breathe new life into an old application despite upgrades to your hardware and operating system.

Tuesday, April 27, 2010

Create CheckBox Controls Inside A GroupBox Programmatically

I'm working on a WinForms app to interface with SQL server to grab parameters and other info for various objects. It uses a custom control I discovered on CodeProject to create a collapsible GroupBox control.

Say that I want to create a bunch of new controls based on the output of some SQL function or stored procedure. For example, the system stored procedure sp_databases returns a list of all databases on a given SQL server. 

In my collapsible GroupBox, I might want to create a CheckBox control for each database so that I can let the user choose which database to work on in the current session of the application.

To facilitate this, some pseudocode might be helpful:
  • Instantiate a new CheckBox object.
  • Does my GroupBox contain any other CheckBoxes?
    • NO: Set the CheckBox location so that it appears in the upper-left corner of the GroupBox
    • YES: Grab the X and Y coordinates of the last CheckBox contained in the GroupBox
  • Would the width of an additional CheckBox exceed that of the GroupBox?
    • YES: Set the new CheckBox X coordinate so that it aligns with the first CheckBox in the GroupBox, then bump the Y coordinate down by a set value.
    • NO: Place the new CheckBox to the right of the previous one.
  • Set the Text property of the newly-added CheckBox to a given input string value.

Along these lines, I created the method below, which takes a string as input representing the Text property of the newly-created CheckBox.

       
/// <summary>
        /// Create a new CheckBox control within a collapsible GroupBox, assigning input sName
        /// to the Text property.
        /// </summary>
        /// <param name="sName"></param>
        /// <returns></returns>
        private CheckBox CreateNewCheckBox(string sName)
        {
            int iExistingCheckBoxX = 0;
            int iExistingCheckBoxY = 0;

            int iIncrementX = 100;
            int iIncrementY = 20;

            CheckBox cbNew = new CheckBox();

            cbNew.Width = iIncrementX;

            if (cgbDatabases.Controls.Count == 0)
            {
                cbNew.Location = new Point(cgbDatabases.Location.X + 15, cgbDatabases.Location.Y - 50);
            }
            else
            {
                // Existing checkboxes, so get the Location of the last one.
                iExistingCheckBoxX = cgbDatabases.Controls[cgbDatabases.Controls.Count - 1].Location.X;
                iExistingCheckBoxY = cgbDatabases.Controls[cgbDatabases.Controls.Count - 1].Location.Y;

                // If the new control would overshoot the end of the container, bump it down.
                if ((iExistingCheckBoxX + iIncrementX) + cbNew.Width >= cgbDatabases.Width)
                {
                    iExistingCheckBoxX = cgbDatabases.Location.X + 15;
                    iExistingCheckBoxY = iExistingCheckBoxY + iIncrementY;

                    cbNew.Location = new Point(iExistingCheckBoxX, iExistingCheckBoxY);
                }
                else
                {
                    cbNew.Location = new Point(iExistingCheckBoxX + iIncrementX, iExistingCheckBoxY);
                }
            }

            // Set the Text property according to the input.
            cbNew.Text = sName;

            return cbNew;
        }


In the constructor of my WinForm app, as a test I used the collapsible GroupBox control's Add method in conjunction with the new method to insert a bunch of child CheckBox controls into parent GroupBox. 

        public frmMain()
        {
            InitializeComponent();

            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox1"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox2"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox3"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("CheckBox4"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox5"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox6"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox7"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox8"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox9"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox10"));
            cgbDatabases.Controls.Add(CreateNewCheckBox("Checkbox11"));
        }


The results are as I expect:




Advantages of this method include the ability to tweak the variables within the CreateNewCheckBox method to determine what the starting X and Y coordinates will be based on the Location of the GroupBox; if I move the GroupBox somewhere else in my form's design view, the code won't care, it will simply churn out the CheckBox objects based on the parent control's current position at runtime. Also, it prevents new objects from being created outside the visible width of the GroupBox.

Shortcomings include a lack of checking the height of the GroupBox; if a zillion controls are created within it, there's currently no logic to prevent them from being placed in the nonvisible area of the control. Also, I'm currently not analyzing the incoming string parameter to see whether I want to constrain the resulting object to a uniform height or width, which means a CheckBox with a huge label likely will not display its Text value correctly.

Speaking of dimensions, the method is currently not "smart" enough to roll with the punches in terms of variations in height or width of the resulting controls; it doesn't offer an easy way to make the child objects conform to specific patterns (e.g. the objects appear one after the next from left to right, not up to down or diagonally or some other order). These would need to be tweaked and tested manually to ensure the object labels remain intact, and the objects themselves remain visible and usable. A more elegant solution would be to have the method scrutinize the control to be created and its attributes and compensate.

Baby steps, but nonetheless I found this a helpful exercise in creating CheckBox controls at will within a parent GroupBox, and already am seeing ways in which I can improve this implementation. I wish to thank Jordan Hammond, creator of the CollapsibleGroupBox control from the article I cited above, and also Manoli's code formatter, which was used here to make the C# excerpts presentable.