Monday, September 25, 2006

T.E.D.D.Y.

James sent me a link to a video demonstration of something called "T.E.D.D.Y." -- a simple 3D modeling program.

The link James sent me linked back to another blog that had found TEDDY, and that blog had a link to the original work, which can be found by clicking here.

Check out the video of TEDDY in action:



Wednesday, August 30, 2006

CheezLog

Hey, and old buddie of mine just started blogging. He's going to be getting himself up to speed with C#, and the XNA framework.

Since I don't have time to play with XNA myself, I hope to be able to live vicariously through his experiences. :)

Anyway, check out Cheez's blog:
CheezLog

Thursday, August 17, 2006

Classical Music Remixes

I'm in no way a music aficionado, and I have very specific likes and dislikes. Sometimes I like certain songs by a certain band, but really dislike the majority of other music in the same genre. It's weird.

One type of music I like almost 100% across the board is classical. I'm not a huge fan of overly-chamber-ish classical, and I don't really go outta my way to listen to classical. It's just decent background music. (No vocals == good background noise as far as I'm concerned.)

Now, remixed classical? I really like that. Check out this YouTube video for an example:



I'd really like to hear more remixes by this guy. Does anybody have any leads?


UPDATE: I found this YouTube vid because of digg.com, click here to digg-it. In the comments, someone has a link to JerryC's website. (I thought it was JerryL.). Anyway:

JerryC (mostly-English)

Collection of all his vides.

Wednesday, July 19, 2006

Debugging Threads In VS2005? Woe To Thee!

Ok folks, this is mostly a post for my own personal use. Basically, so the next time I run into the problem, I'll remember that I wrote this post. :)

While the title is misleading -- debugging in VS2005, especially debugging when debugging multithreaded apps. I've just ran into a problem though.

See, I'd set a breakpoint inside some code that's executing on another thread. When the breakpoint hits, VS2005 just sits there for about 10 seconds. It's like it's dead. Then, after it comes-to, if I try to step-through, or step-into any code after the breakpoint weird things happen. Like, it doesn't step-forward into the code. And while the IDE indicates the app is still in a 'paused' state, it certainly doesn't have any instruction pointer, nor does the "Threads" debugger panel indicate that your extra thread even exists anymore! Hitting "F5" and letting it go about it's business doesn't help either -- the app is now in some sort of voodoo-ized state.

The only solution is to stop the app and restart it.

This still doesn't help the fact that I can't debug any code running on a non-main/UI thread!


What to do?


Off to the MSDN forums for me!

Here's a post that helped me: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=285644&SiteID=1
That post links to this post:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=147707&SiteID=1
And that post links to this blog:
http://blogs.msdn.com/greggm/archive/2005/11/18/494648.aspx

Basically, what's happening is the debugger is trying to peek at all the local variables in order to 'help you' debug. Unfortunately, access the GUI objects created on the main/UI thread from another thread is bad juju, and the debugger hangs when it hits a breakpoint while trying to probe values from objects owned by the UI thread. Why it screws everything else up, I don't know.

BUT, I've come up with a solution not listed in the above links -- disable/close/don't-look-at the "Locals" debugging panel. If that panel isn't visible, the debugger won't waste time poking-n-prodding all the objects found in the current scope, and you'll avoid the problem entirely. :)

Tuesday, June 27, 2006

SQL MythBusters – MSDE/SQL Express has a 5 concurrent user limit

Having worked with various versions of MS SQL Server for a number of years now, (6.5, 7.0, 2000, 2005,) and the verious MSDE and 'Express' editions of the product, I found this following link interesting:

Euan Garden's BLOG : SQL MythBusters – MSDE/SQL Express has a 5 concurrent user limit

That '5 Concurrent User' limit has always been difficult to explain to our users...mostly because what we were explaining was never clearly explained to us... But anyway, I won't ramble on forever.

Wednesday, April 05, 2006

Monday, April 03, 2006

System.Runtime.Serialization.SerializationInfo -- .KeyExists()?

The Problem:

There are a number of collection-like objects in the .NET Framework that allow you to 'key' the data you enter into them. Dictionary<TKey,TValue> comes to mind almost immediately. Dictionary<TKey,TValue> contains a Dictionary<TKey,TValue>.ContainsKey(T key) method that makes key-existance determination trivial.

But what about the SerializationInfo object?

When an object implements ISerializable the ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) method adds the object's data to the serialization stream in a key/value style:

   info.AddValue("MyObjectsValueKey", this._MyValue);

Then, during deserialization, the constructor that meets the ISerializable implied-constructor signature:

   MyObject(SerializationInfo info, StreamingContext context)

is called, and the object is supposed to bootstrap itself from the data contained in the SerializationInfo instance.

How? By retrieving values based on the previously used string-keys, of course.

So, why isn't there a SerializationInfo.KeyExists(string key) method?

I hear some of you saying "Well, it's the serialization of an object, you had better know what's was serialized in the first place!" True, very true. But, consider a versioning issue that might arise:


Example (version 1):

Assume you have a business object that implements ISerializable. For this example, let's call that business object MyObject. In your first version of MyObject, you have some code that looks like this (large portions of code left out to save space):

[Serializable]
public sealed class MyObject : ISerializable {
private List<OtherObject> _OtherObjects;
private Int32 _CurrentOtherObjectIndex;

public OtherObject CurrentOtherObject {
get { return this._OtherObjects[_CurrentOtherObjectIndex]; }
set { this._CurrentOtherObjectIndex = this._OtherObjects.IndexOf(value); }
}


private const string OTHEROBJECTS_KEY = "___otherobjetskey___";
private const string INDEX_KEY = "___indexkey___";
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));
this._CurrentOtherObjectIndex = info.GetInt32(INDEX_KEY);
}

private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(INDEX_KEY, this._CurrentOtherObjectIndex);
}
}

As you can see, MyObject has an internal List<T> of OtherObject's. It exposes a property that returns whatever the 'current' OtherObject is, based upon a private index into the _MyOtherObjects List<T>.

The serialization code is fairly straight forward.

Now, let's say, somewhere in the development of the version 2, we find a bug related to _CurrentOtherObjectIndex not being updated properly when instances OtherObject are being inserted into the _OtherObjects List<T> at various locations, thereby possibly invalidating the OtherObject pointed to by _CurrentOtherObjectIndex.

Instead of updating the various code locations that would need to update _CurrentOtherObjectIndex we decide it would be better to just replace _CurrentOtherObjectIndex with an OtherObject instance. ie:

[Serializable]
public sealed class MyObject : ISerializable {
private List<OtherObject> _OtherObjects;
private OtherObject _CurrentOtherObject;

public OtherObject CurrentOtherObject {
get { return this._CurrentOtherObject; }
set { this._CurrentOtherObject = value; }
}
}

Ahhhh, but making this change would break the compatiblity between version 1 and version 2 of MyObject. Oh, but wait, we're handling the serialization ourselves, we should be able to code around it.
[Let's ignore any possible versioning issues involved with strong-naming, let's just assume the version 2 code tries to deserialize a version 1 MyObject.]

So, ideally, we could change the ISerializable implementation to look like this:

private const string OTHEROBJECTS_KEY = "___otherobjetskey___";
private const string INDEX_KEY = "___indexkey___"; // we need the v1 key
private const string CURRENTOTHEROBJECT_KEY = "___currentotherobjectkey___";
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));

if (info.ContainsKey(INDEX_KEY)) {
// we're deserializing a version-1 MyObject. Update it to version-2
Int32 tmpIndex = info.GetInt32(INDEX_KEY);
this._CurrentOtherObject = this._OtherObjects[tmpIndex];
} else {
// we're deserializing a version-2 MyObject. Just get the deserialize the CurrentOtherObject
this._CurrentOtherObject = (OtherObject)info.GetValue(CURRENTOTHEROBJECT_KEY, typeof(OtherObject));
}
}

private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(CURRENTOTHEROBJECT_KEY, this._CurrentOtherObject);
}

Unfortunately, we can't do this because there is no SerializationInfo.ContainsKey(string key) method! What we have to do is this:

private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));

try {
this._CurrentOtherObject = (OtherObject)info.GetValue(CURRENTOTHEROBJECT_KEY, typeof(OtherObject));
} catch (SerializationException) {
// we're deserializing a version-1 MyObject. Update it to version-2
Int32 tmpIndex = info.GetInt32(INDEX_KEY);
this._CurrentOtherObject = this._OtherObjects[tmpIndex];
}
}

We have to rely on an exception as part of our 'normal' code path. This feels 'icky' to me. ("Icky" being a highly technical term that means many things at different times. In this case, 'icky' means "goes against my 'best-practices' sense". Exceptions should be exactly that: an unexpected error condition. In the course of a normal deserialization, we have decided that being able to deserialize v1 MyObject instances into v2 MyObject instances is a completely normal operation. We should not have to rely on an Exception to perform normal work. And if we have a situation where v2 MyObject code may be deserializing a large amount of v1 MyObjects, we can expect it to be much slower as well because the Exception handling system carries a heavy tax.


One Possible Solution

One solution is to have any object that implements ISerializable also serialize some for of version information. Whether this version information is culled from the assembly versioning info, or is a private field of the class is completely up to your implementation. In the following modification to MyObject, MyObject will store it's own versioning information.

So, again from the top, version 1 of MyObject:

[Serializable]
public sealed class MyObject : ISerializable {
private static Int32 Version = 1;

private List<OtherObject> _OtherObjects;
private Int32 _CurrentOtherObjectIndex;

public OtherObject CurrentOtherObject {
get { return this._OtherObjects[_CurrentOtherObjectIndex]; }
set { this._CurrentOtherObjectIndex = this._OtherObjects.IndexOf(value); }
}


private const string VERSION_KEY = "___version___";
private const string OTHEROBJECTS_KEY = "___otherobjetskey___";
private const string INDEX_KEY = "___indexkey___";
private MyObject(SerializationInfo info, StreamingContext context) {
this._OtherObjects = (List<OtherObject>)info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>));

// version 1 doesn't care about the VERSION_KEY value because it is the first version
this._CurrentOtherObjectIndex = info.GetInt32(INDEX_KEY);
}

private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(VERSION_KEY, MyObject.Version);
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(INDEX_KEY, this._CurrentOtherObjectIndex);
}
}

And the updated version 2 of MyObject:

[Serializable]
public sealed class MyObject : ISerializable {
private static Int32 Version = 2;

private List<OtherObject> _OtherObjects;
private OtherObject _CurrentOtherObject;

public OtherObject CurrentOtherObject {
get { return this._CurrentOtherObject; }
set { this._CurrentOtherObject = value; }
}


private MyObject(SerializationInfo info, StreamingContext context) {
Int32 streamVersion = info.GetInt32(VERSION_KEY);

this._OtherObjects = (List<OtherObject>info.GetValue(OTHEROBJECTS_KEY, typeof(List<OtherObject>

if (streamVersion == 2) {
this._CurrentOtherObject = (OtherObject)info.GetValue(CURRENTOTHEROBJECT_KEY, typeof(OtherObject));
} else {
Int32 tmpIndex = info.GetInt32(INDEX_KEY);
this._CurrentOtherObject = this._OtherObjects[tmpIndex];
}
}

private void GetObjectData(SerializationInfo info, StreamingContext context) {
info.AddValue(VERSION_KEY, MyObject.Version);
info.AddValue(OTHEROBJECTS_KEY, this._OtherObjects);
info.AddValue(CURRENTOTHEROBJECT_KEY, this._CurrentOtherObject);
}

Tada. Clean, deterministic deserialization of version 1 and 2 MyObject instances.


Wrap-Up

So, does anyone out there know why there isn't a
SerializationInfo.ContainsKey(string key)
method? As with many things that I've learned about the .NET Framework, what at first seems obtuse to me usually has a very good explanation behind it.

I gotta give thanks to Mr. DotNet who has helpd me through those mentally-obtuse times. He really knows his stuff. I was hoping to be able to use his SyntaxHighlighter (*nudge*-*nudge*) to make my code a bit more readable. Maybe in a future update!


Technorati Tags: , , , ,

Friday, March 31, 2006

The Top 10 weirdest keyboards ever - Fosfor Gadgets

I know I've blogged about weird keyboards before, so why not again? :)

The Top 10 weirdest keyboards ever - Fosfor Gadgets

I think #6 looks interesting, and I wouldn't mind trying it once, but for normal use? No thanks.

A couple coworkers have bad wrist problems and have keyboard #8.


What am I using right now? A Microsoft Ergonomic 4000.
It's relatively similar to the original Microsoft Natural, but the key layout is slightly modified -- more relaxed I guess. I like the sexy-black color and the soft foamy wrist wrest. I'm not sure about all the extra buttons on the keyboard though. At least they're kept to a relative minimum, and are out of the way, on this keyboard.

Anyway....

Technorati Tags: , ,

Wednesday, March 29, 2006

Problem during ClickOnce deployment.

I just finished figuring out a problem I was having with a ClickOnce deployment for a project I've been working on.

This project has a reference to ADODB.dll -- a Primary Interop Reference provided by Microsoft in the .NET Framework SDK. Unfortunately, that PIA isn't provided in the .NET Framework redistributable. Also, unfortunately, setting the adodb.dll to copy-local during the project-build process didn't help during ClickOnce deployment -- the ADODB.dll was specified as needing to be installed into the GAC before my app would install.

I did some searching around, and stumbled upon this post as the MSDN ClickOnce forums:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=323832&SiteID=1

You can find my response there, but if you're averse to clicking, read-on.

Basically, the problem boils down to the default ClickOnce publishing behavior for the ADODB PIA. For whatever reason, it marks the ADODB PIA as a pre-requisite in the applications .manifest file. This means that ClickOnce requires the ADODB PIA to be installed into the GAC before it will allow my app to be installed. Unfortunately, none of the bootstrapper pre-reqs installed the PIA into the GAC, (making one of those pre-req bootstrapper installers is a possible solution, and I mention it in the reply, but it's not the easiest solution.)

What fixes is the problem is modifying the 'Publish Status' of the ADODB.dll
in the project's ClickOnce publishing settings. You change ADODB.dll's publish-status from the default "Include (Auto)" to "Include".

Yes.

Change it from one setting to another setting that appears to be the exact same setting.

Re-publish. The applications .manifest now specifies ADODB.dll to 'install' -- which will cause ClickOnce to copy it to the install folder, instead of requiring it be installed into the GAC.


Here's a couple screen shots for ya:

Bring up your Project Properties Page, and go to the Publish tab. Click the "Application Files..." button:

In the dialog that pops up, set ADODB.dll's Publish Status to Include:

Friday, October 21, 2005

Flickr: luminea's photos tagged with strobelab

High-speed camera + (Rose + Liquid Nitrogen) == Awesome.

Wednesday, September 07, 2005

Adam Nathan's Win32 to WinFX Blog : Windows Vista: It's the little things...

Adam Nathan's Win32 to WinFX Blog : Windows Vista: It's the little things...

Wow. I really like the second-to-the-bottom screen shot.

I don't know about you all, but I usually have so much crap in my Start menu that, even though I spend time organizing it, I have a heck of a time actually finding anything that I don't use on a daily basis. (And things that I use on a daily basis are copied into a taskbar toolbar, anyway...)

ANYWAY...

WinAmp 5.1 'Surround Edition'

I just grabbed the latest-n-greatest version of WinAmp because I heard a rumor that it has Podcast support somehow built into the Media Library.

I download it.

I install it.

I fire it up.

It has the usual 'WinAmp WINAMP winamp...it really WHIPS the llamas ass' sample MP3 queued up, as well as a second MP3 that came with the download.

I hit play. It plays, it whips the llama, and prompty crashes.

I fire WinAmp up a second time. Try it again. Yup. That MP3 kills winamp. How neat! I fire it up AGAIN and try playing the other MP3 -- as the song ends, it crashes WinAmp! Any song ending crashes WinAmp. How nice! :D

UPDATE:
I did a bit of searching, and discovered that I wasn't the only one with this problem!

Someone suggested disabling the new Predixis MusicMix (or whatever it's called) plugin. I disabled it, and tada! No crashing!

Bad Predixis plugin...BAD!

Wednesday, August 24, 2005

Turn Your Head

I have a distant interest in wood working. (ie: I really would like to get into it, but time spent on other hobbies, the money for tools and wood, life in general, etc -- it all prevents me from really getting into it.)

But anyway, the point of this post:
If I ever get a lathe, I really want to make something like this:
Turn Your Head. Really really cool.

Monday, August 22, 2005

August 18th's PvPOnline

Anybody else ever have a conversation like this?

I've had a couple... You guess which side of the conversation I'm on. ;)

Wednesday, August 17, 2005

Amazon.com: Books: Earthcore

I've recently finished listening to a free podcast audio book called Earthcore. It was long, but I loved it. The good news it that the author, Scott Sigler, got published! Actually, this book was going to get published once, but then got cut shortly after 9/11.

If you want to pre-order the book, grab it here:
Amazon.com: Books: Earthcore
I highly recommend this book.

Wednesday, July 27, 2005

Optimus keyboard

Optimus keyboard

Now this is a pretty cool keyboard! Every key is a tiny LCD screen, and you can display whatever you want on each key.

That's definitely geeky. But I've got a couple problems. I loves me my Microsoft Natural keyboard (the _ORIGINAL_, none of these new ones w/ screwed up arrow and insert/delete/pgup/pgdown key layouts, or with 30 extra shortcut buttons.) Why don't any of these cool keyboards that I'd actually want ever come in ergo-configurations? My only other problem with this keyboard would be that I know I wouldn't use the LCD keys for legit purposes. I'd end up with naughty pictures all over my keyboard or some other useless configuration. :)

Oh, I guess I implied that there are other 'cool' keyboards out there, eh? Here's a few, just from ThinkGeek:
Das Keyboard.
Maltron Super Ergo KB.
EluminX KB.
Rool-Up KB

and my favorite that I would LOVE to try for at least a month:
The TouchStream LP Zero-Force no-physical-keys, gesture-enabled/compatible keyboard. *drrooooool*

Wednesday, June 29, 2005

I bent my Whidbey!

Ok, this is weird. For friends / family who come here not knowing what "Whidbey" is, please, just move along.

So, I've been using Whidbey for a while now and I've never experienced anything as weird as I experienced today. I'm posting this to re-hash my experience, and hopefully find someone else who's experienced this problem, and maybe, just maybe have someone tell me why it happened.

First, some background on the project I'm working on. This project requires the implementation of two seperate but very similar and intertwined, applications. Because of the shared elements, I felt it best to create a Solution consisting of three projects -- two main Windows Forms projects and a common Class Library project. The mains reference the common project and use the helper methods, 'middle-tier' business objects, common tool form windows, project-property dialogs, etc, that the common project serves-up.

At some point I guess I did something wrong this morning because I opened a code view, and I could type characters and numbers, but I couldn't press enter, backspace, delete, or the arrow keys. It's almost as if any key that wasn't an [a-zA-Z0-9] key was just discarded by the IDE. I could highlight code and copy/cut/paste from the right-click context menu, but I couldn't use the ctrl-[cxp] shortcut keys to do the same thing. I also noticed that when I was typing, Intellisense wasn't poping up.

Ok. . . Weird.

I tried many things.

  • Closed all open files -- nope.

  • Checked everything into Source Safe, then back out -- nope.

  • Closed the solution, and closed VS2005, and opened it back up -- nope.

  • Rebooted my PC -- nope.

  • Deleted the bin and obj directories from my 3 project directories and re-opened the solution -- nope.

  • Reset all VS keyboard shortcut customizations -- nope.

  • Rebuilt a 'clean' copy of the solution from Source Safe -- nope.

  • Opened VS2005, created a dummy project -- NO PROBLEMS!.
    ("Ok, so it seems like it's something with my solution." I thought.)

  • Opened a different, pre-existing, previously known-to-be-working project -- NO PROBLEMS!.
    ("Yup...it's definately something with my solution.")


I'd almost run out of options (I really didn't want to try the uninstall/reinstall 'option',) when it became crystal-clear that it was something in my solution that was causing the problem...but what? There were no build errors, the application ran, and I can seemingly view all designers and code windows, I just couldn't edit code!

So, how did I 'fix' it? I'm not sure if I fixed it, or if it fixed itself, but here's what I did:

  • Fired up my 'broken' solution

  • Confirmed that, yes, it was still broken.

  • File->New->Project. Created another junk project/solution. (ie: I never closed Visual Studio.)

  • Confirmed that, yes, in this junk project/solution, there were no problems with the code editor -- Intellisense was working, and so was enter/delete/backspace.

  • File->Recent Projects->MyBroken.sln to re-open my 'broken' Solution.

  • The Code Editor Worked.



- W - T - F -???

What was I doing before it 'broke'? Well, to tell you that, you need a little more background info.

Remember that the main form in the main projects use tool windows provided by the common project. As such, I wanted a way to handle any exceptions that might happen in the tool windows in my main projects. (ie: The main projects have 'centralized' exception displaying/logging, and I want exceptions that happen in the tool windows (provided by common,) to basically pass the exception to it's parent form for user-notification and logging.) To facilitate this, in the common project, I made a simple derived class that looked something like this:


public abstract class MySpecialForm : System.Windows.Forms.Form {
protected virtual void ExceptionHandlerCORE(Exception ex, string logfile) {
...
}

public virtual void ExceptionHandler(Exception ex) {
...
}
}


Then, in the main project, it's main form is derived from MySpecialForm. It overloads the ExceptionHandler method, calling base.ExceptionHandlerCORE(...), passing in a user-specific logfile.

This solves my requirement of having the common tool windows 'report' exceptions back to their owner form. All these tool windows need to do is something like this:


try {
// something that throws an error
} catch (System.Exception ex) {
MySpecialForm owner = (MySpecialForm)this.Owner;
owner.ExceptionHandler(ex);
}


At this point I hear some of you guys hollaring: "You're MySpecialForm, it can't be declared abstract if you ever expect to use it in the Visual Studio Designer!" You're exactly right! It was with the discovery of this little fact that the IDE started acting weird, and the Code Editor decided to start acting up on me.

I tried opening the main project's main form, and instead of getting my form, I get a page telling me that MySpecialForm is declared abstract, and I can't work in the Designer because of that. Oookay. I closed the designer, went and modifed MySpecialForm so it wasn't abstract, rebuilt the Common project, tried re-opening the main project's form in the designer, but nope. The same error. *sigh* Stupid thing isn't seeing my recompiled common. I rebuilt the entire solution, which in the past has fixed problems where the main projects couldn't 'see' the recompiled changes in their referenced common assembly. I even tried removing and re-adding the reference to the compiled common assembly -- the error persisted. It was some where around that time that the Code Editor started acting wonky -- I think I closed/restarted Visual Studio in an effort to try and get main to refresh it's references, and then the weirdness in the code editor began.

And with that...I'm out. I've got to thank my friend Mr .NET for helping me try to figure this out. I've also got to chastize him for not knowing the answer! heh.

With that, I leave the floor open. Someone tell me they've seen this before!

Thursday, February 10, 2005

Snap-Crackle-Pop (NOT) Rice Crispies!

Well, I finally broke down and went and saw a chiropractor.

For over a week now, just sitting here working all day has caused the musles in the back of my neck to knot up tight/stiff, along with the occasional burning sensation. It was driving me nuts. It was giving me the worst headaches. With the family sinus problems, I'm no stranger to sinus headaches, and these aren't sinus headaches. Almost migraine like. Quite literally a pain in the neck/head.

Usually, when I have a bad headache of any sort, and the meds just aren't helping much, I always get relief from a good nights sleep.

Not anymore.

In fact, seemingly by the luck of the draw, I could wake up with a sore neck, and a fresh headache starting to soak itself in. Heather suggested I either go to the doctor, or "Doctor Dave" (the local chiropractor that everyone swears by.) Well, Doctor Dave wouldn't take a new patient, so I went to this Doc. Peterson, Chiro-back-crack-ologist and Nutritionalist.

Well, he snap-crackle-popped me, and TADA! I feel a bit better! There's inflamation in the joints (that was there BEFORE the rice-crispy-action,) that will take some time, and ice, to settle down, but for now, I'm feeling a ton better! WOOO!

Thursday, January 27, 2005

Guiness Book of World Records

So, according to this article in the campus news paper, MTU has set a record for for the world's biggest pendulum...104 years after making the actual pendulum.

Huh. Weird.

From the sounds of it, it's purpose was basically a depth-o-meter, if there is such a thing.

Monday, January 24, 2005

Is It Monday Already?

*yaaaaaawwwn*

Wow, it's Monday already, and I'm sitting here at work, sipping a cup of coffee, trying to get caught up on email, news, and get some coding done. BUT, before that, a quit entry. This weekend seemed like it went non-stop!

Saturday, I woke up all geared-up and ready to brew a batch of beer. I had the idea of waking up 'early' (8/9am,) and getting the brewing done quickly, but as Heather will attest, I say that I'd like to wake up on many brew days. That bed is just far too comfortable to wake up early. :)

We finally all did wake up around 10-ish. Breakfast was had. Coffee was brewed, and drank. I got garbed-up, and went wading through the snow banks in order to drag wood from the pile to the basement. Fires flamed, the house was warmed. Noon rolled by, and I decided I needed to get moving if this beer was ever going to get brewed! I fired up the computer and started doing the final calculations for the recipe.

See, I was originally going to brew a 5+/- gallon batch of brown ale. Err, 'nut brown ale' you call it because I guess calling something a 'brown ale' just sounds like you're brewing a poop-brew. ) My recipe, as I brewed it, isn't available online (yet.) You can find the original recipe I based my recipe upon here. (Basically, I just converted it to all-grain, and swapped a little of the Special-B Malt for Dark (135-165L) Crystal Malt.)

ANYWAY, I _WAS_ going to brew a 5-ish gallon batch. Well, I had a really good yeast culture going of White Labs WLP023 - Burton Ale Yeast that I got from a friend (thanks, Randy!) It's a surprisingly good yeast that I'd brewed with once before that has a really great 'English' character, and as that White Labs page will attest, is well-suited for an English-style brown ale. The thing is, I also had 'rescued' a yeast culture that I put away over a year ago of White Labs WLP001 - California Ale Yeast. Just about any brewer who's worth his salt has used this yeast at least once. It's _the_ 'American' yeast. Clean, crisp, and unlike an English yeast, it's really quite 'clean' for an ale yeast -- very little fruity esters. It accentuates (big word for the day...had to look up how to spell it,) the hops and grains instead of masks them under the yeast characteristics. CRAP Can I actually get to the point? I'll try. So, this yeast that I was sure was dead, came back to life! The starter culture smelled and tasted clean, surprisingly no infection that I could detect, so I just had to use it. So, my point that I was trying to get at? I decided to brew an 8+ gallon batch, and split the batch among the two yeasts, so I needed to scale the recipe up before actually getting started.

While I was deftly tacking away at the keyboard, Heather was getting a grocery list made up. A pretty big one too! It was somewhere in the middle of this that I realized I didn't have Fuggles hops! I was sure I had them. I dug through the freezer upstairs, and the freezer downstairs. No Fuggles hops. CRAP.

"Ok, this isn't a problem, Heather's going into town, I'll go with, pick up the hops I need, no problem!" Except in the back of my head I knew I was already resigning the brew to another day.

With a grocery list like the one Heather had in hand, this wasn't going to be a quick into-town-and-back-home joy ride. Really, the list didn't have that many things on it, but it included at least four separate stops at different stores. That's a pretty good days worth of shopping, and anyone who has/has-had a baby knows it's going to be an even-longer day. And you know how it is when you get into the store: you're going to browse and if you're in a hurry, every obstacle will be in your way. Friends you haven't seen in a while? "Hello!" Long lines? Yup. By the time we got out of Wally-World I was sure I wasn't brewing on Saturday.

I don't think we actually hit the road until about 1:30. I think we got home some time around 6:30, 7:00. Yeesh. But hey! I got a new pair of jeans out of it, and if you know how often I buy new clothes, that's a pretty big deal! Instead of piddling away the rest of the evening, after dinner I got my grain mill, and scale, and went to work on measuring out my grains and crushing them so I wouldn't have to spend the extra time in the morning.

You know what's awesome? Hooking your 14v cordless drill to your grain mill! Holy crap! I can grind grain in no time flat! It's amazing!


Well, anyway, Sunday rolls around. Noah and I wake up, and make breakfast for all three of us. While breakfast is getting prepared, I put my mash water (about 5 gallons) on the stove to heat up. By the time breakfast was done, the mash water is ready, and I mash-in. I decided to try mashing in my 10 gallon GOTT cooler that I picked up at a garage sale this year. This cooler is AWESOME! After an hour-long mash, I was surprised to see that the mash hadn't dropped a single degree! Very cool.

Anyway, to wrap things up....the rest of the brew day was typical, the sparge went fine, the boil went fine, and I ended up with two carboys with about 4.5 gallons of wort in each. I checked this morning on my way to work and both carboys are burpling away like a happy wort-becoming-beer should.

Anyway...I need to get going. I guess I could talk about putting together the treadmill, or the fun I had with Heather and Noah, but yeesh, this post is long enough! I'll talk about that in another post. :)