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.

Tuesday, March 23, 2010

Monday, March 8, 2010

Faith is Flawed

H. L. Mencken wrote, "It is not materialism that is the chief curse of the world, as pastors teach, but idealism. Men get into trouble by taking their visions and hallucinations too seriously."

When 11-year-old Madeline Neumann began suffering acutely from runaway ketoacidosis as a result of untreated diabetes, her parents, devout followers of the Bible, did what they thought was right. They prayed. Ultimately, Madeline died a painful, miserable death. This poor child suffered for over thirty days with extreme thirst, nausea, and weakness, all caused by an easily treatable condition.

David Koresh, the late leader of the Branch Davidians, claimed he not only possessed the gift of prophecy, but also claimed to have a vision that he was Cyrus, a reincarnation of the first Zoroastrian Persian emperor and founder of the Persian Empire. Ultimately Koresh and many of his followers perished in flame following the tragic Waco siege, paying the ultimate price for their deep commitment to their beliefs.

These people all share a common thread, they believed in what they were doing. The Neumann parents, fervent believers in the Scripture, convinced themselves that prayer would bring their daughter free and clear of suffering, and indeed following Madeline's death they dejectedly claimed that it was their own lack of faith which failed to bring their daughter back from the brink. Koresh, a fanatical believer in prophecy and his place as a new messiah appointed by God, led himself and dozens of devoted followers willingly into the sights of brutally effective government firepower.

William James, the pioneering psychologist and philosopher, defined true beliefs as those that prove useful to the believer. Certainly, believing that prayer will heal and that prophecy is truth served the people described above who embraced these beliefs. It gave them a sense of power, a sense of purpose, reassurance that they could apply the force of faith to their respective situations and prevail against evil.

The problem, however, is that beliefs do not counteract brutal reality. I don't claim knowledge of a "soul" or any intangible, nebulous definition of human existence that persists beyond the physical realm, but at the same time I do not discount this possibility.

I simply refuse to define and decide, within the confines of my merely human mind, that spectacularly serendipitous events like an ailing child healing or a band of followers providing the boon of their fealty to me are realistic expectations of fervent belief in a thing which, for all intents and purposes, is a product of my own imagination.

God exists in countless forms to countless people. Mencken, in his Treatise on the Gods, suggested that mysticism is the purest form of religion because it demands no tithe, no steeple, no trappings of religious doctrine, but merely an intimate, personal relationship of devotion and contemplation. This seems to me a more sensible system of belief than almost any form of organized religion in existence today, since God is not presented like some new car, a flagship ride to salvation, by bands of Its followers. Rather, God makes Itself known to the believer in a manner It deems fit, without outside influence and without mindlessly embracing scriptural doctrine maintained by human beings.

The aforementioned danger, of course, exists in the faith of mystic as well as maniac believer in religion, that they will be compelled to transform visions and compulsions into reality, in their mind purely for their God, but in essence either good or evil depending upon the impact to themselves or others.

Perhaps, in the end, it is safer and wiser to simply adhere to the New Commandment of Jesus Christ, "A new commandment I give unto you, that you love one another." Love is simple and true and in its purest forms leads to happiness for all involved. Better yet, love among creatures with intelligence, like dogs, is reciprocated in ways that are clear and meaningful, though they, like faith, are ultimately intangible.

___

Constructive commentary is always welcome!