Sunday, December 13, 2009

Approximate string matching using Longest Common Substrings

Approximate string matching is the process of determining that two strings, while not identical, share enough characteristics that the likelihood of them referring to each other is high. For example, in my haste to write this post, I typed “likelyhood” which the spell checker quickly identified as not being a word in the dictionary but probably referred to the word “likelihood.”  (Thank you Mr. Spellchecker!)

There are many algorithms that can be used to perform approximate string matching. Levenshtein Distance being an example of one of them.  While reviewing some old projects, I came across the implementation of another: Longest Common Substrings.

The method shown below finds and remove the longest common substring from the two strings being compared. It continues until the length falls below a specified threshold. A measure of equality is determined by taking the sum of the characters removed and dividing it by the length of the smaller string. You end up with a value from 0.0 (completely different or smaller than the threshold) to 1.0 (equal).

Here’s the code.

`using System;using System.Text; public partial class StringFunctions{    public static Double ApproximateStringMatchingUsingLCS(string str1, string str2, int requiredMinLength)    {         if (string.IsNullOrEmpty(str1) || string.IsNullOrEmpty(str2)) return 0;         if (str1 == str2) return 1.0;         int totalMatchedCharacters = 0;        string foundSubstring;        string targetString1 = str1.ToLowerInvariant();        string targetString2 = str2.ToLowerInvariant();        while((foundSubstring = LongestCommonSubstring(targetString1, targetString2)).Length >= requiredMinLength)        {            totalMatchedCharacters += foundSubstring.Length;             targetString1 = RemoveFirstOccurence(targetString1, foundSubstring);            targetString2 = RemoveFirstOccurence(targetString2, foundSubstring);        }         return (1.0*totalMatchedCharacters/Math.Min(str1.Length, str2.Length));    }     /// <summary>    /// Removes the first occurance of a substring    /// </summary>    /// <param name="targetString">The string to search</param>    /// <param name="stringToRemove">The string to search for</param>    /// <returns>The string to search with the first occurance of the substring removed.</returns>    public static string RemoveFirstOccurence(string targetString, string stringToRemove)    {        if (String.IsNullOrEmpty(targetString))        {            throw new ArgumentNullException("targetString", "A non-null value must be supplied for 'targetString'");        }         if (String.IsNullOrEmpty(stringToRemove))        {            throw new ArgumentNullException("stringToRemove", "A non-null value must be supplied for 'stringToRemove'");        }         int start = targetString.IndexOf(stringToRemove);        return -1 == start ? targetString : targetString.Remove(start, stringToRemove.Length);    }     /// <summary>    /// Finds the longest substring that two strings have in common    /// </summary>    /// <param name="str1">The first string to search.</param>    /// <param name="str2">The second string to search</param>    /// <returns>The longest substring that the two strings have in common.</returns>    private static string LongestCommonSubstring(string str1, string str2)    {        if (String.IsNullOrEmpty(str1) || String.IsNullOrEmpty(str2))            return string.Empty;         int[,] num = new int[str1.Length, str2.Length];        int maxlen = 0;        int lastSubstringStartingPosition = 0;        StringBuilder sequenceBuilder = new StringBuilder();         for (int i = 0; i < str1.Length; i++)        {            for (int j = 0; j < str2.Length; j++)            {                if (str1[i] != str2[j])                    num[i, j] = 0;                else                {                    if ((i == 0) || (j == 0))                        num[i, j] = 1;                    else                        num[i, j] = 1 + num[i - 1, j - 1];                     if (num[i, j] > maxlen)                    {                        maxlen = num[i, j];                        int thisSubstringStartingPosition = i - num[i, j] + 1;                        if (lastSubstringStartingPosition == thisSubstringStartingPosition)                        {                            //if the current LCS is the same as the last time this block ran                            sequenceBuilder.Append(str1[i]);                        }                        else                         {                            //this block resets the string builder if a different LCS is found                            lastSubstringStartingPosition = thisSubstringStartingPosition;                                                        // reset the string builder                            sequenceBuilder.Remove(0, sequenceBuilder.Length);                            sequenceBuilder.Append(str1.Substring(lastSubstringStartingPosition, (i + 1) - lastSubstringStartingPosition));                        }                    }                }            }        }        return sequenceBuilder.ToString();    }    };`

If you’re interested, here’s a (rather old) whitepaper that compares the performance of some of the approximate string matching algorithms: Real World Performance of Approximate String Comparators for use in Patient Matching

Monday, December 7, 2009

TSQL Gem

This works:

Looking at the BOL, the FROM clause is optional.

I guess I just never paid attention

Tuesday, December 1, 2009

Generate a sequence of numbers in TSQL

Sometimes you need a quick way to generate a sequence of numbers. The recursive query functionality that was introduced in SQL Server 2005 makes this really easy.

`WITH Numbers (val) AS (	SELECT 1 as val	UNION ALL	SELECT 1 + val FROM Numbers WHERE val < 100)`

Monday, November 23, 2009

Configuration Helpers

This post is mainly so I’ll be able to find this code later.

I’ve been on multiple projects that make heavy use of configuration and I always end up writing these helpers similar to the ones listed below. These are general conversion routines that take a String and try to cast it to a specified value. In this version, I’ve included a special case when casting to Boolean. A “1” is considered TRUE and “0” FALSE.

`public bool TryCastFromStringTo<T>(string s, out T value) {	value = default(T); 	if (typeof(T) == typeof(bool)) 	{		if (s.Trim() == "1") 		{			value = ((T)(object)true); 			return true; 		}		if (s.Trim() == "0") 		{			value = ((T)(object)false); 			return true; 		}	}		TypeConverter converter = TypeDescriptor.GetConverter(typeof(T)); 	object convertedValue; 	try 	{		convertedValue = converter.ConvertFromString(s); 	}	catch (Exception e) 	{		if (e is NotSupportedException 			|| e is InvalidCastException || e is FormatException) 		{		return false; 		}		if (null != e.InnerException && e.InnerException is FormatException) 		{		return false; 		}		throw; 	}	value = (T) convertedValue; 	return true; }public T SafelyCastFromStringTo<T>(string value, T defaultValue) {	if (null == value) return defaultValue; 	T convertedValue; 	if (this.TryCastFromStringTo(value, out convertedValue)) 	{		return convertedValue; 	}	return defaultValue; }`

Wednesday, November 11, 2009

SQL Server XML - Replacing the value of an attribute with a column from the same row

This will hopefully save someone the 45 minutes that it took me to figure it out. I wanted to replace the value of an attribute within an XML column with the value of a column on the same row.

UPDATE myTable
SET xmlColumn.modify('replace value of (/x/y/@a)[1] with sql:column("columnName")')
WHERE ...

When I tried wrapping the call to sql:column with braces (ex. {sql:column("columnName")}, I received error 2224 - An expression was expected.

When I tried enclosing the whole thing in double-quotes (ex. "sql:column("columnName")", I received error 2370 - No more tokens expected at the end of the XQuery expression. Found 'columnName'

Tuesday, November 10, 2009

Home Server, Part 3 – Creating a VM for Windows Home Server

This is the third post of a series where I discuss the steps I went through to stand up a server for my home network

One of my primary goals was to stand up a Windows Home Server (WHS). This post made it clear that it was possible. Now, was it practical and would it perform on Hyper-V Server? Both valid question that I would eventually find the answer to.

I’m not going to go into the details of installing Windows Home Server. There are many articles on the web that cover that. I’m really going to concentrate on the Hyper-V aspect of the install. With that in mind, I will say that I found this WHS whitepaper helpful.

I created the VHD first. Originally I wanted to create a small drive for the system and a larger one for the data. Then I saw a couple of articles that suggested that you use your largest HD as the primary. Something about the way that WHS allocates space? I should have kept the URL of the article. (Please let me know if you find an article that explains this – thanks.). To make things simple, I created a single 500GB fixed disk. Why a fixed disk? According to this whitepaper, fixed drives offer better performance. Also, one of my main goal for WHS is to have it backup all the computers in the house. So I went big.

Next I created the VM. I walked through the wizard.  Windows Home Server doesn’t require a lot of memory. I’ve seen some articles that say you can get by with as little as 512M. I allocated 1GB RAM to the VM. I also allocated one processor. I ended up with two IDE controllers and one SCSI controller. I assigned the 500GB VHD to the SCSI controller because it performs better than the IDE controllers (see the performance whitepaper). I also configured the DVD drive to reference the physical DVD, which contained the Windows Home Server Install DVD.

With that completed, I started the VM which started the WHS install.

After a couple of minutes, I was greeted with the message “Hard disk capable of hosting Windows Home Server was not found. Would you like to load additional storage drivers?” What the hell? How could the install not find the drive? I had no idea what driver to load. I wasn’t sure what the problem was.

I started searching the Internet for clues (Where would we be today without the Internet?) . I hit one article that discussed this very issue. According to the article, the issue is that the Windows Home Server install does not have the drivers for a SCSI drive but you can install them from a virtual floppy drive image called SCSI Shunt Driver.vfd. Unfortunately I couldn’t find it. It wasn’t on the Hyper-V Server host anywhere.

After more searching I bumped into this article. It turns out that Hyper-V Server 2008 R2 cannot boot a guest OS from a SCSI drive. The guest OS boot drive must be an IDE drive. I changed the configuration to move the VHD to the first IDE controller and restarted the VM.

The install proceeded without any more problems.

There was only one more step once the install had completed. I had to install Hyper-V Integration Services. Integration Services is installed on the guest OS and provides an interface to a set of services offered by Hyper-V Server. To install Integration Services, I connected to the VM from the Hyper-V Manager.

This brought up a window that is very similar to Remote Desktop.

After logging in, I was greeted with a very nice warning message of the damage that I could do by managing WHS this way. In this case, it’s safe to close the instance of Internet Explorer to expose the desktop. From the Virtual Machine Connection’s Action menu I selected Insert Integration Services Setup Disk. This loaded the virtual DVD drive with a CD image. Autoplay didn’t kick in so I had to go manually navigate to the DVD and find the setup program. In this case, I needed the version that was in the Support\x86 folder.

Integration with the guest is much smoother once Integrations Services is installed.

With the server install, I followed the the remainder of the Getting Started whitepaper to complete the install. I now have a Window Home Server running very smoothly and it is successfully backing up the other machines in the house. The next thing that I want to do is see how well it will stream media to the PS3.

Friday, November 6, 2009

Home Server, Part 2 – Installing Hyper-V Server 2008 R2

This post is one of a series where I discuss the steps I went through to stand up a server for my home network

I’m going to be honest: I’ve a huge fan of VMWare Workstation. I tried Microsoft’s Virtual PC when it first came out but the performance was really lacking. A co-worker convinced me to try VMWare and I’ve been loyal since.

So I bet you’re wondering why the title contains Hyper-V Server and not something like VMWare Server or ESXi. I’ve been intrigued by Hyper-V since Microsoft announced that the Azure Fabric is based on it. This was an opportunity to give it a try, especially with the R2 release.

Hyper-V Server 2008 R2 is a free download from Microsoft. It is installed on the bare iron and provides a hypervisor for running virtualized servers. Pull down the configuration guide also. It’s not for R2 but I found it to be very helpful.

I’m going to tell you now that installing Hyper-V Server 2008 R2 was dead simple. I burned the iso to a DVD, popped it into the drive and bounced the machine. Soon the setup was running. After a couple of restarts I was logged in and greeted with the configuration tool – Server Configuration.

Using the information in the configuration guide, I setup the server to be in a Workgroup and enabled all of the remote management options. This is important since you will mainly be managing Hyper-V remotely. Also, enable Remote Desktop (RDP), you’re going to need it.

Hard Drives

When I installed Hyper-V Server 2008 R2, it formatted the partition that I installed it to. It did nothing with the other drives in the machine. I had to use the DISKPART command-line utility to bring the other hard drive online.

Hyper-V Server 2008 R2 is supposed to be managed remotely. To do that I installed the Hyper-V Manager from the Remote Server Administration Toolkit (RSAT). Unfortunately there are different deployment packages for Vista and Windows 7.

After I installed the toolkit, I had to use the Turn Windows Features On or Off option in the Control Panel to enable the Hyper-V Manager.

Things were going really smoothly at this point. By now the hardest thing that I had to do was locate the RSAT deployment package for Windows 7. But what kind of project goes smoothly? Not this one. Keep reading.

The “Fun” Starts

The first VM that I want to create will be hosting Windows Home Server so I fired up the Hyper-V Manager to create the VM. I was greeted with the error message “You do not have the required permission to complete this task.  Contact the administrator of the authorization policy for the computer <computer name>.”  I started doing what all computer professionals do – searching the web.

I came across John Howard’s blog and specifically this post. John is a PM on the Hyper-V team at Microsoft. This post is part 1 in a series that addresses this issue. He’s even created a tool, HVRemote, to simplify the steps.

As I did more reading, it seems that R2 now takes care of a lot of the configuration that John lists in that post. This would be the Configure Remote Management option in the Server Configuration tool (sconfig).  Unfortunately I still couldn’t connect.

I started looking at the HVRemote utility again. There’s a 10-second Guide on the site that addresses a variety of configurations. Mine is the first one: Client and Server both workgroup. Using the Server Configuration tool, I created an account on the Hyper-V server with the same name and password as my account on my laptop. Like magic the permission error disappeared and I was able to connect to the server.

Ha! Home free!”  I started to build the VHDs for the new VM.

Until I was greeted by another error message: “Cannot connect to the RPC service on computer <computer name>. Make sure your RPC service is running.”

This had me stumped for a while. I used the Server Configuration utility to install the most recent updates and bounced the server. I was able to connect again – for about 10 minutes. Then the RPC service error popped up again.

I stopped the firewall on my client to see if it was the issue. Nope. Not it. I pinged my laptop from the server and the error went away – for about 10 minutes. That was interesting. I was actually able to do some of the configuration, like creating a Virtual Network and one of the VHDs. All I had to do was periodically ping my laptop from the server.

Obviously this was not an acceptable solution.

While searching I came across this thread in the Technet forums. The poster had solved a problem similar to mine by doing the following:

From a command window on the server, issue the following command:

netsh advfirewall set allprofiles state off

This disables the firewall on the server. While I really don’t want the firewall disabled, I ran the command anyway.

On the client:

1. run dcomcnfg
2. Under Component Services, navigate down to My Computer
3. Bring up the Property Dialog for My Computer and select the COM Security tab
4. Click the Edit Limits in the Access Permissions section
5. Enable Remote Access for Anonymous Logon

Doing these two steps did seem to correct the RPC problem. I’ve not seen it since. I’ve also gone back and enabled the firewall on the server.

Update – I usually sit on a post for a day and re-read it prior to posting. I came back to the Hyper-V Manager after 24 hours and was meet by the “RPC service” error message. I stopped the firewall on the server and I’m now able to connect to the server as expected. I’m not happy about having to run without a firewall. I’m going to start a thread in the forums to find out the exact firewall configuration.

After getting all of this taken care of, I was able to create the two VHDs that I need for my Windows Home Server VM. That will be the topic for the next post in this series.

Next: Installing Windows Home Server

Home Server, Part 1 - Hardware

So begins another saga of large projects. This time, though, I’m in the domain of computers – something that I know a little more about.

I’ve wanted a server for the house for a while now. I periodically scan the Dell site looking for a good deal. A couple of weeks ago I stumbled into the PowerEdge T110 Tower Server. I picked one up with a quad-core 2.4 GHz proc, 2GB RAM (single DIMM) and one 160GB SATA hard drive. I typically purchase the minimum amount of RAM and hard drive that I can get. I’ve found that I can purchase them much cheaper after-market.

What I didn’t realize was that this machine used a Dual-Channel architecture and, as I understand it, operates optimally with matched-pairs of memory modules. The invoice from Dell didn’t say much about the configuration of the DIMM that I purchased, but between the user’s guide for the machine (yes, I read the manual) and Crucial,  I was able to identify the configuration that I needed.

With that information, it was just a matter of checking all the usual online sites. I ended up a Newegg.com (I know – shocking isn’t it!). Newegg had a really good deal on a 6GB  Tri-channel kit from Mushkin that was the correct configuration. I hadn’t heard of them so I checked out their forums. The moderator was really helpful. I gave him all the information that I had and he felt that the memory would work. He also offered to verify it with the engineering team. I like good service so I gambled and made the purchase.

The hardware arrived after a week and a half. After unpacking  the server, I fired it up to verify that things seemed OK. I shut it down after a couple of hours and installed the new memory. Then fired it back up. The server recognized the memory and everything seemed OK. After a couple more hours, I shut it down and installed the new hard drive.

Now I had a new server, eating electricity and doing nothing.

Next: Installing Hyper-V Server 2008 R2

Thursday, October 1, 2009

VMware Workstation and Resharper

I’m a huge fan of both VMware Workstation and Resharper. I do all my various software development tasks within a virtual machine. Each client or project gets their own VM. It really lessens the chance of an environmental changes for one client affecting another client or project. If that’s never happen to you, consider yourself lucky.

I have Resharper configured to use the IntelliJ IDEA keyboard shortcuts. I started using Resharper back with version 2.? and those were the shortcuts in place at the time. So those are the ones that I’m used to. One of my most used navigation shortcuts is Ctrl+Alt+F7, which is Find Usages. The shortcut never worked in the VMs. Well, today I realized that VMware was intercepting Ctrl+Alt as the hot key to release the mouse back to the host computer.

Luckily VMware has an option to change the hot key combination. Under Edit | Preferences and then select the Hot Keys tab in the Preferences dialog. I’m now using a custom combination of Ctrl+Alt+Win.

Saturday, September 12, 2009

The Bass Guitar Build – Part 4

This is the fourth post in a series describing the construction of a bass guitar. This is a project that my son and I took on when he stumbled into the opportunity to purchase a Jackson Bass Guitar body and neck for a pretty good price.

At this point, all the construction tasks had been completed.

We strung up the guitar using the strings that I had purchased from one of the Sam Ash trips. Actually, putting the strings on the bass is easier than stringing the other guitars. Probably because bass strings are thicker and easier to handle.

The first thing that we noticed was a terrible buzz on every string. No surprise really. I suspected that we’d have to adjust the relief of the neck. If you’re not familiar with what I’m talking about, most guitar necks are not straight. They have a little bow in them and this is called the relief. If you hold the guitar in playing position and sight down the neck, you’ll typically see bowing one way or another. In our case, the neck had a sever back-bow which was causing the strings to not have enough clearance above the frets. So when the strings were struck, they bounced off the frets causing a buzzing noise.

The obvious solution was to correct the bowing and most guitars have a metal rod, called the truss rod, through the neck that is used to make this adjustment. This is where the next trouble-spot of this project occurred. The truss-rod nut on this guitar was sitting in a little pocket that was cut into the head stock.

None of my sockets would fit within the pocket so that I could adjust the nut. I went to Lowes and bought a socket and extension that I thought would work. You can probably guess that it didn’t. I even removed the neck and took it to Lowes. Still no luck.

I knew we really needed a 9/32 inch barrel wrench so we went to Guitar Center. They didn’t have anything. We were close at Sam Ash. They had a 5/16 inch one. So we ended up ordering one from Stewart-MacDonald.

Once we received the wrench, I was able to adjust the relief to remove the back-bow and get the action (the height of the strings above the frets) where it was comfortable for my son to play. We went from this

to this (sorry about the blurry picture).

Hopefully you can see the increase in height of the string about the fret. In our case, I used the recommendation from the Fender support site. You can find them here.

With the action set, we moved on to adjusting the intonation. The intonation affects the tuning of the guitar all along the neck. The way that the neck is laid out, the open sixth string will typically be tuned to an E and fretting the sixth string at the 12th fret will also produce an E but one octave higher. Setting the intonation requires that you tune the open string, fret the string at the 12th fret and hope that you get the same note. If you don’t, you adjust the string’s saddle forward or back, depending on whether the note was sharp or flat. Moving the saddle causes the string’s length to change. You then have to retune the open string and check the tuning at the 12th fret again. You repeat this procedure for each string and it will take a long time.

The last step was to adjust the height of the pickups. Again we used the recommendation from the Fender site. This procedure was made easier by the fact that we had mounted the pickups on springs.

Finally we removed the protective wrapping from the control-cavity cover and installed the knobs on the volume and tone controls. And with that, we were done.

This was a great little project that I really enjoyed because it allowed me to spend some quality time with my son working on something that was important to him.

Thursday, September 3, 2009

My first blog comment...

and it's comment spam

Sunday, August 23, 2009

The Bass Guitar Build – Part 3

This is the third post in a series describing the construction of a bass guitar. This is a project that my son and I took on when he stumbled into the opportunity to purchase a Jackson Bass Guitar body and neck for a pretty good price.

I’d like to describe the installation of the electronics in this post. Unfortunately I don’t have as many photos as I would have liked. In the previous guitar build, I has easily spent 80% of the time on refinishing the body. Now the body was done and the rest would be easy; pop in the pickups, insert the potentiometers, throw in some solder in strategic places and BAM! Sound.

Or so we thought.

Those Damn Pickups

For pickups we went with EMG Selects. EMG makes good pickups and Stewart-MacDonald had them at a good price.

We unpacked the pickups and did a dry-fit. This is where the problem began. The routing for the pickups was much deeper than the pickups themselves so the they fell to the point where they were flush with the guitar body.

The Fender support site recommends a pickup height of 7/64” on the bass side and 5/64” on the treble side. We tried using a piece of wooden pencil but that wasn’t high enough. We then tried cutting a shim from a scrap block of wood but that also wasn’t giving us the right fit.

I remember from the previous build that the pickups were mounted in a spring loaded housing. I went scurrying around the house looking for pens to steal the spring from. All I could find were three pens. I needed eight.

I them remembered that my wife had just purchased a new hair dryer because the previous one had burned out. (I bet you’re thinking “Where the hell did this come from?” Well, what is the heating element in a hair dryer? A couple of coils wrapped around a tube. What is a spring? A compressed coil. ) I rushed upstairs to grab the old dryer out of the recycle bin and proceed to dismantle it.

I unwound one of the coils and cut it off the tub. It was then easy enough to cut the eight springs that we needed.

We threaded the mounting screws through the pickups and through the springs. Then popped them into the routings in the body. The springs gave the right amount of lift so we were able to get the recommended height.

Note: When reciting this story to one of the instructors at the music school where my son takes lessons, he mentioned that some builders us foam padding under the pickups to achieve the same effect. That probably would have been easier if I had some laying around.

With the pickups mounted, we mounted the potentiometers for the volume and tone controls.

Wiring

If you’re interested in building a guitar, don’t let the wiring portion of the project scare you. In my opinion, dealing with the body and paint is much harder than the dozen or so solder connections that you have to make. Even getting all the parts is easy if you purchase a wiring kit. For this project, I purchased the wiring kit from Stewart-MacDonald. It comes with three pot, the capacitor, jack, wiring and a wiring diagram.

Here’s the wiring diagram that we used:

This is really an easy project for someone that has never used done any soldering work before. The only difficulty might be in the tight workspace of the control cavity. Just remember to cover as much of the guitar’s body as possible in the event of any solder drips.

Unfortunately I don’t have any pictures of the wiring work. I will say that it didn’t take long for my son to burn himself on the soldering iron. Also, here’s a tip: periodically run the tip of the soldering iron on a foam sanding block. After a while, the tip will become covered with a layer of residue that prevent interferes with heat transmission. The sanding block removes the residue quickly. It will make the work good much faster and easier.

Once the wiring is completed, we used a multi-meter to check that all the connections where good, including all the grounds. We then mounted the jack into the jack-plate and screwed it to the body. Now it was time to hook the guitar to the amp and test everything.

We used a nickel to gently tap each pickup to verify that it was producing a sound. Everything worked as expected.

The small stuff

Now that the wiring was completed, we could finish the rest of the body work. That included installing the control-cavity cover, the strap buttons, neck, tuners and the nut.

I purchased a nut that was pre-cut for a four-string bass guitar. To install it I cleaned up the area where the previous nut had been. We then installed the two outer strings to help position the nut correctly. A thin layer of glue is applied to both the neck and nut, and then the nut is clamped into position.

All that was left was to install the strings and do the setup. As you might expect, that was the start of a new adventure. I’ll save it for the next post.

Wednesday, August 19, 2009

The Bass Guitar Build – Part 2

This is the second installment of the Bass Guitar Build. If you’re just jumping in, my son and I purchased the body and neck of a Jackson Bass Guitar. It has been stripped of everything else by the previous owner so we were able to get it cheap.

In part 1, I described the work that my son and I did to repair three chips in the body. Here I’d like to continue describing the rest of the body work that we had to do.

The Control Cavity Cover

The original control cavity cover was also missing when we purchased the guitar so I ordered a new one from Stewart-MacDonald. From the looks of it, the original was mounted straight onto the back. Since I was already working on the body, it was easy enough to route space around the control cavity so that the cover would lay flush instead of on top.

I don’t own a router but I do have a Dremel. I used a  router bit and was able to remove the unnecessary material from around the control cavity with little trouble.

After dry-fitting the cover so that we could drill holes for the screws, I decided to paint the fresh wood to match the rest of the body. It just seemed like a nice touch.

The Bridge

Next we turned our attention to mounting the bridge. There was a hole near the middle screw for a bridge ground but it wasn’t drilled through to the control cavity. Now, a guitar body is not that thick, maybe 2 or 2 1/2 inches but the control cavity is not in the middle of the guitar. It’s all the way to one side. The hole for the bridge ground has to be drilled at an angle, a very slight angle. This takes a very long, thin bit – that I don’t have. Luckily I learned a trick where a segment of coat hanger can be used as a make-shift drill bit. You just have to snip one end at a slight angle to create a very sharp point.

So my son and I did some guessing at what the angle should be to go from the bridge to the control cavity and we put our make-shift bit to use. Well, we got really lucky. We came out about 3/4 of an inch short of the control cavity but still within the area that I had just routed out. I broke out the Dremel (I love that tool!) and cut a channel from the hole into the control cavity so that the cover would still lie flush.

To mount the bridge, I ran a wire from the control cavity, through the new hold, and folded one end into one of the screw holes. We then aligned the bridge and popped in the back screws. Our bridge required that we drill two new screw holes in the front. The original bridge used only five screws, ours required seven.

We could turn our attention to the electronics now that the the body work was completed. And that will be the topic for the next post in this series.

Monday, August 10, 2009

Upgraded the laptop to Windows 7

I’ve had Windows 7 on my Dell Vostro 1500 laptop since the RC was made available. For the RC, I took the opportunity to get a new hard drive. I wanted to create two partitions. One for the OS and one for data. I periodically repave the machine and it’s painful every time. So I look for opportunities to minimize the hurt.

That’s why I started doing all project work and installing betas in virtual machines (VMware Workstation). I don’t have to worry about a refresh affecting one of my projects nor do I have to worry about an install for one project affecting another.

When I read that Windows 7 was to be released,I wasn’t looking forward to spending the hours reinstalling. I was quite pleased when a co-worker brought this article to my attention.

I followed the instructions, using VMware Workstation to mount the ISO as the CD drive. And just in case, I burnt everything to a DVD after modifying the configuration file.

I had no problems with the Windows upgrade, but after it rebooted, the AVG firewall wouldn’t start. The firewall reported the following error description:

Firewall cannot start because on error has occurred in communication with a driver. Please contact AVG Technical support.

Reinstalling AVG corrects the problem.

I’m now running the RTM of Windows 7 and I only had to reinstall AVG and VMware Workstation.

Override the connection string in IBatis.Net

Like many software developers, I built one too many data access layers. Don’t get me wrong – I’m really happy with ADO.Net and it’s capabilities. I just don’t want to write the same code snippets over and over. I’ve also gone the code-generation route using multiple tools like CodeSmith and even the Guidance Automation Toolkit. I’m a big fan of NHibernate and I’m looking forward to using it again in the future.

On my current project, we’re using IBatis.Net’s DataMapper.

For this project though, there was a slight twist. For security reasons, the connection string is encrypted - but not using the facilities to encrypt sections of the config file.  For whatever the reason, it is what it is.

Now, normally you would define your data sources in the SqlMap.config file. It would look something like this:

`   1: <databases>`

`   2:     <provider name="sqlServer2.0"/>`

`   3:     <dataSource name="centralDb"`

`   4:         connectionString="server=(local); catalog=central;integrated security=true;persist security info=false;"`

`   5: </database>`

This, of course, is not an encrypted connection string. It turns out that using an encrypted connection string with IBatis.Net really isn’t that difficult. We’ll start with out SqlMap.Config file.

Our SqlMap.config file

The only purpose of our file is to indicate that type of provider that we’ll be using. Notice that connection string contains information directing people to look elsewhere for it.

` 1: <database> 2: <provider name="sqlServer2.0"> 3: <datasource name="centralDb" connectionstring=" -- uses encrypted string from config file --"> 4: </database> `

EncryptedDataSource

We have a custom DataSource that is responsible for retrieving the encrypted connection string, decrypting it and making it available.

EncryptedDataSource.cs

`   1: public class EncryptedDataSource : DataSource `

`   2: { `

`   3:     private IDataSource _innerDataSource; `

`   4:     private string _connectionString; `

`   5:     private object _lock = new object(); `

`   6:     `

`   7:     /// The data source. `

`   8:     public EncryptedDataSource(IDataSource dataSource) `

`   9:     { `

`  10:         _innerDataSource = dataSource; `

`  11:     } `

`  12:     `

`  13:     private void Initialize() `

`  14:     { `

`  15:         string encryptedConnectionString = ...; `

`  16:     `

`  17:         if (string.IsNullOrEmpty(encryptedConnectionString)) `

`  18:         { `

`  19:             throw new ConfigurationErrorsException( `

`  20:             "The encrypted connection string could not be located within the configuration file. Please check the configuration file."); `

`  21:         } `

`  22:         this._connectionString = ...; // decrypt key `

`  23:     } `

`  24:     `

`  25:     public override string ConnectionString `

`  26:     { `

`  27:         get `

`  28:         { `

`  29:             if (string.IsNullOrEmpty(this._connectionString)) `

`  30:             { `

`  31:                 lock (_lock) `

`  32:                 { `

`  33:                     if (string.IsNullOrEmpty(this._connectionString)) this.Initialize(); `

`  34:                 } `

`  35:             } `

`  36:         `

`  37:             return this._connectionString; `

`  38:         } `

`  39:         set `

`  40:         { `

`  41:             this._connectionString = value; `

`  42:         } `

`  43:     } `

`  44:     `

`  45:     /// `

`  46:     /// The provider to use for this data source. `

`  47:     /// `

`  48:     public override IDbProvider DbProvider `

`  49:     { `

`  50:         get `

`  51:         { `

`  52:             return this._innerDataSource.DbProvider; `

`  53:         } `

`  54:         set `

`  55:         { `

`  56:             this._innerDataSource.DbProvider = value; `

`  57:         } `

`  58:     } `

`  59: } `

` Mapper.cs We initialize our mapper as you would expect but we reset the DataSource with an instance of our EncryptedDataSource class. The constructor of the EncryptedDataSource accepts the data source that was built as part of the initialization. This way we can return it whenever the framework asks for information about the configured provider.`

`   1: protected static void InitMapper() `

`   2: { `

`   3:     ConfigureHandler handler = new ConfigureHandler(Configure); `

`   4:     DomSqlMapBuilder builder = new DomSqlMapBuilder(); `

`   5:     ISqlMapper mapper = builder.ConfigureAndWatch(_sqlMapFile,handler); `

`   6:     Debug.Assert(null != mapper); `

`   7:     mapper.DataSource = new EncryptedDataSource(mapper.DataSource); `

`   8:     _mapper = mapper; `

`   9: } `