BibleGateway.com Verse Of The Day

Thursday, May 17, 2007

My Ruby Dilemna

To Ruby or not to Ruby?

I looked at Ruby a while back, maybe 2004/5-ish, when it was just starting to make a buzz. It seemed interesting because it was an object oriented scripting language. Loosely typed, to-the-point syntax, etc. I liked the concept, but ultimately I couldn't find a use for it to get me off the ground. When I really needed a shell script, it was quicker to just use ksh or bash and the standard array of unix utilities--awk, sed, cut, grep, etc.

Spare time is precious, and there are a lot of things besides programming to fill it with. And how often do you really get time at work to sit down and learn a new technology, pure R&D and personal development type stuff?

And if I do sit down to learn something new, should I really be spending time on a "toy" like Ruby when I could be brushing up on new Java stuff? Afterall, Java/J2EE are paying the bills, so shouldn't I be the best Java guy I can be, instead of dabbling in flavor-of-the-month technologies?

Then I saw a demo for Ruby on Rails. Wow, that blows the mind of a STRUTS/JSP/Servlet kinds of guy like me. It looks so cool, so fast, so easy, can it really be like the demo? It sparked my interest, but again, the buzz was that this was more of a "toy" than a real enterprise alternative, and lots of negative press was spent decrying lack of security and scalability, blah blah blah. Short attention span, drifting off, blah blah blah.

So now a friend of mine is diving head first into Ruby on Rails along with a few of his friends at work. His genuine enthusiasm has piqued my interest for a 3rd time. He is enthusiastic without being one of those zealots that are screaming loudly about how Ruby is going to kill Java or kill .Net or kill Python or whatever. No languages have to die here, people, it's just one more tool in the toolbox -- do you throw away your drill when you buy a new hammer?

And after all this time, Ruby is still out there and gaining support, so I can't really label it "flavor-of-the-month" or "toy" anymore. To be honest, I thought the same thing about Java back in '96/'97-ish when it was just being used to write applets embedded in HTML pages. I dabbled with some Java, but as a C/SQL/Motif programmer, Java seemed completely useless for real apps. I wasn't convinced until I saw the proof-of-concept office suite Corel wrote in Java -- whoa, real applications like drawing and word processing and spreadsheets running in a graphics "desktop" with icons and stuff! Now I write Java every day. So given that my judgement on this sort of thing sucks goat, I think Ruby, esp. Ruby on Rails, deserves another, more serious, look.

Using the instructions on this link, I was able to use Ruby GEMS to download and install Rails. Then a few commands and I got my sample skeleton project up and running. About 20 minutes worth of "work" while I sit here trying to figure out a production support issue for work. And here it is, my local server running my skeleton project....

And now, some links.....

Ruby Programming Language

Ruby On Rails

Ruby in 20 Minutes tutorial

Learning Ruby by comparing to languages you already know

More Ruby documentation

RDT Ruby IDE plugin for Eclipse

Why's Poignant Guide To Ruby

Using Oracle with Ruby

Wednesday, May 16, 2007

Mini KISS

Couple of friends saw these guys playing at the JavaOne After Dark bash. It's at once disturbing and intriguing at the same time. Mini KISS is a KISS tribute band made up of midgets, er, little people, or whatever they like to be called nowadays.

http://www.minikissonline.com/

Tuesday, May 15, 2007

Freaky Word Tricks For Your Shriveled Little Mind

An interesting email I got recently. Must be some amount of truth to it because I could read it without much difficulty...


Only great minds can read this


This is weird, but interesting!

fi yuo cna raed tihs, yuo hvae a sgtrane mnid too
Cna yuo raed tihs? Olny 55 plepoe out of 100 can.
i cdnuolt blveiee taht I cluod aulaclty uesdnatnrd waht I was rdanieg. The phaonmneal pweor of the hmuan mnid, aoccdrnig to a rscheearch at Cmabrigde Uinervtisy, it dseno't mtaetr in waht oerdr the ltteres in a wrod are, the olny iproamtnt tihng is taht the frsit and lsat ltteer be in the rghit pclae. The rset can be a taotl mses and you can sitll raed it whotuit a pboerlm. Tihs is bcuseae the huamn mnid deos not raed ervey lteter by istlef, but the wrod as a wlohe. Azanmig huh? yaeh and I awlyas tghuhot slpeling was ipmorantt! if you can raed tihs forwrad it

FORWARD ONLY IF YOU CAN READ IT.

Monday, May 14, 2007

More Chicken Pictures

The chickens have more than tripled in size since we got them a few weeks ago.

The buff orpington's seem to be the beefiest of them all right now, and a few of the reds are still kind of scrawny looking. They are all almost fully feathered out now, though -- with just their undersides and necks looking downy now.

I picked one up the other day and could not believe how thick the legs are already. These things went from fluffy little balls to something that resembles actual chickens now. Every day I go back there I notice a difference. I think if I just sat back there in the coop, I would actually see them grow. Well, maybe not.

Friday, May 11, 2007

I've Got Some Time

I've been increasingly paranoid about not having time to build my nest boxes for the chickens. So I asked myself, "self, how early do chickens start laying eggs?"

And when I had no answers, I asked Google instead. According to the Murray McMurray hatchery site, this is the answer:

"Most hens will start laying between 5-7 months of age. They will lay best at 1 to 2 years of age. All pullets (female chicken under 1 year of age) lay small eggs at first and after a while will lay larger eggs. Younger hens will lay 1 egg every 3-4 days. A hen 30 weeks old can lay 2 eggs every 3 days. Some have been known to lay an egg a day. All breeds have different laying abilities."
So I have a little time before I really need to panic. They are getting pretty big though, and when I fed them this morning, one of them was actually up on the perch. They are almost fully feathered out now as well. By the end of May we should be grillin' up our first chickens.

MMMmmmm, chickens!

Thursday, May 10, 2007

9 Week Old Lexi

This is what Lexi, our Wheaten Terrier, looks like at about 9 weeks old. Chewing on a toy. Play! Play! Play! Crash and sleep! Repeat.....

Wednesday, May 09, 2007

Bear Kills Moose in Alaska Driveway as Residents Watch

Bear Kills Moose in Alaska Driveway as Residents Watch
FOX News

I've seen stray cats hunting for mice in my driveway, but never anything as exciting as a brown bear killing a moose. If I had been in this situation, I probably would have grabbed the camera AFTER grabbing my rifle and skinning knife.

Click on the URL below for the rest of this story:
http://www.foxnews.com/story/0,2933,270936,00.html

Monday, May 07, 2007

Winchester 1300 - Possible Issue Shooting Slugs?

My father just bought the rifled slug barrel for his Winchester 1300 12 gauge, and brought it up this weekend to try it out. I gave him a couple of my Lightfield Hybrid EXP sabot slugs to shoot through it, and the when he fired, the action came all the way open and ejected the shell without any intervention.

He thought maybe he was inadvertently pulling the slide open because he wasn't expecting that much recoil, so I tried it. I rested the gun over the "V" of my pointer finger and thumb, not holding the forestock at all. The action came all the way open and ejected the spent casing for me as well.

Now we aren't sure if the barrel is keeping the bolt from fully locking properly, or if this is a side effect of the Winchester "Speed Pump" feature (I never really knew what that feature was supposed to do anyways), or if it is a matter of too much shell for the gun to handle?

Each shot was dead accurate at about 70 yards, and it didn't seem to be an "unsafe" condition as it was firing accurately and ejecting the spent casing, but it could definitely catch you off guard in a hunting situation if you are used to doing all the work of pumping a new round in.

I've fired everything from light target loads to heavy 3" magnum turkey and goose loads to rifled slugs through my Mossberg 500 and never had this happen, so I can't image a 2-3/4 slug being too much for a 1300 to handle.

My initial research on the web found another guy in a forum that this happened to, but haven't been able to find too much more info on it. I'll have to keep looking, and in the meantime he was going to have a gunsmith look at it to see if there is an issue with the bolt locking mechanism.

Thursday, May 03, 2007

Lexi Is OURS!!! HAHAHA

We picked her up Tuesday evening because the breeder was going to be out of town delivering a few puppies on Wednesday (a few hours early, yeah!). We'll have to post more pictures when we get a chance. She does a lot of hyper play-play-playing, followed immediately by crashing into a sleep. That's what puppies do.

Monday, April 30, 2007

2 More Days And Lexi Is Ours!

Here she is, at almost 8 weeks old. She turns 8 weeks Wednesday, May 2, so we can pick her up then.

Sunday, April 29, 2007

The Chickens Are Home

Today I put the finishing touches on the chicken run. Paula cleaned out the building that will serve as the coop while I finished putting the gate on. We put the perch in there, carried the chickens outside in laundry baskets, and hung up the brooder heat lamp. I got bigger feeder and waterer and set those up, and Paula went and got more corncob bedding to put down on the floor. So the chickens our our of our home and into their home.

And it was about time. They got to the point where they could fly out of the wading pool even with the 12" cardboard walls surrounding it. This morning one of them was running around the living room chirping because it was lost and couldn't get back in the pool. Later in the morning I saw a couple of them fly out when they got excited about something. They also started to do a little picking on one of the Buff Orpingtons, which meant it was time for them to get more space per bird.

Of course, now that they have so much more room, I went out to take pictures and they are all huddled together in the corner. When we got home from dinner, I peeked in the side window and they were all laying down right under the brooder lamp. But they have the space if they need it, so I feel better. And they aren't running around in my living room, so my wife feels better.

By the end of May they should be right about eatin' size, and it will be time to fire up the grill and have some friends over. Nice and fresh.

I still need to build or buy nest boxes, but I should have a few weeks before they get to that point, so it isn't an emergency yet.

Tuesday, April 24, 2007

More Puppy Pix 4/24

More pictures of the Wheaten puppies.
We get to pick ours up May 2!!

Thursday, April 19, 2007

The Other Chick - A Mystery!

This is the extra chick we got with our order from Murray. Still not sure what kind of chicken it is. Once the wing feathers start coming in more it should be a lot easier to tell, or I could just wait until it's fully grown.

Wednesday, April 18, 2007

Go Ahead And Make Yourself At Home

These 3 deer were among the 7 that visited our feeder the other day. It's not all that uncommon for them to be in our yard with the apple trees and the fact that we back up to an abandoned apple orchard. It's not even uncommon for them to poke their noses in the squirrel feeder and eat out of there. But this particular deer decided to make herself right at home and just layed down right smack dab in the middle of our yard.

Obviously she doesn't know who lives here. Hard to not think of a full freezer with scenes like this.

Who Says Programmers Can't Get Chicks?


Here's a close up of a Rhode Island Red chick, about 5 days old, sitting on my kitchen table.

Tuesday, April 17, 2007

The Chicks Have Arrived

The chicks have arrived! I finally got to bed around 6am after working on that file upload all night, and drifted off to sleep around 6:20 -- just in time for my cell phone to ring at 6:30. I jumped up and answered assuming it was work calling about the failed upload, but it was the post office letting me know the chickens have arrived. I rolled over andwent back to sleep for a few hours, then picked them up around lunch time. One had died in transit, but there were still 26 birds in there, so they must have put in 2 extra instead of just the one extra. We got 5 Buff Orpington roosters, 20 Rhode Island Red straight-run (as they hatch, no sexing), plus the one "exotic" chick Murray McMurray throws in for free. It is black with a stripe, so not sure what kind it is yet. Looking through the catalog it could be any number of breeds -- we'll see once it gets bigger.

We have our old kiddie pool set up in the back living room for them right now. We got the starter kit from Murray McMurray that has the cardboard draft shield, brooder lamp and red heat bulb, thermometer, 2 waterers, and 2 feeders. It seemed like a good deal versus buying all the individual pieces separately.

Right now our house if full of the CHEEP CHEEP CHEEP of 26 baby chickens. The girls think they are so cute and wanted to know what we would name them. Our answer of course NO NAMES, these are LIVESTOCK not PETS!

The dog on the other hand is a pet, she will have a name (Lexi -- we picked her out last night, and get to bring her home in a few more weeks) -- we won't eat the dog! Try to explain that to a 2 and 3 year old and it suddenly becomes clear how arbitrary the whole thing is -- how certain animals can share our homes as pets (dogs, cats, guinea pigs), other animals get killed for sharing our homes without asking (mice, rats, moles), and other animals get raised solely to eat (chickens, cows, pigs).


Thursday, April 12, 2007

Working With Velocity Templates

I used Velocity as the templating engine for my persistence code generator project. It is really simple and clean to set up and use, which is refreshing compared to a lot of the Apache projects which are obtuse and over-abstracted for the sake of inflating programmer's egos.

Why use Velocity? I use it for code generation -- connect to a database, get the meta data, and generate the DAO, VO, and DaoFactory Java classes to work with that database. But you could use it to generate any sort of text, whether it is HTML, JSP, ASP, emails, documentation, source code, etc.


Below is a very simple stub to show how easy it is to work with Velocity. This is the bare minimum Java code you need to merge your data into a template and generate an output file. Of course, you would have more than one bind variable in the context would probably have to deal with more complex data structures, but this gives you the basics...


import java.io.File;
import java.io.FileWriter;
import java.util.Properties;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;

public class VelocityExample
{

public void execute() throws Exception
{
//Set up Velocity engine and context
Properties p = new Properties();
VelocityEngine ve = new VelocityEngine();
VelocityContext vctx = new VelocityContext();

p.setProperty("file.resource.loader.path", "/path/to/your/velocity/templates");
ve.init(p);

// put any number of properties in the context. These are
// used as bind vars in the Velocity template. For example
// In template any instance of ${someProperty} will be replaced
// with someValue.
vctx.put("voClassName", "ExampleVo");

// Get your template
Template templ = ve.getTemplate("YourTemplate.vm");
// and a writer to new file to be generated
FileWriter writer = new FileWriter("/path/and/filename/of/generatedfile");

// merge template with context and write to your output file
templ.merge(vctx, writer);
writer.flush();
writer.close();
}
}


Ok, so that's the code, what does the template look like? Below is the template I use to generate VO's (or DTO's) -- a class with properties and getters/setters methods for each property.

Notice is looks a lot like a Java class already, except for all those pesky $var's and #directives. Anything you put in the velocity context is available from the template. You reference the properties using $property or ${property}, and if it is a complex type you can reference fields using dot notation like ${property.name}, or loop through List's and arrays using #foreach directives.


// ====================================================================
// DO NOT EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED BY DAO-GEN.
// YOUR CHANGES WILL BE LOST NEXT TIME THE CODE IS GENERATED!
// ====================================================================

package ${voPackageName};

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import java.sql.Date;
import java.sql.Timestamp;


/**
* @author DaoGen
* @version cvs: $Id: VoTemplate.vm,v 1.2 2006/12/12 20:13:23 ran488 Exp $
*/
public class ${voClassName}
extends BaseVo
implements Serializable
{

#foreach( $field in $persistableFields )
/** $field.colName */
private $field.javaType $field.jFieldName ;

#end


/** Constructor */
public ${voClassName}()
{
super();
}


// Getters and Setters
#foreach( $field in $persistableFields )


/**
* Setter for DB column $field.colName
* @return void
* @param $field.typeName
*/
public void set${field.jProperFieldName}( $field.javaType $field.jFieldName )
{
this.${field.jFieldName} = $field.jFieldName;
}


/**
* Getter for DB column $field.colName
* @return value
*/
public $field.javaType get${field.jProperFieldName}()
{
return this.${field.jFieldName};
}
#end
}




For a more real-world example of the Java code, here is the method I use to generate the VO from the above example. This method actually generates the DAO implementation and interface and the VO for each table in a database.



/**
* @param db
* @param basePath
* @param ve
* @param vctx
* @throws ResourceNotFoundException
* @throws ParseErrorException
* @throws Exception
* @throws IOException
* @throws MethodInvocationException
*/
private void generateTablePersistentObjects(Database db, String basePath, VelocityEngine ve, VelocityContext vctx) throws ResourceNotFoundException, ParseErrorException, Exception, IOException, MethodInvocationException
{
Template voTempl = null;
Template daoIntfcTempl = null;
Template daoImplTempl = null;
voTempl = ve.getTemplate("VoTemplate.vm");
daoIntfcTempl = ve.getTemplate("DaoTemplate.vm");
daoImplTempl = ve.getTemplate("DaoImplTemplate.vm");

// The MEAT and POTATOES
for (Table table : db.getTables())
{
// put everything from table into Velocity context
vctx.put("voClassName", table.getJProperFieldName() + "Vo");
vctx.put("daoImplClassName", table.getJProperFieldName() + "DaoImpl");
vctx.put("daoInterfaceName", table.getJProperFieldName() + "Dao");
vctx.put("dbTableName", table.getTableName());
vctx.put("javaTableName", table.getTableName());
vctx.put("persistableFields", table.getColumns());
vctx.put("primaryKeyFields", table.getPrimaryKeys());
vctx.put("schema", table.getTableSchema());
vctx.put("tableType", table.getTableType());
vctx.put("numPkFields", table.getPrimaryKeys().size());

FileWriter voWriter = new FileWriter(basePath+"vo"+File.separator+table.getJProperFieldName()+"Vo.java");
voTempl.merge(vctx, voWriter);
voWriter.flush();
voWriter.close();

FileWriter daoIntfcWriter = new FileWriter(basePath+"dao"+File.separator+table.getJProperFieldName()+"Dao.java");
daoIntfcTempl.merge(vctx,daoIntfcWriter);
daoIntfcWriter.flush();
daoIntfcWriter.close();

FileWriter daoImplWriter = new FileWriter(basePath+"dao"+File.separator+table.getJProperFieldName()+"DaoImpl.java");
daoImplTempl.merge(vctx,daoImplWriter);
daoImplWriter.flush();
daoImplWriter.close();
}
}


For more info check out http://velocity.apache.org/

There is also an Eclipse plugin for the templates at http://veloedit.sourceforge.net/.

Monday, April 09, 2007

More Puppy Pix

We went to see the Wheaton Terrier puppies again last Thursday. A few of the pictures are here....http://www.frontiernet.net/~nicholson150/puppies.html They are up and playing now, pushing each other around, wrestling, barking at each other.

Tuesday, April 03, 2007

K&N Performance Air Filter Kits

I was wondering what the difference between the FIPK eries 57) kit and the "Performance" Series 77 kit was, other than the 77 kit being chrome instead of plastic. My assumption was the new 77 was supposed to be higher performance as well, but I was wrong.

According to the K&N website, the series 57 kits gives an extra 10.49 horsepower for the 5.7L HEMI, while the 77 only gives 8.34 HP (dyno chart), and the 57 seems to be more consistent boost across the RPM range.

FIPK Installation Instructions for 5.7L HEMI V8.

Monday, April 02, 2007

More Puppy Pictures

The Wheaten Terrier puppies at about 3-1/2 weeks....



Thursday, March 29, 2007

ETA On Chickens: 4/16

I just ordered my chickens, and they should arrive the week of April 16th. Got them from Murray McMurray hatchery via internet. They will be shipped out as day old chicks, ready to go, so I just need ot pick them up at the post office as soon as they arrive. We got a striaght run of 20 Rhode Island Reds, 5 Buff Orpington roosters, plus whatever the extra free "exotic" chick is they put in there with them.

I also ordered the starter kit (brooding lamp, waterers, feeders, etc) from them earlier today. So now the dream of rasining chickens is reality, no turning back.

Fire up the barbeque!

Wednesday, March 28, 2007

Chicken Perch Finished


Tonight I finally finished building the perch for our chickens. Here is a picture of the finished product. Actually not completely done, as I would like to sand the actual perches a bit better and maybe hit the whole thing with a coat of paint or stain.

Now I just need to build the nest boxes, fix the roofing, fence in the run area, and purchase the chickens along with some supplies like feeders and waterers, food, grit, etc.

Tuesday, March 27, 2007

A Big Day

We had a big day yesterday. I came home from work and Paula had a pan of homemade macaroni and cheese in the oven.

And my new tonneau cover was on the porch, freshly delivered from Amazon.com. I got the Lund Genesis Tri-Fold and it really was about a 5 minute install, no exaggeration. Line it up at front of bed, clamp down the front, unbuckle the mid section and unfold. Clamp down two rear clamps. Done. Took longer to pull into the barn (all the while tearing up my very wet lawn with my very big and heavy truck tires).

Then we packed up the kids and went out to look at some puppies. We ended up putting down a deposit on a Soft Coated Wheaten Terrier female. They are 3 weeks old right now, so we have wait until May. We played with the mom, "Claire", and watched the puppies for about an hour before we finally left. Marion Morse is the breeder, and she is in Webster, NY. website link

Tuesday, March 13, 2007

Lights Mod For Ram

On the Dodge Ram, the grill is attached to the hood, and the whole kit and kaboodle lifts as one piece. Here's an ingenius method for mounting driving lights so they sit behind the grill, mounted on the cross bar in front of the radiator. When I get around to mounting my driving lights, I'll be a lame ass and copy these guys. http://www.dodgetalk.com/forums/showthread.php?t=141886

Friday, February 23, 2007

Apache "Maintenance" Pages Using mod_rewrite

Just found out about the power of mod_rewrite in the Apache web server. To enable a system wide "maintenance" page (system not available type thing) you need enter only 2 lines of code in the httpd.conf file and restart apache. This is so simple, it kind of baffles me why this example wasn't mentioned in the 2 links I used to figure it out.

The pattern matches for everything except maintenance.html and sends the request to maintenance.html. That is important, because at first I tried to redirect all requests by matching on ^/(.*) but that got into an endless loop, since it would redirect request to maint page which redirected to the maint page which redirected to, well you get the idea.

Here is my rule:
RewriteEngine On
#RewriteRule !^/maintenance.html$ /maintenance.html [R,L]


Save file, cd ../bin and sudo ./apachectl restart and presto! All requests go to maintenance.html instead of the intended destination. Comment out those 2 lines, restart, and all normal.

Links of interest:

FOLLOWUP - 3/29
My maintenance redirect wasn't working for requests already coming in over SSL. I had to add the rule to the secure virtual host config section as well for it to work. Special thanks to "shimmyshack" on the alt.apache.configuration newsgroup for pointing me in the right direction.

Thursday, February 22, 2007

2007 DST Issues And Java

This daylight savings time (DST) issue is a pain in my buttI didn't need right now. We still have legacy applications running on JRE 1.2.2, and since it is Silverstream 3.5, changing anything out from under will destroy the world and it will not run right, if at all.

Links to Sun's FAQ is at http://java.sun.com/developer/technicalArticles/Intl/USDST_Faq.html
Of notable interest here is this little tidbit of crap:
  1. Do my operating system's timezone patches fix the Java platform's timezone data?
    • No. The Java SE platform's timezone data is not read from the local or host operating system.
    • The Java SE platform maintains a private repository of timezone data in locally installed files (.../jre/lib/zi) as part of the Java Runtime Environement (JRE) software.
      • Applying whatever operating system timezone patches (for example Solaris OS, Linux, Windows) will have no effect on the accuracy of the Java SE platform's timezone data.

Well isn't that lovely? Java doesn't rely on the underlying OS to get timezone info. I'm sure there's a "good" reason, but it seems like pointless redundancy to me. Why set it up on the OS if the JVM doesn't use it? Sure there is probably some backward OS that has no concept of timezones, so Java abstracts everything to a point of uselessness just like Swing UI's.

If installing or updating new JRE is not an option (say, in production where the app server and all the apps haven't been tested on newer JRE's) The JRE updater tool is found at http://java.sun.com/developer/technicalArticles/Intl/USDST_Faq.html -- not sure how reliable ot stable that thing is, but we'll find out in our dev and test environments soon enough.

There is a brief discussion on the Jboss forums at http://jboss.org/index.html?module=bb&op=viewtopic&t=98682 as well. Or for Websphere http://www-1.ibm.com/support/docview.wss?rs=180&context=SSEQTP&dc=D600&uid=swg21219396#actions.

Venison And Mushrooms In Gravy

This is a simple "recipe" we did tonight that was extremely good -- very tender meat and great flavor. We didn't really have a recipe, so I don't know what to call it (Bambi swimming in gravy?)

1 lb. venison, cut in 1" cubes
2 cups mushrooms, sliced or cubed
Beef gravy, mix or pre-made.
Flour
Salt
Pepper
Garlic Powder

  1. Heat up a cast iron skillet with a little bit of oil.
  2. Mix the salt, pepper, garlic powder into some flour on a plate or in a plastic bag.
  3. Dredge meat cubes in the seasoned flour and brown each side in the pan. Don't worry about cooking all the way through, just searin the juices. Once browned, remove the meat from the skilet and set aside.
  4. Sautee the mushrooms in the same pan, using a little oil or butter as necessary to soften them up. Remove and set aside with the meat.
  5. Pour the gravy (or mix up the gravy mix according to directions, we used 3 packages but 2 would have been fine) into the skillet.
  6. Put the meat and mushrooms back into the skillet, lower heat, cover, and simmer for about 30 minutes or so, until meat is tender and fully cooked.
We dumped this over white rice and it was delicious.

Next time I would probably try adding some sauteed onions in with the mushrooms as well. There's really no reason why you couldn't substitute some other meat for the venison, e.g. elk, caribou, bear, rabbit, squirrel, or even beef.

Wednesday, February 14, 2007

"Peterbilt" Dodge Ram

This thing is sweet. He must have spent a lot of cash and time on this custom project. I only looked at the pictures so far, but I plan on going back to read it later. He started with a Ram 3500 and put a Peterbilt cab on it, truck bed off an old Chevy, 40" Mickey Thompson's, etc. Must be seen to be believed....

http://www.autoblog.com/2006/09/13/when-a-dodge-ram-just-isnt-sufficiently-truck-like

Server Printing Using Java Print Service

The first and most obvious thing you will notice about the Java Print Service (JPS) API's is that it is pretty much geared toward client side printing. For example, to look up print services you use javax.print.PrintServiceLookup, which has methods to lookup the default print service, lookup all the print services that match the given AttributeSets and/or DocFlavor's. That all makes sense if you are building a print dialog with the default printer selected already, and a list of all the other printers defined on the system, to allow the user to choose one.

On the server, however, printing is just one more stop in a process flow. It has to just happen automatically, which means you have a specific printer in mind for the stuff to go to. Notice on the PrintServiceLookup class, there is no method to get a specific named printer service. In my mind, that is a deficiency, but one that is easily rectified.

Here is the code I use to lookup a named printer service. The name is kept in a properties file that gets bound to JNDI, or it could be kept in a database, etc. Basically you pass in null for the DocFlavor and AttributeSet to get all print services on the machine. Then loop through those looking for a match, and return the matching service, or throw an Exception.



import javax.print.*;

...

public PrintService getNamedPrintService(String prnName)
throws Exception
{
PrintService[] prnSvcs;
PrintService prnSvc = null;

// get all print services for this machine
prnSvcs = PrintServiceLookup.lookupPrintServices(null, null);

if (prnSvcs.length > 0)
{
int ii = 0;
while ( ii < prnSvcs.length )
{
log.debug("Named Printer found: "+prnSvcs[ii].getName());
if (prnSvcs[ii].getName().equalsIgnoreCase(prnName))
{
prnSvc = prnSvcs[ii];
log.debug("Named Printer selected: "+prnSvcs[ii].getName()+"*");
break;
}
ii++;
}
}

if (prnSvc == null)
{
throw new Exception("Printer " + prnName + " was not found on this system.");
}

return prnSvc;
}

Parsing Fixed-Length Positional Text Data

I recently had to parse out positional (fixed-length field) data, and I really didn't want to write some ugly hard-coded parser that would break every time a field changed length or a new field was added.

I also didn't want to write some overly complicated abomination with XML configuration files and AbstractFactories and visitor patterns and so on (you know, like the Apache guys would have done.)

Instead I chose to use some of the new features of JDK 5 -- like enums and the enhanced for loop. I create an enum like the one show below.


public enum GetTransactionFields
{
ADDR_ID (10, Justification.LEFT_SPACEFILLED),
ADDRESS (70, Justification.LEFT_SPACEFILLED),
TYPE_CODE (1, Justification.NONE),
ACCOUNT_INFO_IND (1, Justification.NONE),
RECEIVE_OFFERS_IND (1, Justification.NONE),
THIRD_PARTY_IND (1, Justification.NONE),
CUSTOMER_EMAIL_STATUS (1, Justification.NONE),
WIRELESS_CARRIER (4, Justification.NONE),
INVALID_IND (1, Justification.NONE),
SOURCE_CODE (1, Justification.NONE),
SYSTEM_CODE (1, Justification.NONE),
LAST_UPDATE (8, Justification.NONE),
;

private int fieldSize;
private Justification justification;

/** Private constructor */
private GetTransactionFields(int fieldSize, Justification justification)
{
this.fieldSize = fieldSize;
this.justification = justification;
}

/**
* @return Returns the justification.
*/
public Justification getJustification()
{
return justification;
}

/**
* @return Returns the fieldSize.
*/
public int getFieldSize()
{
return fieldSize;
}
}


Now, to add a new field, I simply insert it in the right position, with it's fixed length and the justification (if you only get 10 characters in a 20 character field, are they left or right justified? In this case Justification is an enum as well, but I ended up not needing to use it)

If a field size changes, you only need to change the size here. Your parser code does not need to know or care. That parsing code is extremely simple. An example is shown below. This example just prints the field name (from the enum) and the value that was parsed out.

In my real application, I created an XML document using the enum names as the XML nodes, and the values were the parsed values. This way, the data was more flexible to work with, as I could use XSLT to show the data nicely formatted on a JSP log viewer, and use another XSLT to transform it into the format needed by the backend web services.


private void parseGetRecord(String record)
{
int posn = 0;
int endIdx = 0;
for (GetTransactionFields f: GetTransactionFields.values())
{
endIdx = posn + f.getFieldSize();
System.out.println("Parsing field " + f.toString() +", value = " + record.substring(posn, endIdx)));
posn = endIdx;
}
}


And that's all there is to it. An enum and a for loop. Simple, elegant, and best of all, maintainable even by drooling neanderthal programmers.

Reading a Text File Line By Line

Sometimes I need to read a text file line by line from Java code. Whether it's reading transactions to blast onto an MQ queue, or parsing out CSV files, the actual reading of the file remains the same. But it's something that I always have to look up an example for, because I don't work with all the streams, readers, and writers classes often enough to memorize.

Here's the simplest running example, basically a crappy implementation of the the Unix "cat" command (read a file and spit it out to the console, line by line). To get it to do something useful, replace the System.out.println with something more useful, like putting to a queue, or running the line through a CSV parser, or running a SQL query, etc.



import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class UnixCat
{
public void cat(String filename) throws IOException
{
BufferedReader is = new BufferedReader(new FileReader(filename));

String line = "";
while (line != null)
{
line = is.readLine();
System.out.println(line);
}
is.close();
}

public static void main(String[] args)
{
UnixCat uc = new UnixCat();

// Assume args is a list of filenames
for (int ii = 0; ii < args.length; ii++)
{
try
{
uc.cat(args[ii]);
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
}
}
}


Tuesday, February 13, 2007

Ram HEMI: First Shock

I ended up buying that Ram last week (http://redneckprogrammer.blogspot.com/2007/02/is-this-truck.html
), and I have to say it's awesome. It's a 2003 Ram 1500 SLT Quad Cab 4x4 with short bed and the 5.7 liter 345 HEMI V8. It hauls lots of serious ass. It's kind of hard to open her up with all the snow and ice we've had, but you can feel it growling under that big bulging RAM hood. The kids love and and always aks to ride in Daddy's truck.

I filled it up late last week to the tune of $50, then filled it up again last night. I did a little basic math and found that I got a little (very little) over 13 miles per gallon mileage. It was a little bit of a shock to fill that 26 gallon tank, and a bit of a shock to get 13 mpg, but it really can't be too much worse than the Jeep with 4.11 gears, 33" tires, and the aerodynamic qualities of a brick. I don't know for sure because I never actually calculated what the Jeep got. I figured I just didn't care enough to run the numbers. Anyone who drives a lifted and modified Jeep is not in it for the economic benefits. Same goes for driving a full size truck with a big V8.

The truck has all the goodies, towing package with the hidden hitch, trailer wiring, trailer brake controller, leather seats, overhead console, bed liner, "Infinity premium sound" system with the CD and cassette, fold out flat cargo deck in back seats, with storage under that, heated side mirrors, power locks/windows/driver's seat, auto transmission, etc.

Monday, February 12, 2007

Tonneau Covers

I'm looking to get a tonneau cover for the new Dodge Ram this spring. My father has one for his Dakota that attached very similar to the soft top on a Jeep. The problem is when it gets cold the material gets stiff and shrinks a bit. If you get it off, you'll never get it back on, as we found out when we were packing for our bear hunting trip last November. Lund and a couple other companies make a cover with the bows and frame built right in, so you just clamp it down to the bed rails. It folds up in 3 sections, and installs in minutes no matter what the weather.

The Lund is the Lund Genesis Tri Fold, and it's amazing how much of a range exists in pricing. At the cheapest, I have found Amazon.com has it for $282.74 with free shipping, and as high was 423.95 at Auto Parts Warehouse, with free shipping (gee, thanks, charge me and extra $140 but give me free shipping).

I was kind of amazed Amazon.com had it at all, let alone them being the cheapest by far. Remember when they sold books? And maybe CD's and movies? Now they are like the Super Walmart of the internet world.

Price list for Lund Genesis Tri Fold model 95064 for Dodge Ram 1500 Quad Cab short bed (6'3")
  • Summit Racing - $329.95
  • JEGS - didn't have it
  • Truck Addons.com - $330.99, free shipping
  • Truck Stuff USA - 369.99
  • JC Whitney - $359.99
  • Auto Parts Warehouse - $423.95, free shipping
  • Amazon.com - $282.74, free shipping

Saturday, February 03, 2007

Apple Picking Fall 2006

This past fall we went apple picking at Morgan Farms out here in 315 land. Here are a few pictures.

Daddy And Taryn
daddy and taryn
Mommy and Raina
mommy and raina

Pix From The Cabin (Last Fall)

Just going through some pictures on my hard drive. Here are a few from the cabin last fall.

Grammy and the girls coming back from a walk


Taryn, Teddie, and Charlie sleeping together. I think Charlie liked being able to sleep with Taryn, where she normally would have been sleeping in a brib at home.

Thursday, February 01, 2007

Winter Warmth

One of my favorite winter time recipes...

1. Fill a rocks glass with ice
2. Fill with bourbon
3. Enjoy responsibly.

Wednesday, January 31, 2007

Chicken Mushroom Soup

Came up with this one trying to emulate a soup I had at Chilis once. Not sure how close it is since they seem to have it when I go there anymore.

INGREDIENTS
1 can cream of mushroom soup
1 can chicken broth
1 can sliced mushrooms
1 boneless chicken breast
garlic powder
black pepper
salt

DIRECTIONS
Cut chicken into 1" cubes & brown. Combine all ingredients in slowcooker and cook on low. Scale up for larger pots of soup.

Italian Beef

Got this one from my Mom. Makes good sandwiches on hard rolls.

INGREDIENTS
6 lbs sirloin tip roast
2 onions
1 stalk celery
1 green pepper
1/2 bottle ketchup
2 T. BBQ sauce
2 T. Vinegar
1 t. Pepper
2 T. Salt
2 T. Chili powder
2 cups water

DIRECTIONS
Cook roast all night in crock pot. Flake meat & take off any fat. Put back in crock pot. Combine all other ingredients pour over meat. Leave on low all day.

Stuffed Mushrooms

Ingredients
1 package whole mushrooms
pepperoni
sliced salami
sliced ham
grated parmesan cheese
1 egg
either heavy cream, provolone, or mozzarella cheese.

Directions
1. Pull stems from mushrooms.
2. Lay out mushroom caps on baking pan.
3. Put stems, Pepperoni, salami, & ham in food processor to chop finely.
4. Combine meat w/ egg & mix well.
5. Add grated cheese to desired consistency.
6. Pack mushroom caps w/ mixture.
7. Put cheese on the caps, or pour cream over them.
8. Bake (~350 deg) until cheese in bubbly & turning brown.

Beer Can Chicken

This is a yummy treat in the warmer weather. Speaking of warmer weather, who the hell turned off Global Warming? I was starting to enjoy the warm December, but now it's freakin cold!

Anyway, beer can chicken. Slow roasted on an open fire and still tender and juicy.

1. Fire up the grill. I like charcoal and wood chips, but you can use gas.
2. Rub the whole chicken with Montreal seasoning or any other spice you like. Salt, pepper, garlic powder is a nice simple rub.
3. Drink half a can of beer, leave the other half in the can.
4. Sodomize the chicken carcass with the can of beer, making sure not to spill any beer.
5. Prop up the bird on the grill so it looks like he's taking a dump. The can should be fully upright.
6. Cover up and let it sit until done.

Don't worry too much about overcooking, the evaporating beer will keep it moist.

Tuesday, January 30, 2007

Robb's "Award Winning" Chili Recipe

For printable copy http://frontiernet.net/~nicholson150/Chili.pdf

Instead of duplicating the recipe here, I'll just include it with a handy iframe....

Friday, January 19, 2007

DAO Generator Update

Progress has been somewhat slow, but I fixed some issues with the Velocity templates, as I got a chance to generate the persistence layer for a mini project, which surfaced a few issues.

Also, main bulk of work now is with the custom query generation. At first I started with a custom query tab, then a different tab for each table. That screen got really busy and unusable really fast, so I decided to do more of a popup, screen-by-screen "wizard" type approach.

Click on the table, hit "Custom Method" button...


And it pops up a screen with the current custom methods for that table (if any)....

Then you can edit, delete, or create new. New button launches a screen that will look something like this (but needs some way to display all the parms as they are added, with way to edit or delete parms)....

The DAO generation for stored procedures has been a pain in the butt, so I shelved that chunk for now. One of the databases I ran this against had 2 stored procedures in the same schema with the same name, and as far as I could tell the params looked the same too. That of course puts duplicate methods in the DaoFactory but only generates one DAO class instead of two. Maybe I should just make that whole thing more generic, like the DAO "execute" method takes a single array of parameters instead of being a finely grained typed call. And then the binding is done on the fly. If you sent too many or too few params, you lose, Exception thrown.

Once I get the custom query stuff done, the next chunk of work will be to make this work with other database servers. I can test it against Oracle, MySQL, and SQL-Server without too much effort since I have all those installed on my PC.

HTTP Proxy - BURP Suite

As more and more of our development centers around integrating various systems, we find that troubleshooting issues gets more and more complicated. Instead of just walked through my own code with a debugger or examining log files, you have to involve other groups and application owners. Part of the hassle is convincing other people that there is a problem at all, let alone where the problem might lie. Complicate that with the fact that you may not have as much visibility into the whole transport layer as you might like.

I trace through all my code to the last point before it fails, and that is a call into the SOAP connector. So the request may or may not be getting to the target system OK. The SOAP requet you think you created and the one actually getting transmitted may be different.

Enter the BURP suite, a set of tools to act as an HTTP proxy and capture requests and responses. Now you know exactly what your app is spewing out and what the target system is responding (or not). It can be a simple proxy, showing you all the requests and responses, or you can intercept requests/responses, alter them, and forward that.

Below: Main screen

Below: Detail screen showing a particular request, your altered request, and the response, each in tabs. I did some censoring to take out specific server names and stuff.

There are also other tools in the suite, like spider, repeater, etc. but I mostly find the proxy and intercepter useful for troubleshooting and testing. This thing is definitely worth the free download, esp if you are doing any kind of web services type crap and dealing with less-than-cooperative developers from other teams or systems.

Below is a screenshot of the configuration screen for the proxy. You can configure exactly what to capture and automatically alter some header info, etc.

BTW - You can click on any of the pictures for a bigger view. Closeups aren't just for porn anymore.

Sunday, January 07, 2007

Raising Chickens In The Backyard

Well, now that we have two boats, a lawn mower, a snow blower, and a broken down Jeep YJ stored on our property (none of which belong to us, this is all in addition to our lawn mowers and Jeep) we just couldn't deny that we are true 315-ers, even if we do still carry a 585 area code. We are true Wayne County rednecks -- we eat critters from the woods out back, we have a pool that contained thousands of tadpoles this past spring, and now we have a Sanford and Son collection started. The cap it all off, we really need some livestock running around. And hence, our decision to raise chickens for food....

We're starting to move forward on our plan to raise chickens this spring. Our thought is this will be somewhat educational for the girls, as well as a source of meat and eggs. Mmmmm, barbecue chicken!! Doesn't get much fresher than killing it and grilling it 30 minutes later. The breeds we picked are good all around birds that lay a decent amount of eggs but still get to be good eating size.

There is a block building in the back yard, the size of a good size shed. We will turn that building into the coop by adding some perches and nest boxes in there, and adding a fenced in run. We have a very large barn so we really don't need that small outbuilding for any real storage or anything.

Since we live in an area that is known for having rough winters, we will order the chicks closer to spring so we don't have to worry too much about them freezing. We also settled on breeds that are known for doing well in the northeast: Rhode Island Reds and Buff Orpingtons.







We'll be ordering 25 day old chicks from Murray McMurray hatchery, along with a starter kit (water bottles, feeders, brooding light, etc. We will get some feed, grit, fencing, and waterers at local suppliers like Country Max or Tractor Supply Company. In warmer weather we plan to let the chickens free range during the day so they eats bugs and stuff from the yard.

This should be an interesting, fun, educational, and hopefully rewarding experience. I have a smoker that could cook up probably 10 chickens at time and still have room for corn on the cob, so COCK A DOODLE DOO!!

Friday, January 05, 2007

2007 IRS Tax Withholding Calculator

To figure out how to full out your W-4 to maximize in-pocket money year round without having to pay ... http://www.irs.gov/individuals/page/0,,id=14806,00.html

Thursday, December 14, 2006

Ant Visualization Tool - yWorks Ant Explorer

Found this free tool last night that shows a visual graph of an Ant build.xml and shows the hierarchy of task dependencies. Can be stand-alone installed or Webstart, or IDE plugin for Eclipse or Netbeans.

http://www.yworks.com/en/products_antexplorer_about.htm

Wednesday, December 13, 2006

DAO Gen Update 12/13

Between other tasks and our Christmas party, I got some work done on the DAO generator tool.

Completed Tasks
  • ResourceManager - getConnection() for when Connection is not supplied: Currently it's guts are commented out. Should put a JNDI lookup for a data source in there. That's how we do it, most likely anyone doing server-side code also does this. They could always customize for using DBCP or some other mechanism.
  • DB query tab. Lets you enter queries and run them. Results come out to output tab as tab-separated text, along with number of rows retrieved and how long it took to run.
  • simple Batch file launcher for Windows.
  • Fixed an elusive NPE on describe that only happened once in a blue moon.
  • Usability stuff: there are validations now for required fields being blank, and clicking on describe button will take you to output tab to show what is going on. When done, it goes to DB explorer tab. If a field is blank when validation runs, the config tab is selected so user can fill in,and some other things that make it all more usable.
Screenshot of simple query runner tab:


Outstanding Tasks
  • DaoFactory - generated factory class is missing factory methods for stored procedure DAO's (easy fix, but have been busy with GUI)
  • Stored Proc DAO's - need a lot of work
  • CLOBS/BLOBS/BFILES - haven't accounted for those at all. they are a pain to write by hand so they should be done right in the generated code.
  • Generated DAO's and all classes need to be fully tested to make sure the templates are right.
  • Dist - need to come up with a distribution package mechanism, with shell and batch files to launch, special directory for templates, etc.
  • Custom Queries - not implemented in generator or GUI yet.
  • Saving new project file - app should put .prj extension on filename automatically if it isn't there.
  • Help screen needs content
  • Code cleanup w/ respect to comments, package names, etc.
  • Pick a better name for application and update the package names
  • Documentation would be helpful
  • Pick an open source license and OS project hosting

Tuesday, December 12, 2006

DAO Gen Update 12/12

I got lots of cosmetic and functional work done on the GUI side of my persistence generator. Still need to work on the Velocity templates, implement custom query generation, clean up code/comments, pick a better name, open source it somewhere, and some more GUI features to add.

Progress this week:
  • Added a Browse button for the template directory to make it more consistant with the generated code destination field. Also improved the layout a little bit on the screen.
  • Switched to a tabbed interface. The main screen from last week is now the configuration tab. There will be a tab for writing the custom query methods, running queries against the current DB, the output window has been nixed in favor of an output tab, and a tab that visually shows the DB objects to some extent.
  • Add mnemonics to menu and toolbar controls.
  • Open and Save/Save As now fully work, and described database meta data gets saved with project.
  • Help "about" and "contents" actually launch screens, even if there is no real content yet.
Screenshots: Config Tab (default Java "Metal" look and feel)Output tab (used to be separate window)

DB Explorer tab:
Look And Feel is controlled by View menu, below are the Windows (native) and the crappy "Motif" look-a-like that comes with Java:



Outstanding task list:
  • ResourceManager - getConnection() for when Connection is not supplied: Currently it's guts are commented out. Should put a JNDI lookup for a data source in there. That's how we do it, most likely anyone doing server-side code also does this. They could always customize for using DBCP or some other mechanism.
  • DaoFactory - generated factory class is missing factory methods for stored procedure DAO's (easy fix, but have been busy with GUI)
  • Stored Proc DAO's - need a lot of work
  • CLOBS/BLOBS/BFILES - haven't accounted for those at all. they are a pain to write by hand so they should be done right in the generated code.
  • Generated DAO's and all classes need to be fully tested to make sure the templates are right.
  • Dist - need to come up with a distribution package mechanism, with shell and batch files to launch, special directory for templates, etc.
  • DB query tab - not implemented yet
  • Custom Queries - not implemented in generator or GUI yet.

Tuesday, December 05, 2006

A Few Unix Shell Tricks

If you want to set a value in a shell script, but only if it isn't already set (e.g. set a default value but let it be overridden), try this. The following command will set PROJECT to be mqbridge, unless PROJECT is already set. In that case, the current value overrides. I have used this trick in ksh and bash. Not sure what other shells it works in.

export PROJECT=${PROJECT:-"mqbridge"}

Redirecting stderr to stdout: If you are trying to capture output of a command into a file, you will notice the regular output goes into the file, but errors go directly to the screen instead. If you want to capture both, use shell redirection like this (2>&1) after your command.

For example, to have all output go to the screen and to a file, you can do something like this:

    run.sh 2>&1 | tee output.log





Wednesday, November 29, 2006

Crontab Format

Every time I need to put something in cron, I forget the format or layout of each job. I stripped this decent explanation from this site:

The format of the crontab file is as follows:

Minute (0-59) Hour (0-23) Day of Month (1-31) Month (1-12 or Jan-Dec) Day of Week (0-6 or Sun-Sat) Command

0 2 12 * 0,6 /usr/bin/find

This line executes the "find" command at 2AM on the 12th of every month that a Sunday or Saturday falls on.

Wednesday, November 08, 2006

In Loving Memory...

Charlie
(AKC "Good Grief Charlie Brown")
April 27, 1998 - November 7, 2006
Airedale Terrier

Charlie was our first dog, our first baby. He was diagnosed with Lymphoma (cancer of the lymph node system) about 2 weeks ago, and we had to put him down last night. It was not an easy decision, but it was what was right for him so he wouldn't suffer and be in pain any longer.

The Lymphoma was a horrible disease, because early detection doesn't really buy you anything. We took him to the vet because his throat was swollen and his eyes were red. We thought he had an allergic reaction or infection. We weren't prepared to hear the doctor say the "C" word, especially since Charlie was acting completely normal, looked normal, was still playing and happy, wagging his tail, eating and drinking, and just being himself.

Charlie was a great dog. Even when we had children, he took to them very well and welcomed them to the family. He soon became very protective of them, like they were his own. He would sleep in the hallway outside their doors at night. If someone he didn't know came to the house, he made sure to be between the girls and the stranger at all times. When they cried in their crib, he would go investigate and come barking at us so we knew something was up.

(Left: Charlie and Morgan taking a break from playing)

He was of course every bit a terrier though, we can't forget that. He was smart, but stubborn. When training him, he would reach a point where he would get bored and just wouldn't cooperate. He was big enough to do his share of "counter surfing" -- getting up on the counters to steal any food that wasn't bolted down. He had no use for other animals, especially strange dogs. Sure he played with the dogs he knew, like Morgan, Pongo, Sage, Wolf, etc. But any other dog he would go nuts barking and lunging at them. As a very small puppy, he actually started barking and "picking a fight" with a full grown rottweiler. That's terrier attitude for you.

(Left: classic example of Charlie being in the middle of the action during Taryn's birthday party)

When we first went to get Charlie as a puppy, we were "just going to look". I liked Airedales from what I knew about them, but had no real intention of actually getting one right then. I was still in an apartment that didn't allow dogs, but I was closing on my first house in a few weeks. Plus I was going to ask my girlfriend to marry me. I wanted it to be a surprise, so I kept telling her I didn't have the money for the ring. Well in her mind, I had no money for a ring but I just dropped $500+ for a puppy. I just couldn't resist once I saw them. There were about 4 puppies left when we got to the breeder's house, and Charlie was running around with a little purple ribbon tied around his neck like a collar. For some reason we gravitated right to him, but he kept running under their porch. The breeder spent a good 15 minutes or so trying to get him to come out so we could take him home. We're glad he finally came out. And my wife has since forgiven me for the ring incident once she found out I had already purchased the ring.

(Right: Upside-down Bear)

If Charlie was laying down, and any of us walked near him, he would roll over on his back with all 4 paws up in the air. We would say "Charlie's upside-down" and then rub his belly. After getting used to this behavior, he would sometimes "go upside-down" even if you weren't near him, knowing you would go over and rub his belly anyways. We even taught our daughters that any time he was upside-down, they had to rub his belly.

He was never much for the game of Fetch in the traditional sense. Throw a ball or frisbee and he would run over, grab it, and then lay down to chew on it. So we turned it into a game of "I'm Gonna Get You". We would run after him, and he would grab the toy and run away, purposely getting himeself into situations where we could corner him and grab the toy, but then running past us in the other direction.

Sometimes Charlie would kind of sigh in his sleep, so it sounded like he was "leaking" air. Another strange thing he did was he would lick my head when I got down on the floor to play with him. It was funny when he would get done eating or drinking, then walk the length of our bed rubbing one side of his face on the comforter, then back the other way rubbing the other side of his face, like our bed was a giant napkin just for him. Speaking of napkins, he would go on one his marathon water drinking sessions, then come up to you with his terrier beard dripping wet and put his head on your lap (usually when you're wearing shorts!).

We will miss Charlie a lot. I didn't really feel ready to say goodbye, but I wouldn't have been any more ready next week, next month, or even 8 years from now when he would have been "old". We did the right thing for him instead of being selfish and keeping him around in misery. We'll always remember him and love him. He was our first baby.
(Left: "You lookin' at me?")

(Below: Just hangin' out)