Wednesday, November 09, 2005

Boy, were they ready!

What an exciting launch. Microsoft spent a ton of money on this marketing campaign and it showed! They had the guys from the show American Choppers build a motorcycle and Paul Sr. drove it into the crowd and allowed all the attendies to take a photo with him and Mikey. (I love that show so it was exciting for me!) They also got the rock band Cheap Trick to play a concert that evening - they rocked.

I was stationed at the Ask The Experts lounge, the Enterprise Developer cabana and helped out over in the Hands on Lab. I had a lot of positive customer experiences and interesting conversations.

Everyone at the event received a full licensed copy of SQL-Server 2005 Standard edition and Visual Studio 2005 Professional edition packaged to look like two platinum record albums. I ended up with a backstage pass and on my copy I got autographs of Paul Sr. and Mikey as well as the lead singer of Cheap Trick, Robin Zander.

If you can make it to one of the Launch events in your area I would highly recommend attending. Thank you Microsoft for a great day!

Friday, November 04, 2005

Are you ready to rock!?

Visual Studio 2005 Launch Event - San Francisco
This Monday is the SF launch event! I'll be hanging out in the Ask The Experts lounge from 10am-12:30pm and then at the Enterprise Developer copa-cabana from 1:30-2:45pm. Come by and say hello!

Sunday, October 02, 2005

MVP Summit is over...

Ahhhh... I'm still recovering from the MVP Summit "social activities". ;-) It was a great summit. I learned a lot and saw a ton of amazing stuff coming from the Microsoft camp. I'm really excited about the future.

In my search for the answer to the question "What is an Architect?" I realized that even the other architects I spoke with had the same question. It was interesting to hear different views on what an architect is and what the architect MVPs actually did. I don't think there really is a clear definition of what an architect is or does exactly, however, I did learn that all architects have a couple things in common.

Architects are open minded people that can accept other people's solutions to particular problems. As long as the solution meets the problem's performance and scalability needs and the solution is easily maintainable then an architect will buy into your design. Architects balance the needs of the business and the needs of the system. They are sensitive to construction costs and maintenance costs based on the people designing and maintaining the system. They understand (or are at least aware of) the proven patterns of not only software solutions but also business processes.

Regardless of whether you are an enterprise connected systems architect or a software product architect or an infrastructure architect, you are sensitive to the construction and maintenance costs of your solution with your particular group of people and your particular business.

Tuesday, September 27, 2005

MVP Summit here I come!

I'm working from a downtown Seattle hotel with a beautiful view today -- tomorrow the MVP Summit starts. Someone forgot to tell Seattle that summer is over, it's absolutely gorgeous here!

I'm really looking forward to meeting my fellow architect MVPs. I'm interested to see exactly what other "architects" actually do. Connected systems, business applications, products, infrastructure, databases, all of the above? How much code do they actually write? How many developers do they direct? How much influence do they have on the business? Are they typically consultants or employees? What is an architect anyway? Microsoft's vision for architecture sounds a little fluffy to me. I'm hoping to walk away from the summit with a much clearer picture.

Of course, I'm also excited about seeing the new XBox 360 ;-)

Tuesday, September 20, 2005

Tragedy Hits the Fox Community

On Friday Drew Speedie and his son, Brent, fell a few hundred feet to their deaths from a bridge in Yellowstone Park while vacationing there. My heart goes out to Irene his wife. Drew was a Visual FoxPro MVP and regular conference speaker and writer.

I remember the first time I ever met Drew was at the Visual FoxPro 6.0 DevCon in May 1998 in Orlando. I remember how funny and engaging he was showing off the VFP Grid. Drew was great at showing you the ins and outs and tips and tricks of a particular feature -- things you never thought of.

The first time I ever met Brent was at an Essential Fox conference (I think 3 years ago) in Kansas City. The first thing that came to mind when talking with him was "Wow, this kid is smart. And just like his father." He was very engaging and had the same wit as Drew during our conversation about Arizona. The last time I spoke with Drew he told me about some beautiful places to visit in Arizona -- I think I'll have to go see them now.

For more information please visit the FoxWiki.

Thursday, September 15, 2005

The exciting future of Visual Basic

Make sure you check out the Future Versions section of the VB site for information on LINQ. You can even download a preview of this technology which works with the release candidate of Visual Studio! And if you haven't read this yet, this MSDN paper is a great overview of Visual Basic 9.0. Man! VS 2005 isn't even released yet and I'm drooling over the features of the next version after that! Sigh.

Wednesday, September 14, 2005

A fundamental shift in programming for most, a sigh of relief and a breath of excitement for us!

Paul Vick formally announced Project LINQ yesterday at PDC. LINQ stands for "Language Integrated Query". LINQ brings standard query operations into the .NET platform. Wow, an object oriented language with rich query syntax... hmmmm... sounds vaguely familiar ;-). This is what I've personally been waiting for ever since I moved into .NET programming from Visual FoxPro work. Paul is right; this does represent a fundamental shift in programming for most developers. When you have a language that supports this style of programming, the architecture of your applications change. You start to think about dynamic data (and metadata) as the engine of your application. It's not to say you can't create dynamic data-driven applications right now in .NET, it's just a lot harder. When you can write elegant queries directly into the editor you tend to favor that expressive style when working with data instead of a rigid strongly-typed object approach. For instance you could write a function that performs some complex operations on changing data but apply it inside of a select query for only the matching pieces of data; and you can do it in 5-10 lines of code instead of 100 lines of for each's and if statements.

Now for the people of the Fox this is the only logical way to work with data inside of an application so I think that's one of the major reasons people stay working with Visual FoxPro. However, VFP is not a strongly-typed language, it's execution is slower and it's based on COM. But because VFP is loosely-typed you can get away with a lot of slick dynamic, scripting-style programming.

What the architects of LINQ are doing is amazing. They are bringing query comprehension to a strongly-typed environment. However, I'm personally excited about the future of VB.NET. VB.NET is strongly-typed AND loosely-typed at the same time. In my opinion that will make VB.NET the preferred data-oriented programming language and the language of the future -- especially for information systems.

I hope that Visual FoxPro programmers will take a hard look at VB.NET if they haven't already. There is a lot of opportunity for you here because we already know how data-based applications should be written using query in the language and we can provide invaluable feedback to the architects of LINQ and VB.

Tuesday, September 06, 2005

I'm speaking at the Bay.NET UG on Thursday

I'm speaking on Thursday for the Bay.NET user group down in Pleasanton. So if you rather see me than the Raiders vs. Patriots game (I know it's a tough decision) then come on out!

Wednesday, August 24, 2005

The Fox is out of the bag

In the Visual FoxPro August Newsletter in a paragraph regarding the SouthwestFox conference Ken mentions: "Calvin's presentation will be on great demos of new language features being added to a future version of Visual Basic for data-centric .NET programming significantly based on Visual FoxPro technology."

On a related note, Paul Vick punches up the abstract on his PDC topic Visual Basic: Future Directions in Language Innovation

Hip hip, HOORAY!!!! And the crowd goes wild......

Wednesday, August 17, 2005

Back from vacation

Ahhhh. I love summer. This year we drove up the west coast from San Francisco to Seattle. The first day we made our way through the redwoods up to Humboldt County. We stopped in Eureka and stayed at the Carter House Inn. It was beautiful and lots of fun. It was foggy in the morning but it cleared up and was sunny and mild in the afternoon- typical Northern California costal weather for August.

We then headed up the coast into Oregon, stopping at every tourist trap along the way -- Confusion Hill, Trees of Mystery, and the Enchanted Forest (complete with concrete dinosaurs). We made our way up to a camground near Dune City, OR - 8 miles south of Florence - and camped there for two nights. We hiked to the beach in the morning -- pretty easy walk, actually -- and collected shells and played on the beach with the seal lions. It was just me, Alan and the lions -- no one else for miles. A man did come out of nowhere and strolled up to us. But he gave me some cool agate stones and a whole sand dollar he found on the beach. He was cool.

After our relaxing two days we headed up to Seattle via I-5 through Portland. We needed to meet a friend who was flying in that night for Alan's birthday. Of course the flight was delayed 2 hours (because she flew Alaska Airlines) and she missed the dinner party. I should have figured. Alaska is ALWAYS delayed no matter what time of year. You're better off flying SouthWest (if you don't mind being hearded like cattle).

The rest of the week we spent visiting friends in Seattle and going up to Victoria, Canada (yes we went to Butchart Gardens ;-)). It was cold and overcast in Seattle (naturally!) but Victoria was nice and sunny.

It's nice to be back home. Visiting other places really makes me appreciate where I live. Summer is still in full swing here in the East Bay and I'm looking forward to spending the rest of it at home. Well, maybe I'll go camping on Mount Diablo one weekend with my sister, but that's only a 20 minute drive ;-)

Monday, July 11, 2005

VB.NET as a dynamic, data language

Personally, I am very excited about what Paul says in his post here. This is one of the biggest reasons why I love VB.NET (and VFP), and it looks like there will be some very exciting things to look forward to after VS2005. Make sure to check out this paper (which Paul links to from his post) by Erik Meijer and Peter Drayton.

Monday, June 27, 2005

Back Home from DevTeach

Well I'm back home from DevTeach which was held in beautiful Montreal. If anyone was looking for the rest of the presentation demos and slides they are all up on the DevTeach site now. I met lots of new friends this trip that I hope to keep for a long time to come. Thanks to everyone at DevTeach for a wonderful conference!

Wednesday, June 08, 2005

VS/SQL-Server 2005 Release Date Announced

The release dates for the next versions of Visual Studio, BizTalk and SQL-Server were announced at Tech Ed to be the week of Nov. 7th. A few places to read about it are here, here and here.

Wednesday, June 01, 2005

Bonus Session at DevTeach

If you're coming to DevTeach, you should definately check out the architecture bonus session. I'll be sitting on a panel with a bunch of really cool architecture dudes. Plus Nick Landry is going to be the animator so it should be a lot of fun! Hope to see you there.

Tuesday, May 17, 2005

Make your .NET demos better with a TraceListener

Last night I was writing a sample application for one of my DevTeach sessions and I thought I'd share this little trick. If you've ever tried to fiqure out a speaker's sample code after the conference when you got home you'd appreciate this as well. Usually I just write copious amounts of comments in my code to help people but last night it dawned on me how I could add a very simple TraceListener to my application to easily display the application's sequence of events in a list box. This way the developer could see exactly what was going on at runtime without having to debug the code.

If you're unfamiliar with TraceListeners have a read here.

Trace listeners monitor the output of the Debug and Trace messages in an application. You can create custom listeners and then add them to the Debug or Trace Listeners collection on application startup quite easily:
Imports System.Diagnostics

Public Class Main
 ''' --------------------------------------------------------------
 ''' <summary>
 ''' Main enrty point for the application.
 ''' </summary>
 ''' <remarks>
 ''' </remarks>
 ''' <history>
 '''  [Beth] 5/16/2005 Created
 ''' </history>
 ''' --------------------------------------------------------------
 Shared Sub Main()
  '-- Registers a trace listener 
  Debug.Listeners.Add(New DemoAppTraceListener)

  Application.Run(New MainForm)
 End Sub
End Class
The idea for the DemoAppTraceListener class is very simple. I just want to globally broadcast the trace messages so that they could be displayed by the application anywhere. We can do this by declaring a Shared (static) event:
Imports System.Diagnostics

''' -----------------------------------------------------------------------------
''' Project  : DataCachingStrategies
''' Class  : DemoAppTraceListener
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' Globally broadcasts the trace messages in this demo which are displayed in the UI.
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
'''  [Beth] 5/16/2005 Created
''' </history>
''' -----------------------------------------------------------------------------
Public Class DemoAppTraceListener
 Inherits TraceListener

 Public Shared Event MessageReceived(ByVal e As MessageEventArgs)

 Public Overloads Overrides Sub Write(ByVal message As String)
  RaiseEvent MessageReceived(New MessageEventArgs(message))
 End Sub

 Public Overloads Overrides Sub WriteLine(ByVal message As String)
  RaiseEvent MessageReceived(New MessageEventArgs(message))
 End Sub

End Class

''' -----------------------------------------------------------------------------
''' Project  : DataCachingStrategies
''' Class  : MessageEventArgs
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' This EventArg is used to broadcast messages from the DemoAppTraceListener.
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
'''  [Beth] 5/16/2005 Created
''' </history>
''' -----------------------------------------------------------------------------
Public Class MessageEventArgs
 Inherits EventArgs

 Private m_msg As String = String.Empty
 Public ReadOnly Property Message() As String
  Get
   Return m_msg
  End Get
 End Property

 Public Sub New(ByVal msg As String)
  m_msg = msg
 End Sub
End Class
Now all you have to do is handle the event and display the messages. Oh, yea you also have to actually put Trace messages in your code now too!
Public Sub Foo
        Trace.Write("Entering Foo method")
.
.
.
End Sub
To display the messages in my demo I created an MDI parent and put a simple list box on the bottom. Then I just added a handler to the DemoAppTraceListener.MessageReceived event. I added the handler in the constructor because this code is hidden in the form designer region and people won't be distracted away from the demo code.
#Region " Windows Form Designer generated code "

Public Sub New()
 MyBase.New()

 'This call is required by the Windows Form Designer.
 InitializeComponent()

 'Add any initialization after the InitializeComponent() call
 AddHandler DemoAppTraceListener.MessageReceived, AddressOf Me.DisplayMessage
End Sub
.
.
.
Finally I added the few lines of code to display the message in the list box and select the last message:
Private Sub DisplayMessage(ByVal e As MessageEventArgs)
 Me.lstMsgs.Items.Add(Me.lstMsgs.Items.Count.ToString + ". " + e.Message)
 Me.lstMsgs.SelectedIndex = Me.lstMsgs.Items.Count - 1
End Sub
Another cool thing about using a TraceListener is that the developer can still copy/paste the code in the demo into their own applications without having to remove the Trace messages if they don't want to.

Now if you come to my data caching session at DevTeach you'll get to see the TraceListener in action! ;-)

Saturday, May 14, 2005

A component walks into a bar....

The component asks the bartender via .NET remoting:
"Gimme a beer"
Bartender:
"What kind of beer?"
Component:
"Just give me all of them one by one and I'll drink the one I like."

The component asks the bartender via Web Services:
"Gimme a beer"
Bartender:
"What kind of beer?"
The component thinks a minute.
"I didn't know you'd have more than one. I just want a beer."
Bartender:
"What kind of beer?"
Component:
"A plain one."
Bartender:
"What's plain beer? How about a bud?"
Component:
"Umm.. ok."
The component tries to take the beer but it slips onto the floor and the glass breaks.
Bartender:
"What's wrong with you?"
Component:
"I got a slippery SoapException."

Thursday, May 05, 2005

Refactor, refactor, REFACTOR!

So much for hiding the word "refactor" from VB.NET developers... (oh how I love the fact that it's spelled with a big fat exclamation point!!!!)

Have you taken a look at this new VB 2005 refactoring? I think this refactoring interface blows doors off the C# one. Everything is context sensitive right at your fingertips and all inline with the code editor -- no modal dialogs! And it's just a whole heck of a lot smarter about what you would want to do with the selected code. Any developer will be able to pick this up in two minutes. Thank you Microsoft for making such an awesome deal with Developer Express to provide us all with this free tool. (I think there's a C# one you can buy for $99.)

Thursday, April 21, 2005

Custom Exceptions and Remoting

I just thought I'd put up a reminder post about enabling the throwing of custom exceptions from your remote objects since this was a change from 1.0 to 1.1. It recently bit me in the butt when I was setting up a new system. If you need to throw your own exceptions from your remote objects that are hosted in IIS, you need to make sure that customErrors="Off" in your Web.config file. By default it's set to "RemoteOnly" which means it will work on your development machine, but not when clents requests are coming from remote machines.

Wednesday, April 13, 2005

Combobox Databinding Woes

UPDATE: This post is for Visual Studio 2003. For Visual Studio 2005 content please see this post.

I've been noticing a lot of questions on the newsgroups related to Winforms databinding and the combobox and I thought I'd post something up here to help people out. There are a couple very common scenarios in which people use the combobox:

1. To display information from a lookup table and send the selected value into another table's field.

2. To display a list of parent table's records and use that as a filter to display related child records. For instance, as the user selects a record in the combobox, you want to display all the related child records in a grid.

As usual, the trick is setting up the data binding properly and using the currency managers. In the first case it's not necessary to set up a data relation in your dataset between the lookup table and the table you're editing, but it doesn't hurt. In the second case it is necessary to create a relation between your parent and child tables. Let's take an example from our beloved Northwind:

Private Const SQL_CONNECTION_STRING As String = _
 "Data Source=localhost;" & _
 "Initial Catalog=Northwind;" & _
 "Integrated Security=SSPI"

Try
 Dim ds As New DataSet
 Dim cnn As New SqlConnection(SQL_CONNECTION_STRING)

 Dim da As New SqlDataAdapter("SELECT * FROM Region", cnn)
 da.Fill(ds, "Region")

 da = New SqlDataAdapter("SELECT * FROM Territories", cnn)
 da.Fill(ds, "Territories")

 ds.Relations.Add("Region_Territories", _
  ds.Tables("Region").Columns("RegionID"), _
  ds.Tables("Territories").Columns("RegionID"))

 ds.DataSetName = "RegionTerritories"

Catch Exp As Exception
 MessageBox.Show(Exp.Message)
End Try
In the first scenario we want to select a Region from the combobox and have that value populated into the Territorries record. In this case you'll need to set up the following properties on your Combobox:
Me.ComboBox1.DataSource = ds.Tables("Region")
Me.ComboBox1.DisplayMember = "RegionDescription"
Me.ComboBox1.ValueMember = "RegionID"
These properties control what items are displayed in the combobox and what value is used when the user makes a selection. Now to get that value into the Territories table, you'll need to set up a data binding:
Me.ComboBox1.DataBindings.Add("SelectedValue", ds, "Territories.RegionID")
Okay we're all set, right? Well... not exactly. You'll also need to call EndCurrentEdit on the territories currency manager at some point in order to write the value back to the dataset. Depending on the style of your form you could do this from an "Update" button (similarly you could call CancelCurrentEdit from a Cancel button). However, when working with datasets I find it much easier to use the dataset methods for Accepting/Rejecting row changes. So 99.99% of the time I just call EndCurrentEdit from the SelectedIndexChanged event handler of the combobox itself:
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
 '-- This forces the comboxbox's value to be written to the dataset.
 Dim cm As CurrencyManager = DirectCast(Me.BindingContext(ds, "Territories"), CurrencyManager)
 cm.EndCurrentEdit()
End Sub
The cool thing (or anoying thing depending on how you look at it) about EndCurrentEdit/CancelCurrentEdit on the currency managers is that they cancel or commit only the fields in which they have bindings for where as the dataset rows' AcceptChanges/RejectChanges works on the whole row regardless of the data bindings. (It would be *really* nice if the currency manager had a property for this like "AlwaysCommitChanges" so we wouldn't have to call EndCurrentEdit all over the place.)

Now let's take our second scenario where we want to use the combobox as a row filter. In this case we have to have a relation set up between our parent and our child; in the example this is Region_Territories. The combobox properties can be set up just like the first example:
Me.ComboBox1.DataSource = ds.Tables("Region")
Me.ComboBox1.DisplayMember = "RegionDescription"
Me.ComboBox1.ValueMember = "RegionID"
Technically we don't need to specify the ValueMember property this time because we're not writing it anywhere, but it doesn't hurt to specify it. Next you'll need to set up the Datasource and DataMember properties of the DataGrid using the relation path. It is very important to get the path right otherwise the datagrid will not filter automatically as we move the position in the parent:
Me.DataGrid1.DataSource = ds
Me.DataGrid1.DataMember = "Region.Region_Territories"
Okay we're all set, right? Well... not exactly (I knew you were going to say that <g>). Unfortunately a combo box won't move the CurrencyManager's position for you like list controls do (Grids, Listboxes). So the trick is to get a hold of the parent currency manager and move the position manually by handling the combobox's SelectedIndexChanged event:
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
 Dim cmParent As CurrencyManager = DirectCast(Me.BindingContext(ds, "Region"), CurrencyManager)
 cmParent.Position = Me.ComboBox1.SelectedIndex
End Sub
Because you set up the datagrid to display the related territories by specifying the relation path Region.Region_Territories as the DataMember, the grid will automatically filter it's rows based on the selected parent row in the combobox.

The currency managers are your friends. You can obtain currency managers for any table/path in your dataset even if there are no control bindings set. You can also use the currency managers to disable controls when the position moves to -1 (no records) Here's an example. The currency managers maintain dataviews so you can easily access the current DataView as well as the current DataRowView:
Dim dv As DataView = DirectCast(cmParent.List, DataView)
Dim dvr As DataRowView = DirectCast(cmParent.Current, DataRowView)
Complex winforms databinding can take some practice, but once you get the hang of it you can create some very cool forms. Have fun!

Stop the mailing list insanity!

Looks like I'm not the only one frustrated with unwanted email that won't unsubscribe! (Make sure you scroll to the diagram on page 3. WARNING: This may offend you.)

Friday, April 08, 2005

Sunday, April 03, 2005

I'd like to thank the academy...

This was totally unexpected and I just want to extend a personal thank you to Microsoft, GiftRAP, and especially the community!

Friday, April 01, 2005

Spoof someone for April fools!

http://www.msnsearchspoof.com/index.aspx

MSN Search celebrates April Fool's Day by introducing Spoof, a tool to let you create funny search results about a friend, family member, or co-worker. When you're done, you can send the page to the target or anyone else you think might get a laugh out of it.

Tuesday, March 29, 2005

Finally a hybrid that doesn't suck?

It's not like I hate the environment or anything (please, all I do in the summer is camp and mountian bike), it's just that hybrid cars are, well, sloooooow. I'm a car enthusiast and I've tweaked my Subaru WRX wagon to put it over the 350hp mark. It's a 4-cylinder turbo wagon that goes 0-60 in 4.9 seconds. That's respectible. Gas milage is 21mpg so that kinda sucks, but it isn't horrible. It's better than most SUV's on the market today (and I still have 4WD). I love my car. I just love cars.

I never thought these hybrid cars would really take off until two things happened. #1 - they were really fast. #2 - you can modify them. I admit #2 is not as important to most people, but I don't know many people who don't like power in their vehicle.

I came across the Lexus GS 450h today and it looks like Lexus has finally answered my #1 complaint about hybrids.

This new hybrid powertrain is unique to the GS 450h. It features a 3.5-liter V6 engine teamed with a high-output electric motor that, when combined, will produce "substantially" more than 300 horsepower, according to Lexus vice president of marketing Mark Templin. Lexus claims that this hybrid will be quicker than the new V8-powered GS 430, yet it should achieve fuel economy similar to that of a compact sedan with a 4-cylinder engine.

Only time and test driving will tell, but I think car manufacturers are moving in the right direction with these hybrids.

Sunday, March 27, 2005

Happy Easter!

Growing up Catholic (and 12 years of Catholic school!) I remember Easter as being a pretty big religious holiday. When me and my sister were kids, my mom used to make us cute little Easter outfits to wear to church. My sister was a little more into the cute dresses than I was but I do remember loving to wear those cool white bonnets with the long ribbons down the back. They also flew like frisbies if you threw them hard enough.

After Mass we used to go over to my Nona and Nono's (mom's parents) house and we'd have an Easter egg hunt. Nona would fill those plastic colored eggs with money and hide them in the yard. And I'm not talking dimes and nickels here, I'm talking paper money... $5, $10, even sometimes $20! The entire family used to participate, not just the kids (who wouldn't!). Though I do vaugely remember the kids got a head start.

One year, we all come back onto the patio and while opening our eggs and counting our money we see Nona hovering around us like she's looking for something. My mom asks her what she's looking for and she says that there's still a $20 egg out there somewhere. Now let me give you a little background on Nona's yard. Nona is one of the best gardeners I know (even today). She used to have beautiful tropical plants everywhere. She lived in Palos Verdies, CA overlooking the ocean and Catalina island. Her backyard looked like the Italian island of Iscia where she was from (off the Almafi coast). The yard was big. Real big. Real lush. Nona didn't make a treasure map. Whoops. We all looked for an hour and no money egg anywhere (though I do remember recruiting some more snails for my snail army). A couple years later while gardening, Nona finds the egg and the semi-decomposed $20 bill. But even the liquor store wouldn't take it when she tried to buy her lottery tickets. Great memories.

Although I'm not very religious now, Easter Sunday is still a day to spend with family eating and drinking (and drinking and drinking). This weekend has been really fun so far. My honey, Alan, is Jewish so he was very facinated with the whole Easter egg decorating. Friday was his first time. See, I usually go for an art deco look which basically involes throwing the eggs in as many colors as possible and then putting as many hideous stickers on them as I possibly can. Quantity, not quality, baby. Alan, on the other hand, took so much care in designing his eggs (all two of them). I do have to say that his were definate masterpieces. Of course, I had to break the news to him that my dad was just going to crack them open and eat them. But it was fun.

Later this afternoon we're heading over to mom's. Typically my mother makes enough gormet food to put Martha Stewart to shame. If 8 people are coming, she'll make food to feed at least 25. Now when we were kids we usually had some kind of roast or ham on Easter. When we got older the tradition changed to going out to a nice big brunch. This year Nona wanted to take it back home and cook. This year we're making rabbit. Yes, we're cooking up cute little easter bunnies and eating them. And if that's not enough, were also roasting a cute little lamb to go with the easter bunnies. My mom would never let Nona make this dish on Easter when we were kids because of the obvious freak-out factor, but we used to raise rabbits and I LOVE LOVE LOVE rabbit. And the way my Nona makes it is amazing. I can't wait!

I know my family is not normal, but we all love eachother very much and that's what these religous holidays mean to me nowadays... getting together with the people you love most in this world and having a good time. HAPPY EASTER EVERYONE!

Sunday, March 20, 2005

Podcasting to Fame

Carl's in the news about podcasting! If you haven't seen the DNR or Monday's shows you're definately missing out on some awesome podcasts. Carl's now setting up a customizable podcast called The Daily Commute. I can't wait to try this out.

Friday, March 18, 2005

Come to DevTeach 2005 in Montreal!

I'll be speaking at DevTeach 2005 this year in beautiful Montreal June 18-22. If you missed out last year, you should definitely consider it this year. I had a blast and those wonderful Canadians are so hospitable. I'm very excited to be coming back. Check out my sessions topics here and here. I'm doing a two parter with Nick Landry (aka Mobile Man) on designing distributed apps for multiple user interfaces. These sessions are going to be very "how to" focusing on a lot of different issues developing usable enterprise information systems. I can't wait!

DataSet Debugger Visualizer for VS 2003!

I don't know how I missed this one. This is probably my most favorite VS 2003 add-in to date. Anyone doing database development in .NET is probably using the DSWatch add-in. This add-in lets you select a dataset variable while in the debugger and presents a form with an XML representation of the dataset's data (as well as a datagrid).

Well say goodbye to DSWatch and hello to the XML Visualizer! This add-in rocks! Among the cool features it lets you view the schema of your dataset as well as the row versions. It also works on DataViews or any XML serializable type! Who needs to wait for Whidbey? Get this now!

Thursday, March 17, 2005

My Singleton Answer

In my previous post I asked a question about using the singleton pattern for application-wide services that were stored in an object repository. With the help of the commenters, I decided not to implement the singleton pattern in this situation because since the services were only accessed via shared members on the object repository there is no need to force the service classes into the singleton pattern. This also makes them easier to extend (inherit).

That said, the discussion led to the question about how to implement lazy initialization of shared members in a thread-safe manner. I mentioned I was using double-checked locking, but someone pointed me to this interestering article and this discussion. I decided to test out double-checked locking versus just locking before the read in my distributed app (basically just created a remoted unit test) and I observed no difference in performance really. The test was just the "give me a warm and fuzzy feeling" test so I didn't write any performance counters or anything. But just measuring speed of the calls with 40 concurrent threads calling the components 100 times I only saw between a 1 and 10 milisecond average difference in speed. This is really nothing to me so I'm going to go with the easier, safer pattern of locking the whole shee-bang:
Private Shared m_service1 As ExtendedService
Private Shared _syncRoot As New Object

Public Shared ReadOnly Property Service1() As ExtendedService
  Get
    SyncLock (_syncRoot)
      If (m_service1 Is Nothing) Then
        m_service1 = Factory.CreateExtendedService()
      End If
    End SyncLock
    Return m_service1
  End Get
End Property

Wednesday, March 16, 2005

Singleton Question

I've been going back and forth trying to decide whether or not to use a Singleton pattern for a specific situation and I've decided I need community input. In my application I have a global "object repository" which is basically just a single point of entry for application-wide services. Some objects are expensive to create and only used in certian situations but what they all have in common is that there only needs to be one instance of each service for my entire application since they are all thread safe (I hope! :P). The object repository itself contains only shared (static) readonly properties used to access the application services and has no instance methods itself. The services need to have an inheritable class hierarchy to support different application's needs.

My question is then, since I only access these objects from the ObjectRepository, do I gain anything by creating the base services as extendable (inheritable) singletons or should I just access them as shared members directly? Now what gets a little trickier is that the application is a server-side application and objects are activated as single-call objects, so depending on the load on the server the application service objects may not be around and may need to be created on the next round if the aspnet worker process is recycled, right? Anyways, I've got the system scaling really well not using the singleton pattern and just accessing the services as shared members of the ObjectRepository, but I'm just curious if using the singleton pattern in this situation will be more performant. Of course, since I need to have the services inheritable, if I go with the singletn pattern I will have to maintain the pattern on all the sub-classes so code maintenance has a weigh-in factor here as well.

So let me show you what I mean. Should I do this (what I'm doing now):
Public Class MyBaseService1

 Public Sub New()
  Initialize()
 End Sub

 Private Sub Initialize()
  'do initialization stuff
 End Sub

 Public Sub TemplateMethod()
  HookMethod1()
  HookMethod2()
 End Sub

 Protected Overridable Sub HookMethod1()
  'do default stuff
 End Sub

 Protected Overridable Sub HookMethod2()
  'do more default stuff
 End Sub
End Class


Public Class MyExtendedService1
 Inherits MyBaseService1

 Public Sub New()
  MyBase.New()
 End Sub

 Protected Overrides Sub HookMethod1()
  'do different stuff
 End Sub

 Protected Overrides Sub HookMethod2()
  'do more different stuff
 End Sub
End Class


Public Class ObjectRepository1

 Private Shared m_service1 As MyExtendedService1
 Private Shared _lock As New Object

 'Use lazy initialization because this 
 ' class is rarely used and expensive to create.
 Public Shared ReadOnly Property Service1() As MyExtendedService1
  Get
   If m_service1 Is Nothing Then
    SyncLock (_lock)
     If m_service1 Is Nothing Then
      m_service1 = New MyExtendedService1
     End If
    End SyncLock
   End If
   Return m_service1
  End Get
 End Property

End Clas
Or would it be better to implement this pattern?
Public Class MyBaseService
 Protected Shared _Instance As MyBaseService
 Protected Shared _Lock As New Object

 Protected Sub New()
  Initialize()
 End Sub

 Public Shared Function GetInstance() As MyBaseService
  If _Instance Is Nothing Then
   SyncLock (_Lock)
    If _Instance Is Nothing Then
     _Instance = New MyBaseService
    End If
   End SyncLock
  End If
  Return _Instance
 End Function

 Private Sub Initialize()
  'do initialization stuff
 End Sub

 Public Sub TemplateMethod()
  HookMethod1()
  HookMethod2()
 End Sub

 Protected Overridable Sub HookMethod1()
  'do default stuff
 End Sub

 Protected Overridable Sub HookMethod2()
  'do more default stuff
 End Sub
End Class


Public Class MyExtendedService
 Inherits MyBaseService

 Public Shared Shadows Function GetInstance() As MyExtendedService
  If _Instance Is Nothing Then
   SyncLock (_Lock)
    If _Instance Is Nothing Then
     _Instance = New MyExtendedService
    End If
   End SyncLock
  End If
  Return DirectCast(_Instance, MyExtendedService)
 End Function

 Protected Overrides Sub HookMethod1()
  'do different stuff
 End Sub

 Protected Overrides Sub HookMethod2()
  'do more different stuff
 End Sub
End Class

Public Class ObjectRepository
 Private Shared m_service1 As MyExtendedService

 'Use lazy initialization because this 
 ' class is rarely used and expensive to create.
 Public Shared ReadOnly Property Service1() As MyExtendedService
  Get
   If m_service1 Is Nothing Then
    m_service1 = MyExtendedService.GetInstance()
   End If
   Return m_service1
  End Get
 End Property

End Class
I mean, I really don't see the advantage of this pattern for my situation but maybe I'm missing something? Thanks in advance!

Monday, March 14, 2005

Can't we all just get along?

Here's a great post from Rick commenting on the absurd .NET language "war" that seems to be going on. It's not really a war, it's just a bunch of Microsoft platform developers bickering and wasting time. This is more ridiculous than the religious war of Java versus .NET. At least the argument with Java is an argument about an entire architecture - OS, Languages, and Tools. Who cares if you wrote your code in C# or VB.NET? It runs on the same damn framework! Like Rick, I come from a VFP background (talk about being neglected) so I'm not really bothered when someone tells me that VB.NET is not a "real" language because I know it is and they are probably just saying that because they don't have a date for Saturday night. Unlike Rick, however, I'm more comfortable with VB.NET because it just seems closer to the Fox programming style I've been used for so long. I think VB-only people are being too sensitive and C#-only people shouldn't knock a language just because it lets you do lose-typing (actually one of the things I like about VB, but that's another post), or isn't "pure" or whatever. Gimme a break. A business isn't going to care what language you program in, they care if the project is done on time, to spec, and works!

Things that make you go "hmmmm...."

I'm not sure if I like this car or not. My friends would either think I'm totally cool or a total weirdo... wait, they already think that.

Thursday, March 10, 2005

GOTCHA: Cancelling a control's validating event in MDI apps

Okay, this is the first time I ever noticed this one and I think it's either a bug or pretty damn retarded. Alright, say you have an MDI application with two child forms call 'em Form1 and Form2, each with a text box on them. You open the forms from your MDI container form like normal (probably from a Main Menu's click event):
Dim frm as New Form1
frm.MdiParent = Me
frm.Show()
Now on Form1, you are handling the TextBox1's validating event and are cancelling the event (probably based on some condition):
Private Sub TextBox1_Validating(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating

   'If some condition blah blah blah
   e.Cancel = True

End Sub
When you run your application, open Form1 and trigger the event, the focus remains in the TextBox1 as expected... until.....

Now you want to open Form2 while Form1 is still open (a perfectly valid use case for an MDI application). BUT, once Form2 opens, even though the form is activated, no control can receive focus on Form2. It basically renders Form2 useless and in a user's eyes it looks like the form is not responding. WHAT!? Why in the world is the Textbox1's Validating event being raised at all on Form1 once Form2 is active? This has got to be a bug or it is just plain retarded. I fail to see why you would ever want this behavior. This is not a problem if the application is not an MDI application. In that case the event will not be raised if the form is not active.

I can't figure out how to prevent the Validating event from being raised, however, I did find a work-around. You can use this check in the handler to avoid running your handler code:
Private Sub TextBox1_Validating(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles TextBox1.Validating

  If Me.MdiParent.ActiveMdiChild Is Me Then
   'If some condition blah blah blah
    e.Cancel = True
  End If

End Sub
This is moderately painful because I have to search my app for "_Validating" and add this line to all the handlers. If anyone's got a better idea I'm all ears.

The VB MVPs are pissed...

I happen to agree with Carl on this one, but I also don't have million line legacy applications to maintain either. If I did I'd probably kill myself. Fact is, all the things I love about programming come directly from learning something new and cool. I prefer to solve my business problems with the best solutions and right now that's VB.NET. Sorry.

Wednesday, February 23, 2005

What two Libras are thinking this week...

Julie and I must be on the same wavelength this week because I was thinking about making an MP3 player purchase soon too. I need one with a great car adapter because I listen to most of my music on the road.

Tuesday, February 22, 2005

I am free!

I just installed a new hard drive in my laptop and WOW.. I feel free again! You'd think I installed a new processor and another GIG of RAM! Nope. Just a new (faster, bigger) hard drive. My old drive scared me by coughing up the blue screen a couple times last week so I ordered a new drive from Dell and started the rebuild on Saturday. I think I have this baby back to a workable computer.... just found the sound drivers today so my speakers are working again. So the old drive is still booting up in safe mode so if I forgot anything I can always go back and get it if I really have to. Much better buying a new drive for $90 than to format your old one only to realize you forgot to copy over all your great grandmother's 120th birthday pictures which you have no backups for. My registry is clean and under a GIG so I'm cooking with gas now. VS even opens in less than 5 seconds... sweeeeeet.

Tuesday, February 08, 2005

ADO.NET Calculated DateTime Expression

In our business we store user entered time values as strings separate from the date. If you're doing the same thing, here's an example of how you can create a calculated column in a DataTable that merges the date and time so you can use it in your business functions a lot easier. This will work the same regardless of whether you're storing the time value as military time or AM/PM and handles null values.
Module Module1
 Sub Main()
   
   Dim dt As New DataTable
   
   dt.Columns.Add(New DataColumn("MyDate", GetType(Date)))
   dt.Columns.Add(New DataColumn("MyTime", GetType(String)))

   Dim expr As String = _
   "SUBSTRING(CONVERT(MyDate, 'System.String'),1,LEN(CONVERT(MyDate, 'System.String'))-11) + ' ' + ISNULL(MyTime,'')"

   dt.Columns.Add(New DataColumn("MyDateTime", GetType(Date), expr))

   For i As Integer = 1 To 10
      Dim dr As DataRow = dt.NewRow
      
      If i < 5 Then
         dr(0) = DateAdd(DateInterval.Day, i, Now)
         dr(1) = i.ToString + ":00 PM"
      Else
         dr(0) = DateAdd(DateInterval.Day, 0, Now)
         dr(1) = i.ToString + ":00 AM"
      End If
      
      dt.Rows.Add(dr)
   Next

   Dim dv As New DataView(dt)
   dv.Sort = "MyDateTime"
   
   Console.WriteLine(ViewToString(dv))
   Console.ReadLine()

 End Sub

 Public Function ViewToString(ByVal view As DataView) As String
   Dim sb As New Text.StringBuilder

   For i As Integer = 0 To view.Count - 1
      Dim row As DataRow = view(i).Row
      sb.Append("Row ")
      sb.Append(i.ToString)
      sb.Append(": ")
      sb.Append(RowToString(row))
   Next
   Return sb.ToString
 End Function

 Public Function RowToString(ByVal row As DataRow) As String
   Dim sb As New Text.StringBuilder
   sb.Append(vbCrLf)

   For Each dc As DataColumn In row.Table.Columns
      If Not row.RowState = DataRowState.Deleted Then
         sb.Append(StrDup(10, " "))
         sb.Append(LSet(dc.ColumnName, 20))
         sb.Append(" : ")
         If row(dc) Is System.DBNull.Value Then
            sb.Append("<null>")
         Else
            sb.Append(row(dc).ToString)
         End If
         sb.Append(vbCrLf)
      End If
   Next
   Return sb.ToString
 End Function
End Module

Monday, January 31, 2005

Mondays on Monday!

Tune in to A&E’s Caesar’s 24/7 on Monday night 10PM (check your local time) to see the cast from Mondays, (Carl Franklins, Rory Blyth, Nick Landry, and Geoff Maciolek) as Nick tries to pick up a woman in the bar at Caesars Palace.

Friday, January 21, 2005

Nice one, Messenger!


Somebody may want to think about some fricken custom errors! Guess I can forget about those live message alerts working...

You know you're coding too much when...

... when you try and "BUILD" a fricken Word document. I was like "What happened to my Build menu?" Whoops. I'm in Word. Just click the save button you idiot.

Friday, January 14, 2005

Live message alerts

Roy just added live message alerts to his blog and I wanted to be cool like him so I did it too. You can now sign up for alerts when this blog updates (see right-hand sidebar for the link or click here). This is handy if you're really really interested in what I have to say the minute I say it and you don't live in an RSS news reader all day. Not really sure who would subscribe... maybe I'll tell my mom.

Tuesday, January 11, 2005

Hung my diploma today...

I mentioned a few posts ago that I moved and as you know, if you've ever moved, it takes forever to get the little things unpacked and put in their correct place. I just hung my diploma on my office wall and I had a semi-proud moment. "Bachelor of Science in Computer Science and Minor in Mathematics" it reads. I'm pretty good at the computer dealio, but the math... can't say I remember calculus. I can't even balance my checkbook anymore :-/. OTOH, why would I need to? That's what online banking is for.

It's funny how I ended up in the business side of software. I remember (vaugely) all those baloney C++ assignments about calculating how many slices in a 14" pizza or writing a craps game my sophomore year. It didn't get interesting until my junior year when I transfered to a real university and started programming with cool graphics packages on sparc station 10's... which were totally expensive back then. Of course I had all the math down and when I graduated I applied at Lawrence Livermore National Laboratory for some geek-y C++ programming job.

Of course I didn't get the job because there were like 1000 applicants. So I took the summer off... practically. One August morning as I was heading out to the jacuzzi my mother found a job in the classifieds that read "Computer programmer. BS in CS required. No experience necessary." So I called, faxed my resume in (litteraly a half of a page) and got a call back for an interview. The company was a small healthcare software company nearby. I nailed the interview and was practiacally hired on the spot.

The first month was basically me learning Clipper (summer 87 -- the cool version). I was too afraid to tell them that I wasn't a CIS graduate and I had no idea what an IDX was so I took the Nantucket book home and learned all about relational database programming. I couldn't believe I spent all that time in college and none of it prepared me for writing business software products. However, within four months I had rewritten their internal office management system and they promoted me from junior programmer and gave me a $10K raise (which let me tell you was a shitload because I was still living at home and driving an 81 LeBaron). I realized that college taught me how to think about programming. Even though they didn't specifically teach me about databases, I gained the skill to be able to make sense out of any computer gobbely-gook. (Granted, later going from Clipper to FoxPro 2.0 was maybe like 5 syntactical differences, but still). But of course I still can't figure out what Math ever gave me.....

Friday, January 07, 2005

Disable Tabs on a TabControl

Here's a complete subclass of the TabControl that has disabled tab page functionality built in. When you set one of the contained tab pages' Enabled property to False, the tab will render in a disabled font color and will not allow the user to open the tab. This version of the tab control handles the EnabledChanged event of any of its contained tab pages and redraws the tab appropriately. Add this class to your toolbox, drop it on a form, add a few tabs like normal. If you want to disable a tab simply set the Enabled property to false in your code:
MyTabControl.TabPage2.Enabled = False
Here's the class:

Imports System.ComponentModel
Imports System.Drawing
Imports System.Windows.Forms

<ToolboxBitmap(GetType(TabControl))> _
Public Class BaseTabControl
  Inherits System.Windows.Forms.TabControl

#Region " Windows Form Designer generated code "

  Public Sub New()
    MyBase.New()

    'This call is required by the Windows Form Designer.
    InitializeComponent()

    'Add any initialization after the InitializeComponent() call
    Me.DrawMode = TabDrawMode.OwnerDrawFixed
  End Sub

  'BaseTabControl overrides dispose to clean up the component list.
  Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    If disposing Then
      If Not (components Is Nothing) Then
        components.Dispose()
      End If
    End If
    MyBase.Dispose(disposing)
  End Sub

  'Required by the Windows Form Designer
  Private components As System.ComponentModel.IContainer

  'NOTE: The following procedure is required by the Windows Form Designer
  'It can be modified using the Windows Form Designer. 
  'Do not modify it using the code editor.
  <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
  '
  End Sub

#End Region

#Region "--- Disabled Pages Functionality ---"

  Private Const WM_LBUTTONDOWN As Integer = &H201

  Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If m.Msg = WM_LBUTTONDOWN Then
      Dim pt As New Point(m.LParam.ToInt32)

      For i As Integer = 0 To Me.TabPages.Count - 1
        If Me.GetTabRect(i).Contains(pt) Then
          If Me.TabPages(i).Enabled Then
	    MyBase.WndProc(m) 
          End If
          Exit For
        End If
      Next
    Else
      MyBase.WndProc(m)
    End If
  End Sub

  Protected Overrides Sub OnKeyDown(ByVal ke As System.Windows.Forms.KeyEventArgs)
    If Me.Focused Then
      Dim selIndex As Integer = Me.SelectedIndex

      If ke.KeyCode = Keys.Left AndAlso Not ke.Control AndAlso Not ke.Alt Then
        For i As Integer = selIndex - 1 To 0 Step -1
          If Me.TabPages(i).Enabled Then
            Me.SelectedIndex = i
            Exit For
          End If
        Next
        ke.Handled = True
      ElseIf ke.KeyCode = Keys.Right AndAlso Not ke.Control AndAlso Not ke.Alt Then
        For i As Integer = selIndex + 1 To TabPages.Count - 1
          If Me.TabPages(i).Enabled Then
            Me.SelectedIndex = i
            Exit For
          End If
        Next
        ke.Handled = True
      End If
    End If
    MyBase.OnKeyDown(ke)
  End Sub

  Protected Overrides Sub OnDrawItem(ByVal e As System.Windows.Forms.DrawItemEventArgs)
    Dim leftImgOffset, topImgOffset As Integer
    Dim rBack As Rectangle
    Dim rText As RectangleF
    Dim img As Bitmap
    Dim format As New StringFormat
    Dim foreBrush As Brush
    Dim backBrush As New SolidBrush(Me.TabPages(e.Index).BackColor)

    If Me.TabPages(e.Index).Enabled Then
      foreBrush = New SolidBrush(Me.TabPages(e.Index).ForeColor)
    Else
      foreBrush = New SolidBrush(SystemColors.ControlDark)
    End If

    If Me.TabPages(e.Index).ImageIndex <> -1 Then
      img = CType(Me.ImageList.Images(Me.TabPages(e.Index).ImageIndex), Bitmap)
      rText = New RectangleF(e.Bounds.X + (img.Width \ 2), e.Bounds.Y, _
                             e.Bounds.Width, e.Bounds.Height)
    Else
      rText = New RectangleF(e.Bounds.X, e.Bounds.Y, _
                             e.Bounds.Width, e.Bounds.Height)
    End If

    If e.State = DrawItemState.Selected Then
      If e.Index = 0 Then
        rBack = New Rectangle(e.Bounds.X + 4, e.Bounds.Y, _
                              e.Bounds.Width - 4, e.Bounds.Height)
      Else
        rBack = e.Bounds
      End If

      e.Graphics.FillRectangle(backBrush, rBack)

      leftImgOffset = 6
      topImgOffset = 5
    Else
      leftImgOffset = 2
      topImgOffset = 2
    End If

    format.Alignment = StringAlignment.Center
    format.LineAlignment = StringAlignment.Center

    e.Graphics.DrawString(Me.TabPages(e.Index).Text, e.Font, foreBrush, rText, format)

    If Me.TabPages(e.Index).ImageIndex <> -1 Then
      Me.ImageList.Draw(e.Graphics, e.Bounds.X + leftImgOffset, _
                        e.Bounds.Top + topImgOffset, Me.TabPages(e.Index).ImageIndex)
    End If

    MyBase.OnDrawItem(e)
  End Sub

  Private Sub Tab_EnabledChanged(ByVal sender As Object, ByVal e As EventArgs)
    If TypeOf sender Is TabPage Then
      Me.Invalidate(Me.GetTabRect(DirectCast(sender, TabPage).TabIndex))
    End If
  End Sub

  Protected Overrides Sub OnControlAdded(ByVal e As System.Windows.Forms.ControlEventArgs)
    If TypeOf e.Control Is TabPage Then
      AddHandler e.Control.EnabledChanged, AddressOf Tab_EnabledChanged
    End If
    MyBase.OnControlAdded(e)
  End Sub

  Protected Overrides Sub OnControlRemoved(ByVal e As System.Windows.Forms.ControlEventArgs)
    If TypeOf e.Control Is TabPage Then
      RemoveHandler e.Control.EnabledChanged, AddressOf Tab_EnabledChanged
    End If
    MyBase.OnControlRemoved(e)
  End Sub

#End Region

End Class

Thursday, January 06, 2005

The Future of TV

I was talikng to Alan the other day about how it would be cool to have multiple signals per TV channel so that you could select your own camera angles durring a football game. Guess what? It's coming!

Tuesday, January 04, 2005

Happy New Year! Now get to work!

Well I'm back after an *awesome* winter break! (Even though I was back to work yesterday, I was overloaded with catch-up work and I just couldn't spare anytime to get a post out.) Okay what's new? Well, we bought a house and we moved in right before Christmas! This was good and bad timing. I had last week off so it was nice to not have to take regular vacation to get moved. On the other hand dealing with the banks, getting new carpet installed and scheduling a move in the rain is not my idea of fun and would have probably been easier to do in the spring or at least away from the holidays. I was a total stress case. Now I'm back to work and felling more relaxed believe it or not. I'm still dealing with a bunch of boxes and my whiteboard in my office is still on the floor, but at least the cable modem is working.