Wednesday, December 07, 2005

Java vs C# vs C++

Take a quick look at Comparing Two High-Performance I/O Design Patterns, page 3 which graphs the results of writting the same I/O code in Java, C# and C++. It is really cool to see how well Java and C# stack up against C++.

I've written a couple of servers in Java using NIO, and in C++ using raw sockets. I was very impressed with the performance of Java. Factor in how easy it was to write the Java code and Java is a clear winner to me.

One thing that isn't shown in the article is the difference between Java and C#'s class library. In Java, most everything is a CharacterSequence. All the conversion and string manipulation features in Java work with CharacterSequence. For example you can perform Regex functions directly on the NIO buffers!

Unfortunately in C#, the various strings and buffers do not have a common parent. The String and StringBuilder classes only have Object as the common parent. Also classes like RegEx do not support a wide range of targets. RegEx only works on String and serialization streams. You can't perform a RegEx directly on StringBuilder in .Net!

In conclusion, go Java :)

Friday, November 04, 2005

Development at Valve

Game Developer Magazine ( had a real great article about Valve's process and practices that they used to produce Half-Life 2 (Nov 2005 issue). Go get your hands on the article it is really an interesting read.

Their process incuded many elements that are also found in Agile processes. They used a lot of prototyping and interations in the development. The iteration strategy really paid off for them. When faced with trade-offs they favored reducing scope to get more iterations. More iterations forced them to reduce the overhead costs of iterations. Having more iterations helped them increase quailty, experimentation, and enabled them to delay decisions until later in the process. They said "Decisions made later in the project were always better than decisions made earlier."

Their team culture is also very interesting. They worked in small 4-5 person teams (Cabal). Each Cabal shared an office space to increase communication and avoid getting side-tracked. They discouraged "sole ownership". They promoted positive competition between team members and across teams. Also they created demanding comsumers for everyone on the team.

I've only touched on some aspects of their system. You'll have to read the article to get the full story.

Monday, October 31, 2005


Today I needed to parse some CSV data. A quick search found a project called OpenCsv that was added to sourceforge last month. I pulled it down and found it did a great job on the data I was parsing. The data I am parsing contained newlines, commas and quoted strings inside the csv elements. Some other libraries would not handle this correctly but OpenCsv did!

Friday, October 28, 2005

Rapid Prototyping - Recommended Reading

Gamasutra published a feature article "How to Prototype a Game in Under 7 Days:
Tips and Tricks from 4 Grad Students Who Made Over 50 Games in 1 Semester

This article provides an interesting story on rapid prototyping. Several points made directly oppose the ideas pushed by Agile Development. Specifically they devalue working together during the coding phases of the project. Also, they denounce formal Brainstorming. While at the same time, some points re-enforce Agile Practices. Their call for picking the solution done the fastest is similar to the Agile practice of making the "simplest thing that could possibly work".

Overall, I think there is more need for Rapid Prototyping in Business Application development. The Agile community calls this a "Spike Solution". Far too often I see product managers and developers writing production solutions without first creating a prototype.

Also, I agree with their assertion that "Complexity is not necessary for Fun" in game play. I think this also applies to application development in that "Complexity != Productive Solutions." Application designers seem to want to add flexibility and options. This adds Complexity and reduces the productivity of the users and developers. Most users just want a simple solution to their problem. Once they find the solution, they don't use those extra options.

They said their Brainstorming sessions did not produce immediate results. But it did get them thinking and at a later time (maybe while driving home), an idea would pop into their head. This is exactly the same process that I have read from a successful inventor. (Sorry I don't have the reference). The inventor said he could always find a new idea or solution with a two step process. First he would focus and concentrate on the problem for some time. He wouldn't expect to get any results from this activity. But somehow it got his subconcious mind working on the problem. Then the second step was just to do something else. Driving, going to a park, etc. At a later time his mind would bring up a new solution or invention related to the problem he had focused on in the first step.

Monday, October 24, 2005

Wednesday, October 12, 2005

Cross-site scripting has posted a good little article on Cross-Site Scripting. Makes a great summary or beginners guide on the subject.

Tuesday, October 11, 2005

Virtual CD-Rom for XP from Microsoft (unsupported)

Need to mount an ISO image? Here is a simple tool from Microsoft: Virtual CD-ROM Control Panel for XP. While unsupported, it seems to work fine.

I found it on the PDC Vista Beta install disk. Looking around Microsoft's web, I found this reference to it... MSDN Subscriptions FAQ see question "What are ISO images files and how do I use them?

I was surprised to find they also linked to some 3rd party tools in the FAQ. Also, kudos to M$ for having java script on the page that worked with Firefox.

How to determine if .Net app is having Lock Contention

Open perfmon and add the .Net CLR LocksAndThreads. Select "Contention rate / sec" and "Total # of Contentions" (use ctrl-click). Then select your application from the "instances" list. Then click the Add and Close buttons. The report view is the best way to see the results.

Thursday, October 06, 2005

DoD: anti-MG tactics

Playing Day of Defeat Source I see a lot of players using smoke grenades to try and sneak past machine guns. While this has slight success, there is a better way.

An MG in a good bunker can be difficult to throw a grenade into for a kill. However, it seems many players dont realize how a near-miss grenade really shakes up the MG. The Source engine violently shakes and blurs the gunner's view. So for a second or two, the MG is unable to effectively see and aim. This provides a great oppertunity to get a clear shot on the MG.

Just time your attack to take place the moment after the nade goes off and you will greatly increase your chance for success. Good luck!

Tuesday, October 04, 2005

Software that makes my day

Software that I use everyday...
  • Java - the best language and platform.
  • Eclipse - Living with eclipse only because I cant spend the $$ for IntelliJ just for home use.
  • Subversion and TortoiseSVN - Keeping the code safe
  • Beyond Compare 2 - handy diff tool, and cheap enough (I'd rather use Araxis Merge but can't afford it)
  • OpenOffice - Better than Office!
  • Office - only because my co-workers keep buying it.
  • Trillian - for those fun interruptions during the work day (yeah it gets lonely in a cube)
  • Half-life and Half-life 2 plus mods CS, DoD, Natural Selection, HL2 DM - for my adrenaline rush and game fix.
  • Firefox - for the internet, and web-based email.
  • Remote Desktop - because there are too many machines in my office
  • Audacity - A poor man's 'tivo' for internet audio.
  • Azureus - Because bittorrent rocks!
  • Windows XP - Only because you have to have an OS, and this is the only one that runs all the other stuff easily.
It is interesting to see that half of these applications are opensource. What software helps you get through the day?

Thursday, September 29, 2005

Learn something new everyday...

I've been using wndows since version 3.1. So it surprised me to find a new trick today. You can ctrl-click multiple windows in the taskbar then right-click one to get options to tile and cascade the windows. I found this tip in a PCWorld article.

Anyone know how to arrange the taskbar window buttons? (Yes, I've seen TaskArrange which works fairly well. But I'd rather be able to drag and drop the buttons on the taskbar itself and have windows remember the order.)

Tuesday, September 27, 2005

Day of Defeat Source

DoD Source was released to the public yesterday. This game plays great on the Source engine. The graphics, physics and sound make the game great fun. There were few changes to the gameplay. Mostly UI changes and some changes to the weapons and loadout. I really like the MG's ability to deploy on any surface. This adds a lot of strategic options for the MG player. The new weapons for each class will take a little getting used too. For example, one time I snuck up on a camping sniper and was about to use the knife. But I couldn't find the knife! As a noob on the version, I didn't know the class I had choosen didn't come with a knife. The sniper thought is was funny to turn around and see my avatar swapping weapons like crazy.

The game isn't without bugs. Once while playing Flash, I bumped into a teammate and our avatars got stuck together. We couldn't move! An enemy came along and happily ended our troubles.

DoD Source is great for any fan of the original Day of Defeat. Many of the guns fire differently so expect minor changes from the original. The Allied rifleman gets a new grenade launcher. It give the rifleman more range to toss a grenade. However, you cant control the fuse time. Another great change is the grenades start their fuse when you begin to throw them. So you dont need to use the "toss on the ground and rethrow" trick used in the first DoD.

The new maps might look familiar, but many have new paths added. So explore a bit on the DoD maps to find all the options.

Wednesday, September 21, 2005

Say "Yahoo" for cool tools!

Here are two very useful tools from Yahoo that you might add to your tool box... Yahoo Desktop Search and MyWeb. In my current job I have to work on a large legacy application. The application has been in development for more than eight years. It has a large amount of source-code and documentation. Finding information in this mass of files was very difficult until I used Yahoo Desktop Search. Search has a great interface for performing the searches and previewing the results. It handles source code, word, pdf and many other documents. So when I look up a function in source, I can easily spot everywhere it is used in code and in the documentation! Very very nice. I tried using Google's desktop search tool, but found the Yahoo Desktop Search to richer and easier to use.

I read a lot of technical articles, whitepapers and blogs. On any given day I probably read 2 to 10 articles about technologies I'm using. That is a lot of information to keep track of. My solution is Yahoo's My Web. Since late May (see previous post) I've been dropping every article I read into MyWeb at Yahoo. MyWeb captures a copy of the webpages so I can search them later. [Hint, use Yahoo Toolbar to make it easy to add to MyWeb.] So the next time I need to find that article on JTidy, Derby, or AspectJ I can use MyWeb to search only the articles I've read.

Maybe one day Yahoo will get the Desktop Search to also include MyWeb. That would be Nerdvana!


Tuesday, September 20, 2005


There is a new portal for Object Databases: ODBMS.ORG. A good resource for information and software. It is rather interesting that this site is sponsored by db4objects. I hope the site doesn't become biased. Anyway it is a good starting point for getting into object databases.

Wednesday, August 24, 2005

Funny stuff... Escape from Yesterworld

Microsoft published the Escape from Yesterworld site to promote 2005 development tools. It contains some funny parody videos on the first page (Main Control Room). Only four more months and 2005 will be Yester-year. Microsoft had better start shipping fast. Enjoy!

I found it interesting that MS used Flash to make the site. Didn't MS make that fancy IE browser to deliver rich content? Also, using IE the pop-ups to show the movies would not appear. When I clicked on the controls to show the movies, IE would just make a weak "beep" sound (maybe that was flash.) IE did not provide an error, neither did the yellow bar appear to enable the popup. So with IE, I couldn't easily view the movies! Good old Firefox worked just fine. (Who made this site?)

Monday, August 22, 2005

How to Create and Change Environment Variables using C# or .Net

Modifying environment variables seems like one of those easy tasks that you would expect .Net to support. Unfortunatley the System.Environment class only supports reading environment variables. So an alternative solution is needed. After a long search on the internet, I found one site that describes some options: Environment variable is handled. Unfortunately, this page is written in Japanese. An english translation is here. There are several options available, each with it's own limitations and issues. I tried each option and found they wouldn't work for me.

Windows Management Instrumentation (WMI) has the ability to easily read the environment. If an environment variable already exists, you can modify it using WMI. However, I could not find a good example of creating a new environment variable through WMI. I installed and ran Microsoft's WMI Tools (available here) to see if I could create an environment variable through the CIM Studio. No luck. There might be a way to use WMI to create a new environment variable, but I haven't seen it. Also, calling WMI causes a noticable performance hit on the first call.

Another solution is to modify the Registry (see MS KB Article) to create and modify environment variables. This seems to work, however the class Microsoft.Win32.RegistryKey doesn't provide the ability to create a REG_EXPAND_SZ value. Without REG_EXPAND_SZ, you can't use the %VAR% expansion! So using .Net framework falls short. (This is one example of my frustration with .Net, many framework interfaces are incomplete. Java never had this problem, instead Java tends to err on the side of giving you too much.)

The solution I found to work the best was to call Windows Scripting Host (WSH) Shell from .Net. This is described in Basic WSH Tasks: Manipulating the System Registry. I found an example of calling WSH from .Net in the article The Code Project - Creating Shell Links (Shortcuts) in .NET Programs Using WSH. Using WSH, it is easy to create and modify environment variables. Also, WSH allows you to set REG_EXPAND_SZ values. The final step after changing the environment variables in the registry is to broadcast the change by calling SendMessageTimeout as described in the KB article. I found this example calling SendMessageTimeout from C# on .Net 247.

So in short, here is the example code for creating and modifying environment variables from C#...

        public static void SetUserVariable( string name, string value, bool isRegExpandSz )
SetVariable( "HKEY_CURRENT_USER\\Environment\\" + name, value, isRegExpandSz );

public static void SetSystemVariable( string name, string value, bool isRegExpandSz )
SetVariable( "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment\\" + name, value, isRegExpandSz );

private static void SetVariable( string fullpath, string value, bool isRegExpandSz )
object objValue = value;
object objType = (isRegExpandSz) ? "REG_EXPAND_SZ" : "REG_SZ";
WshShell shell = new WshShell();
shell.RegWrite( fullpath, ref objValue, ref objType );

int result;
SendMessageTimeout( (System.IntPtr)HWND_BROADCAST,

CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool
IntPtr hWnd,
int Msg,
int wParam,
string lParam,
int fuFlags,
int uTimeout,
out int lpdwResult

public const int HWND_BROADCAST = 0xffff;
public const int WM_SETTINGCHANGE = 0x001A;
public const int SMTO_NORMAL = 0x0000;
public const int SMTO_BLOCK = 0x0001;
public const int SMTO_ABORTIFHUNG = 0x0002;
public const int SMTO_NOTIMEOUTIFNOTHUNG = 0x0008;

Call either SetUserVariable or SetSystemVariable with the name and value. Set the boolean argument isRegEpandSz true if you need REG_EXPAND_SZ or false for REG_SZ type.

Thursday, August 11, 2005

TopCoder on Pair Programming

Shortly after blogging about pair-programming on TopCoder, the folks at TopCoder contacted me. They asked for more information about what we did while pair-programming. I gave them the details and tried to make a case for pair-programming in their Single Round Matches. The case I tried to make focused on the fun involved in pair-programming during their contest. Which for me was the whole reason to play TopCoder anyway. Pair-programming in the competition for me was a lot more fun than playing it by myself. Just like any sport, playing in pairs you build excitement and energy from your teammate. The added social-factor made the event very entertaining. Some of the discussions and comments we made while trying to hack code and race the clock would probably make a good reality-tv show. Pair-programming combined with the time-limit created a fun, social and exciting environment. This was simply FUN!

Unfortunately TopCoder's reply included...

Our current environment is setup to promote individual results and ratings. At this time, we dot not intend to add any type of pair programming or team competitions, but we'll consider your request. We've considered team contests in the past, but ultimately were hesitant due to the high potential for abuse.

If you like the pair programming experience within TopCoder, I encourage you attempt the same format but use the practice rooms instead of an SRM.
Ok, TopCoder has both technical and business issues to overcome before they can support team events. I'm sure if they really want to, they could find a way to support pair-programming. After all, don't they have access to the *Top Coders*? I hope TopCoder changes one day to allow team events. It really was a great form of Recreational Programming. Until then, Tom and I will look for other programming games to pair and play.

Friday, July 29, 2005

Remote pair programming on TopCoder

Last night Tom and I tried our second match on TopCoder using Remote Pair Programming. (Our first match we had some technical difficulties that limited our success.)

The tools we used were:
  • Eclipse 3.1 for our Java IDE.
  • Microsoft Remote Assistant for sharing my desktop with Tom.
  • Skype for voice over IP.
  • Microsoft Messenger to launch Remote Assistant and text chat.
  • Firefox browser.
I have a 3MB/384k DSL connection which handled the sharing of my desktop in 1280x1024 and voice over IP on Skype very well. Only once Tom complained that his refresh got behind his typing when he was driving. An earlier attempt where we used VNC and a 1.5MB/256k DSL connection at the host had more refresh problems, but was generally workable.

The contest went well. TopCoder provides three problems of increasing difficulty worth 250, 500 and 1000 points max (points decrease over time). The problem set is listed on We jumped into the 500 point problem first called WordCompositionGame. As a pair, Tom was immediately thinking ahead about how to implement the next steps as I coded the steps that we knew. This eliminated some hesitations and pauses that might have slowed down either of us alone.

On the 1000 point problem, KthElement we also quickly hacked out the solution. Our code was more brute force than elegant because we were racing the clock. Our JUnit tests failed showing we had the right sequence, just not the correct KthElement. I immediately guessed we had an "index off by one" bug. So rather than puzzling out the bug, I simply added one to the index and re-ran the unit test... it passed!!! (Thanks to Tom for creating a program that converts the TopCoder problem statement into Unit Tests). We submitted the code.

Next we opened the 250 problem with lots of time left. While reading the problem statement, something bugged us about our solution to the 1000point KthElement problem. KthElement ran a long time for large numbers. Tom checked the rules and realized there is a 8 second limit on runtime. So we reopened KthElement. This cost us more points because the clock was now ticking down points on the 250 problem, and reopened the countdown on KthElement.

A quick look at the data in the KthElement unit tests made us realize the sequences started to repeat. So the solution was to collect the sequence until it repeats and calculate the KthElement from the repeating pattern. This took a bit of effort, but saved us from total failure. At one point in this, Tom and I disagreed about how to find the KthElement from the repeating pattern. Tom started to go off on his own solution (he has two monitors at home), while I was hacking out my solution. Fortunately this split didn't last more than a minute or two. I was able to draw Tom back to look at my solution because I was so close to getting it, but needed another pair of eyes. Together we got the pattern identified and the calculation for the Kth element correct.

Finally back to the 250 problem SequenceOfNumbers. It was a real easy one, but we only had 9 min left on the clock. We got rushed and made some mistakes in our approach. Thankfully as a pair we quickly saw when things were off track and got back together. At one point we went off in a tangent trying to make an elegant solution. It wasn't panning out, so we trashed it and did a quick brute force. Adrenaline was pumping as we compiled and ran unit tests with less than one minute remaining. It pass the tests and we got everything submitted with ony 34 sec left in the contest.

Final score... all our solutions worked and scored. We could have scored higher on KthElement and SequenceOfNumbers if we had looked at the unit tests and realized KthElement involved a repeating pattern. Having both problems opened at the same time was not good.

Remote Pair Programming worked great! We performed as well as we would have sitting right next to each other. In fact we probably performed better being remote because it was easier to swap control since we each had our own mouse and keyboard.

(Yes, we know TopCoder considers collaboration as cheating. Sorry. We were just trying to experiment with Pair Programming and enjoy the contest. We assume this is ok during a *not for money* match. It would be nice if TopCoder had a division for Pair Programmers.)

[Aug 11, 2005. I've posted a follow up article.]

Learning Iterated Development from the Game Industry

Julian Gold published a great article "Object-Oriented Game Development: Iterative Development Techniques" on Most Agile developers will recognize the basic iterative development techniques. Julian adds the concept of defining features into three catagories: Core, Required, and Desired. (Most projects I've worked we just identified features as either Required or Desired.) You will have to read the article to understand the difference between Core and Required.

Julian also divides up the object development into well defined levels of quality: null, base, nominal and optimal. I really like the idea of defining the quality of object develop along a well defined scale. This quailty scale is then used to divide up the development into prioritized iterations and evolve the objects through the project's life.

Thursday, July 21, 2005

Reflector == Cool Tool

[image of Reflector]

A co-worker introduced me to this little utility for .Net. Reflector is a nice assembly browser that includes a disassembler, call graph and callee graphs. Very nice! I can point it at my assemblies. Then with a few clicks I can drill down into disassembled source for system libraries and third-party libraries that I am calling. Reflector also has some plugins for DB browsing and other stuff.

Reflector is available from

BORG everywhere

I wonder how many things in the I.T. world are named "BORG". On my previous job we had a project named BORG. On my current job, we've also got a project named "BORG". I was just reading the tutorial doc for DbEncrypt here. Guess what, the DB in the tutorial is also "BORG". :)

I wonder, after the Firefly movie will I start seeing things named Serenity?

Wednesday, July 20, 2005

Byecycle looks like a cool idea. The homepage has a wink demo of the plugin (very nice). Byecycle will display a dependency graph of you modules and highlight dependency cycles (plugin for Eclipse). This makes it easy to see problems in design. One realy cool features of byecycle is the way performs automatic layout. The layout engine will keep shifting the diagram as it finds better layouts. Also, check out the people behind this plugin. Some really smart folks.

Yes, a code metrics tool could provide similar information. But the cool graph display makes this a lot more fun. Plus the layout helps you understand the dependencies. Hopefully, if you system is well designed the layout would show your architecture layers since it tries to make the arrows go top to bottom.

Tuesday, July 19, 2005

VS.Net customization

After my eyes got tired from looking at the screen too long, I found a macro that will let me easily change the font size in Visual Studio .Net. The macro is here: Zooming your code in Visual Studio .NET

I wish VS.Net provided some styles or themes with different color schemes. The plain white gets old. I looked at modifying the colors. But the settings were too detailed. It would take hours or days to get a good looking set of colors and fonts setup.

Friday, July 15, 2005

Remote Collaboration

The NetBeans folks have a very interesting collab module. It was designed to assist remote peer-review of code. The model is really cool. You take a file and share it with others. The shared file goes into a "sandbox" so your original is not modified. Everyone can collaborate in the sandbox. Then the sondbox file changes can be merged back into the original file. This could even help assist remote pair-programming (something I've been experimenting with).

There is an article about it here...

The collab project is here ... You can see a demo of it. Just look under "Getting Started" for the "See" link.

If only it worked in IntelliJ and Eclipse.

Monday, June 27, 2005


Today I got to enjoy a Rainbow as the storm came into our neighborhood. If you look carefully to the right of the rainbow, you will see a faint second rainbow. This was a quick snapshot. So I just took the default landscape settings on my camera. I dont have PaintShop Pro installed at the moment (reloaded computer), so I didn't get a chance to straighten the shot. Sorry, my daughter wont give me enough time to install it. :)

[Looks like blogger reduced the image detail when I posted it. Sorry that you cant see the original image.]

Microsoft on Security

I was listening to an MSDN TV clip on SQL Server 2005. Thomas Rizzo makes this interesting, and funny comment...

One thing I want to point out is both SQL CLR and Web Services are off by default when you install SQL Server. I don't want developers out there saying, oh, my god, is this on by default? What if a virus comes along or anything like that? You do have to explicitly turn it on, both the CLR and the Web Services support. We are making sure that it is very secure out of the box.

Ok, secure out of the box... by turning it off! Very nice, maybe I should turn off my Windows XP machine to make sure it is secure as well. :)

Friday, June 24, 2005

Reporting Fun

This is for my Java friends using SQL Server.

Yesterday I went to the MSDN Event and got to see some presentations on SQL Server 2005 Reporting Services. While it is still in beta, it really looked great. SQL Server 2005 adds Web Services directly into SQL Server. So you dont need IIS to talk to a Web Services (SOAP) with SQL Server. A Java application could easily remotely call stored procedures or services on SQL Server using HTTP/SOAP.

Calling SQL Server over web services gets exciting because you can call Reporting Services on SQL Server. Reporting Services looks really powerful and easy to use. So you could use Reporting Services to create those pretty reports (without BizObjects or Crystal Reports), and display the results in your java front end (HTML and other formats are available).

Another nice feature of Reporting Services is the Report Builder. With this, you can export a "Model" of your database. This model contains the definitions of tables, views, relations that the end-user can use to create their own reports. The model lets you decide what tables the user should query in their reports. Then running Report Builder they can drag and drop columns to build reports. Very easy! What if they dont have Report Builder installed? No problem, MS has made it a "no touch install", which means you can simple follow a link on a webpage and the app gets installed and run. Very similar to Java's Webstart. Ok, so now the user has created the report design. In Report Builder, they can post the report design back to SQL Server Reporting Services (it uses secure HTTP/Soap webservices). Then the report is available for future use. Since Reporting Service is exposed as a WebService you can easily call it from your Java code. Super cool. It sure beats the things we had to do at my last job to get some very basic Crystal Reports functions into the application.

Wednesday, June 22, 2005

Eric Gamma on pair programming

In Patterns and Practice Part IV, Eric Gamma is quoted:
"It's also an excellent way to improve your skills. I always learn something from a pair programming session and I wish I would do it more often."

I must agree that pair programming is very educational. I think I've picked up skills better by pair programming than from other activities. Plus it is more fun.

Prevayler everywhere, maybe not.

Prevayler is a great persistence engine for Java. I've used it a couple of times at home when I needed to persist small amounts of data. Prevayler is based on Serialization and the Command pattern. Overall the engine is pretty fast and lightweight. Writing code to use Prevayler is fairly simple. You just have to put your collection into Prevayler and create command objects for every update. The collection and commands have to be serializable.

So now that I'm working in the .Net world, I had a need to persist a small set of objects. I found Bamboo.Prevalence on SourceForge. I was real excited to find a prevayler for .Net. So I started a test project to get familiar with Bamboo (v1.4.4.4). My simple test failed. I kept getting mysterious exceptions while creating the Bamboo engine. So I thought I would look for docs, but there were none. So I thought I'd look at user groups / mail-lists; they were practically empty. I found a couple of articles, but they were out of date. Bamboo's API has changed since the articles were written. So Bamboo is now getting deleted from my disk. It is a tragic end. Using undocumented open-source is not practical.

Recommended: Prevayler for Java

Not Recommended: Bamboo.Prevalence v1.4.4.4 for .Net

Sunday, June 19, 2005


Last week I had a great trip to Vancouver. The weather was sunny most of the week which is really great for that time of year. Sunil and I tried every Indian restraunt we could find in the area. Plus, I got to eat African and Maylsian food. Also the area had plenty of healthy food. I had a great time trying out all the foods. I think my favorite was a Tai place near our office. We walked all around during the week. IT was really good for me to walk so much.

The trip was productive even though it was short. For myself it was really great to meet the guys from India. I realize now that I had some resentment towards the India team. Mostly because of the unwelcome change to my job and for those who lost their jobs in Bham. But after getting to know those guys better, I've put my resentment behind. These guys are just computer geeks like myself. They are in much the same place in life as myself. Trying to raise families and make a good living. Unfortunately for them, they have to be displaced more than me to meet the demands of their career. After getting to know them, I now look forward to working with them.

Friday, June 10, 2005

Good reading... Eric Gamma on Design Patterns

I've been reading a series of articles on Design Patterns. The articles are here, here and here. Eric Gamma shows great experience with developing using Design Patterns, Frameworks, etc. I particularly like the way he defines toolkits, frameworks, and class libraries. Providing some tips about the pros and cons of each. There might be more articles in this series, so keep watching out for them.

Thursday, June 09, 2005

Office fun... MYTOB.AR

This afternoon we are getting lots of emails. The MYTOB.AR worm has taken a bite out of office productivity. Ah the adventures of cyberspace.

What's up?

Life is going well in my new home. The kids are just getting over the latest round of colds. David is teething. Michelle and I have picked up the cold. So everyone is happy. Heather started swim lessons, so she is loving the time to get into the pool. We got a slip and slide for her. Lots of fun! (No I didn't slide on it.) I would grab Heather and pull her down the slide. Since it was her first encounter with it, I didn't think she was ready to try taking a running dive at the slide. Overall, she played in the slides sprikler more than sliding.

In my new house, I ran a cat5 cable to the location where I want to place my computer. I don't want to go wireless. So I had all the fun of drilling holes and pulling cables. It took a lot longer than I expected because I had to keep going to the store to get different supplies. Plus trying to work on the house with two toddlers constently interrupting slowed me down. Now I just need the time to move the furniture and setup the PC properly.

Friday, June 03, 2005


My friend Richard sent me this funny explination of Missile Guidance. Enjoy!

I also found this one: Battleship.jpg which made me think of Raf for some unknown reason.

No Phones, No Lights, No Motor Cars; Not a Single Luxury

I now know that I'm living out in the country. I have no phone service! The last set of thunderstorms knocked out dial-tone in my area. It has been gone for 24+ hrs now (Friday), and BellSouth currently estimates it will be **TUESDAY** to get it fixed.

Thankfully my DSL still works great, so I'm not completely cut off from civilization like the crew on Gilligan's Island. Unfortunately I'm one of those dead-beats who refuses to get a cell-phone. So I don't have any phone at home. I guess I could use Skype to make a call out using the internet. In a pinch I could always run to a neighbors and use their cell phone :)

So not having a phone for a few days will be an adventure. Especially since it falls on a weekend. It makes it harder to coordinate getting together with friends and family. But, it wont be that difficult. If I had lost internet service, then I think I would start looking for a new house.

Monday, May 23, 2005

Great stuff from Yahoo, soon

I've been playing around with MyWeb (beta) from Yahoo. It provides the ability to save a copy of a webpage to yahoo's servers. Then you can search your saved pages at a later time. This is wonderful for me since I'm always reading a lot of tech articles. So now I can save the articles and use search to find something I've read before. This works so much better than using Google or Yahoo seach on a topic because it is like searching through your own memory.

I've run into some problems with the beta of MyWeb. Currently it only works well if you use Yahoo Toolbar. Unfortunately the toolbar can slow down your browser. So I have to turn off the Yahoo Toolbar most of the time. Then just turn it on to save a page.

Yahoo 360 is another product in beta. I'm not in their invitation only beta. So I cant really say how well it works. However, it looks like it has many features I've wanted. You can check it out on Yahoo's site.

Wednesday, May 11, 2005

Java + XQuery + JTidy to parse HTML!

Occasionally I've written little programs to scrape webpages for useful information. In the past I've used various open-source libraries with varying satisfaction. My favorite approach so far is to use Ruby and it's HTML parsing libraries. Today I found an article published by IBM Developerworks that provides another approach that looks really cool: Java theory and practice: Screen-scraping with XQuery. The approach is to first use JTidy to cleanup the badly structured HTML and return the document and XML (4 lines of code). Then using XML tools like Saxon XQuery to easily query XML and reformat the data (several examples that were <10 lines of code, very readable!). Very nice solution!

Saturday, May 07, 2005

Short Game Anyone?

After a long battle (47 turns via email... spanning 6months), the glorious battle resulted in a **DRAW**. Maybe I should look into a short game. Gamasutra has a great article "Making a Case for Short Games" by the author of Strange Adventures in Infinite Space. A great little game. A short game is a nice change from the 20+ hour games I've been playing. While the Author makes a great case for 20min games. I personally tend to like 6 - 10 hour games. Enough time to be engaging, but not so long that I get bored or tired of the gameplay. One of my favorites on the PS2 ... "Ico" was a delightful 10 hours of play. The game was outstanding, especially considering it was an early release when the PS2 was new to the market. Ico stood out to me because of the castle you played in. Ico's world wasn't just a bunch of designed "levels" that you jumped from one to the other. Instead the castle was wonderfully designed and architected. Each set of rooms which made a small level, fit beautifully into the design of the entire castle. From the towers and parapets of some areas you could see other areas of the castle. All the rooms fit together and made sense. It really felt like you were inside a old castle that was once real and functioning medieval castle. I hear the Ico team is cooking up a new creation that sounds really really cool... Shadow of the Colossus where the level isn't a static castle; instead its a living behemoth colossus creatures. The E3 videos look fantastic!

Soon I will get back in the general's seat and start off another battle against my nemesis Matt in Combat Mission. Our last battle, while a draw, did have some really cool events. I would have completely lost if I hadn't made a desperate and crazy dash up the middle to get behind his tanks. Even then he made a great move to repel my assault on the strongest hill on the map. Only then did a single shot from an overwatching tank stop him. The battle really did spell victory or shattering defeat on that single shot. If I hadn't gotten the kill (and that was a really lucky line of sight); he would have been able to secure a great position and hold my forces off. The results would have been a defeat. Instead, my play worked and finished off his tanks. It was just a mop-up operation after that. Unfortunately, I didn't have enough time to take the highest scoring object from him before the time ran out. Matt was able to claim a draw. We shall have to fight again!

Wednesday, May 04, 2005

... disconnected ...

I don't have Internet service at my new house. It will take a few days more to get setup. So I haven't been able to add to the blog. Sorry, more to come later.

Monday, April 18, 2005

More AOP and Annotations...

Blogger crashed with a 500 error when I first made a great post on this topic. So instead you are getting the shortened version now. I'm too lazy to retype all the stuff I said before my post was lost to the bit bucket.

AOP and metadata: A perfect match, Part 2 go get it, read it, learn from it, enjoy it.

Friday, April 15, 2005

Ratchet and Clank (Playstation 2)

I have to give Ratchet and Clank it's own post because I've found it such an enjoyable game. I just completed R&C 2 (Going Commando) and found myself diving into the *Challenge Mode* where the game is replayed with all the stuff you gained, but the enemies are 10x stronger. The game is one of the best platform games I've played. The levels are nicely designed and fun to complete (not a lot of exploring, each level usually has a couple of branches). One aspect of the game I've liked is the variety. The game has a lot of variety in weapons, gadgets, levels, and things to interact with. Another fun part of the game is the cut scenes. They are really well matched to the game world and plot. In addition the designers did a great job of adding nice touches of humor to it.

If you haven't tried R&C, I recommend it. It is rare that a game holds my interest to 100% completion. Even rarer that I'll complete both the original and the sequel. Yes, I did complete R&C the original game a year or two ago. Fortunately I kept my save game. In R&C 2 I was able to recover the weapons from R&C 1 that were in my saved game. This really is a fun game series. Now if only R&C 3 would become a *Greatest Hit* so I can buy it cheap.

I'm going to Vancouver... or India... or both?

The latest news on my job is that I'm the "Solution Architect" on one of our products that is developed up in Vancouver. Nice! I'm think free trips to Canada. But then our top management makes an big announcement... all development and QA is getting outsourced to India. Ok, free trips to India? Fortunately as an Architect I get to keep my job. {I'm learning to expect anything with this company.} So now I've got to take knowledge from the unfortunate folks in Vancouver, and give it to a new offshore team. We will have to see how this new mandate works out. The reason behind the move to offshoring is the same found at the previous company. The good old boys at the top are involved with both companies. I really feel for the guys I've gotten to know here in Birmingham that are loosing their jobs. I pray they can all find something better.

On a lighter note, I've had the chance to remotely develop from my old house in Atlanta to my new job in Birmingham. It worked very well. I was able to concentrate while at home. Connectivity was good over my dsl. I was able to interact with the Bham folks over IM. Overall, I'd say I got a bit more done from home than I would from the office. At home I was able to keep interruptions to a minimum. I was also able to focus more. At home I was less concerned with the time of day. Which means I took lunch when it was convienent with my work tasks, and was usually much shorter. Also, the work day was a little longer because I started earlier and didn't stop until later. I don't think I'd want to telecommute all the time, but it is nice.

Tuesday, April 05, 2005

Cool Internet Tools

The 5th Annual Search Engine Watch Awards published their results. From it I found a couple of useful tools I'll have to use.

Jux2 is an interesting meta search engine. I like the way it clearly shows what was missed by my favorite search engine Google. Very interesting to see how Google, Yahoo and Jeeves stack up through the lens of Jux2.

Clusty is a good way to handle those search that bring up too many unrelated items. For example, I was searching for public swimming pools in my area. The usual search engines found pools for every city and county that sounds similar to mine. Thus making it tooo hard to find what I wanted. But Clusty got it right by clustering information by location! The results were better than Google and Yahoo local which seemed to just bring up business related to swimming pools.

Feedster is an online RSS reader like Bloglines. While I'm not ready to convert from Bloglines to Feedster, I did find the Feedster RSS Search very useful. By entering in a topic, it found current blogs about the subject. Making it easy to find the buzz on that topic.

Monday, April 04, 2005

eXtreme Programming

The folks over at Cenqua have really been working hard at making XP easier. Check out there latest product... the PairOn. I wish I could get one of these. I've been using one their Commentator for a few weeks and have been very happy with it. I wish it let you define your own custom dictionary. People know I frequently mistype words, so it should have an option to enter my commonly misspelled words and typos to give it more realism.

On a more practicle side, I looked at their FishEye product. While it looks pretty, I'm not sure that it helps solve anything for me. Personally I'd find Blame more interesting and useful.

Wednesday, March 30, 2005

House Sold

Yeah! We have sold our house. So the move will take place at the end of April! It will be great to have everything and everyone local again.


I was reading a blog on boo, a python like scripting language on mono and dotNet. Boo looks very interesting because they have gotten rid of some of the python syntax that I found really bad. For example, OO programming in python required the use of "self." everywhere. This got really bad quickly. Fortunately Boo gets rid of that cluncky syntax.

Anyway, the Boo article I was reading had a link to a short demo. While the demo wasn't that interesting, I found the demo tool interesting. He was using a freeware product called Wink (link). Wink can capture a demo from your screen. The resulting demo is shown using flash or other tools. Looks very nice! And did I mention that it is free :)

Thursday, March 24, 2005

Happy Easter!!!

It is always nice to have a little holiday. Now that spring is upon us I'm going to have to shave off the hunter's beard. At least I wont look like this guy anymore.

This week we had fun with Tornados. One *possible* twister came up on the radar near by and it's path would have gone within a mile or two of the house I was in. Luckly some of the winds that were fueling the storm were too strong and broke the thing up before it could really do anything. At least I did not find myself featured on this page.

Have a Hoppy Easter!!!

Friday, March 18, 2005

Aspects, Annotations and Refactoring

Ramnivas Laddad has published a great article on IBM Developer Works. The article is here. I knew that you could use Annotations to mark jointpoints for Aspects. But in his article he shows how you can use Aspects to inject Annotations into your classes. In addition he takes it a step further by giving a great example of refactoring a Transaction Aspect to eliminate coupling and make the aspect more reusable. This article is a great read for anyone working with Aspects and Annotations.

Wednesday, March 16, 2005

Separated at Birth

Check out Bill Faulkner's Bio. His face is very familiar! One of the people at my new job has worked with Bill since he is a leader in the MRI field. I guess he must have some of my intellect as well as my good looks! :)

Thursday, March 10, 2005

NAnt expressions

After exrecising NAnt a lot, I'm really liking many of it's features. It still has a few rough edges, but overall it has been a good experience. The power of it struck me when I had a large section of copied code (nant xml build script) that I was able to refactor to remove the copied code. When I was done, I sat back and thought "Wow! I could never have done that in Ant".

To make this post more interesting I'm going to include a little code to demonstrate the NAnt expressions. I'm not going to show the refactoring because it would take too long to explain. So instead I'm going to show a simple subroutine task that converts paths which I pull out of Visual Studio project files. Some of the paths refer to webproject and have to be converted from URL's into local file paths. This subroutine does the conversion...

<target name="">
input properties:
output property

When path.temp property contains a URL (i.e. starts with http://), this target will search
the directories directly under wwwroot (i.e. ${wwwroot}/*/) for the file contained in
path.temp. When the file is found, it will replace the URL in path.temp with the full
path to the file. If the file is not found, the build fails with a descriptive message.

If path.temp is not a URL, then path.temp is left alone.
<if test="${string::starts-with(path.temp,'http://')}">
<property name="isFound.temp" value="false">
<foreach item="File" property="filename">
<include name="${wwwroot}/*/${path::get-file-name(path.temp)}">
<property name="isFound.temp" value="true">
<property name="path.temp" value="${filename}">
<if test="${bool::parse(isFound.temp) == false}">
<fail message="Unable to find ${path::get-file-name(path.temp)} under ${wwwroot} directory.">

Notice the ${...} isn't just a simple property replacement. Instead in NAnt, I can make function calls ${string::starts-with(...)} for example. Also, I can have simple expressions like ${bool::parse(aProperty) == false}. Very cool stuff. Ant needs to catch up.

Tuesday, March 08, 2005

A replacement for Ant

As my friends know, I dont like Ant. Fortunately I've had the chance to work with nant (Not Ant). NAnt has really learned from many of the limitations and mistakes in Ant. NAnt has many nice features: expressions, dynamic properties, overwritable properties, and .Net scripting to name a few that I've used this week. The .Net scripting is very nice since you can quickly create a function in C# to include in your build. Then it is easy to call the function using NAnt expressions. Plus C# has access to all the functions you could ever need or want in a build script. The result is a cleaner and more flexable build script than possible with Ant. Next time I need a build script (even for a Java project), I'm going to use NAnt and not Ant. (see also nantcontrib)

Now if they would get rid of the XML based build scripts.

Friday, March 04, 2005

Apress Free Books Apress has some free for download tech books online. The subjects are PHP, Perl and .Net. Too bad there isn't any Java stuff.

Monday, February 28, 2005


Week 1 of the new job has gone well. The Microsoft brain implant seems to be working fairly well. A couple more weeks and they tell me I wont remember that other language that was like J#. C# isn't such a bad language for an Java programmer like myself. At least I don't have to hand code grid layouts. One thing I do like is the way NUnit uses attributes to mark class and methods as test cases. This seems nicer and more flexable than using naming conventions in JUnit. Maybe JUnit could add this feature in a future release.

In other news, I've finally gotten a contract on my next house. I've found a nice little hood down Hwy 280. The area has really been growing super fast in the years I was away in Atlanta. Yes, even in Chelsea Alabama there is a Starbucks on every corner.

Sadly a good friend of mine, Stan Ragan passed away this week from complications related to his fight with brain cancer. Stan and I had a great time in the years I got to know him. We shared the same love for video games and technology. Fortunately we both share the same faith in Christ, so I look forward to seeing him again in the next life. Dealing with losing Stan has provided a time for deep reflection into my own beliefs. It is good at times to question what I believe and why I believe them, since once again I find the answers solid and worthy of my faith. Goodbye for now Stan.

Thursday, February 17, 2005

Hammer's Book Reviews

My good friend and mentor sent me an email about several books. I thought his email important enough to share...

From J. Hammer:

Books that I have found useful recently include:

Five Patterns of Extraordinary Careers (Citrin, Smith)
This is good for understanding career paths and your options in muchgreater detail.

Good to Great (Collins)
This book is stunning. What factors would cause an average company topull away from its competitors for a long period of time (i.e., totransition from good to great). A lot of people will read this book,but few will be able to pull off what it recommends. It may alsoirritate you when you realize that you work for (only) a good company.

Execution: the Discipline of Getting Things Done (Bossidy, Charan)
This book had a big impact on my thinking about employee evaluation,employee development, HR, discipline, and (most importantly) businessmanagement that actually knows what it is doing.

Elements of Mentoring (Johnson, Ridley)
Patterned after Strunk and White's classic, this book synthesizes a vastbody of research literature down to what a mentor needs to know.

Wednesday, February 16, 2005

One more time... reformat reload reinstall.

After reading one more reason why i hate windows from Eric, i have to admit I'm feeling the same towards WinXP. I replaced my mother board; because the MB alarm on my old board was going off. However winBlows XP (eXtra Pain) couldn't boot. The stupid thing would just lockup or reboot during startup. In safe-mode it would stop after printing "mup.sys". After four failed attempts (16+hrs of time) to recover or repair windows I had to resort to just completely reloading windows. Of course this process didn't work well and took two attempts before reaching nerdvana. (There is no way the Matrix could exist if we cant get a simple OS to work) Didn't I just do this about 6mo ago?

Now come the joys of reinstalling all my apps. At least I get to review my list of stuff to backup carefully. Fortunately It means I'll finally get around to updating all my software to the latest versions.

First Apps to Install:
  • Mozilla Firefox with the following extensions
    1. ieview
    2. dictionary search
    3. bugmenot
    4. download manager tweak
    5. copy plain text
    6. adblock
  • Java 5
  • Open Office
  • Mozilla Thunderbird
  • Password Safe (sourceforge)
  • CvsNT and WinCVS
  • Trillian Pro
  • Serene Screen Marine Aquarium 2.0 (screen saver)
  • JASC Pant Shop
  • PowerToys for XP: TweakUI, Power Calc, Command Prompt Here
  • Combat Mission Afrika Korp (look out Matt D, this battle is mine!)
  • Savage (s2games)
  • Halflife2 and CS Source

I wonder how long it would take to reload OSX on a mac mini. I'd bet it wouldn't take a whole week. Funny thing, I've never had to reload my Playstation 2. If I could just send email, print, open office, and surf the net (including flash) on the PS2 or a similar console I wouldn't need a *Personal* computer.

Thursday, February 10, 2005

Computer Crash

Yesterday afternoon I was greeted with a siren from my PC and WinXP would not boot. Even SafeMode will not boot. I'm guessing my motherboard is having a fault. Fortunately I have an extra mobo I can use. But it means I'll have to use the kids PC for a while. :(

Monday, February 07, 2005

Java Generics vs the KISS principle

The designers of JSR 014 Java Generics really missed the "KISS principle"

Before Java 5, we only had to deal with a simple class-cast exception:

ArrayList list = new ArrayList();
list.add( new Bar() );
Foo foo = (Foo) list.get(0); // class cast exception!

This problem sometimes happened at runtime. It is generally a small problem, easily eliminated. Usually good unit tests and functional testing found the problems. The problem was simple enough to understand and explain. Usually even the most junior developers could understand this issue and learn to avoid it with little difficulty.

In Java 5 we now have to deal with Java Generics:

ArrayList list = new ArrayList();
list.add( new Bar() );
Foo foo = list.get(0); // compile time error :)

Everyone's initial impression is "Wow that's a great idea!" Unfortunately the difficulties of Java Generics are not touched in such a simple example. Just take a look at Java thoery and practice: Generics gotchas and the Java Generics FAQs for details about the special problems introduced by generics.

So instead of having to work around one simple class cast problem, we have to work around a complex mess of special rules and gotchas! I have seen experieced developers (myself included) scratching our heads trying to get through the gotchas introduced by Java Generics. All the special rules and problems introduced in Generics are very hard to understand and memorize. Thus Java Generics has violated the "KISS principle." Things really don't work as expected in Java Generics. We have traded one simple problem for a hundred pages of special rules! (Just look at the size of the FAQ)

It will be interesting to see what efforts are made in future JSRs to correct the gotchas in Java Generics. I would imagine adding something to keep the variable's Generic type information at runtime would help.

Friday, February 04, 2005

Six Laws of Software

Interesting article... Six Laws of Software

Advocates very focused, easy to use programs released through small increments. This model certainly works in the Open Source world. But does it apply to commercial software?

Thursday, February 03, 2005

Project planning

I read this good article on Gamasutra today: Making Great Games In 40 Hours Per Week (login required, free signup)

A few points I really liked:
  • "someone must be functioning effectively as the builder and keeper of the schedule". My personal additions to this is: Some people are better at managing project plans and schedules and estimates than others. The *someone* who owns the schedule should be a technical person, capable of understanding the details of a task. Without the technical knowledge they cant judge the quality of estimates given by the engineers. Also from my experience with XP, I favor measuring the progress on tasks frequently. This feedback is important to keeping the schedule in touch with reality and knowing when its time to replan.
  • "There should be no such thing as a five-day task" If your task estimate is 5 days, then you need to drill down into more detail to make your estimate. This is difficult in Analysis and Design phases of the project when so much can change later. I agree tasks should be examined in detail to get estimates. However, this detail can create the illusion that your estimates are accurate. More times than not, your estimates are still inaccurate. A multiplier or fudge factor is still required to allow for changes during the project lifecycle.
  • "Know What Can and Can't Be Cut". Yes, I learned this the hard way on a recent project. The timeline was set by business factors so that only a minimum implementation could be completed on time. Unfortunately we had nothing to cut! So when the unavoidable technical problems happened, schedule slipped. A project should always have prioritized features, and some fudge features that can be cut.
  • "we (usually) add a fudge factor - from 15 to 25 percent - for unexpected events." Howie says he uses a percentage multiplier. I'm impressed that his multiplier is only 0.25. In my experience, I've learned the multiplier depends on the person(s) giving the estimate. Some people typically give more accurate estimates, other people tend to give more optimistic estimates. In addition to the reasons Howie lists for a fudge factor, I would add *reality changes*. That is, during the lifecycle of a project, requirements become invalid because the real world outside is changing. Therefore a project plan must include a fudge factor for *reality changes*, and plan to revisit and modify some percentage of the requirements in the middle of the project's development.
  • "Regularly Update Your Schedule" This gets back to my prevoius comment about tracking progress and replanning.
  • "Use Overtime Sparingly" Howie goes on to talk about scheduling crunch time. I still prefer adding fudge factors to the plan. Fudge factors come in two forms: features that can be cut and good fudge time added to the plan. However, even the best plans can get into trouble. So I liked his ideas of planning and scheduling crunch times. My last project had crunch time in late December! Yuck!
  • "People-Management is Critical" I have yet to work at a company that really does a great job at People Management. However, pretty much all companies I've worked for have done a fair to good job at people management. I guess it is just a trade off between productivity and cost.

Monday, January 31, 2005

Leaving Town

Ok, I've started a blog. So everyone can easily keep up all the great stuff. "Like what?" you ask. Well if you dont know, you haven't been around me enough :P (Isn't it easy to sound like an egomaniac online!)

Anyway what is new and cool stuff:
  1. Moving to Birmingham
  2. Mac Mini (ok, I don't own one, but I still think it is cool)
  3. Ruby the programming language link
  4. Simpson's Hit and Run game
  5. Password Safe link
  6. Kaki King; great music! link
  7. Katamari Damachi game link
  8. BBQ (always good stuff)
  9. Bloglines link
  10. Shichinin no samurai
Not cool stuff:
  1. House hunting, what a headache.
  2. Sky Captain; terrible movie, stupid plot, just stupid. Can I have those two hours of my life back now?
  3. <XML>Everywhere<\XML>
  4. Cell phones
  5. Inconvient weather (ice storms in Atlanta)
  6. Really inconvient weather (tsunami)
  7. numbered lists
  8. Back pain
  9. the terrible twos
  10. Saying good-bye to friends in Atlanta
So there you have it, the start of another silly blog. Enjoy!

- Greg