Tuesday, December 22, 2009

Grails "pluginManager" error

STS has the cool feature where it dynamically recompiles your Grails application when it senses that you've made code changes. This can have an unexpected side effect. If you get an obscure message like the following:

Error creating bean with name 'pluginManager' defined in ServletContext...

Basically it seems related to a mismatch between the domain objects and the database schema. This is different from GORM and Object-Relational Impedance Mismatch... it is simply an unstable condition that might occur with the right combination of changes.

Unfortunately, I can only suggest saving and testing often, and if you see this message, try commenting out the "static hasMany" command in your domain object until it goes away.

Investigating and installing Grails

Based on a recommendation (and some newly acquired knowledge), I'm in the process of investigating Grails and perhaps GWT. This post, and likely the next few posts, will chronicle the installation, setup, and initial experience.

To install Grails, go to the Grails Home Page and download the latest version. Go to the Documentation page and follow the installation instructions. I am using a Debian-based Linux so I extracted Grails into /usr/share/grails and added GRAILS_HOME to my .bashrc. Testing Grails worked without any issue. My current version is 1.1.2.

It then occurred to me that I would really like to implement Grails from within Eclipse and to explore my options for Eclipse add-ons or integration. I chose to use SpringSource Tool Suite (STS).

For the most part, you'll follow the instructions on this page except STS-go here instead to download STS. Click on the appropriate OS link to the right of the Downloads section then follow the instructions at the bottom of that same page. Note: You may want to invoke the installer using "sudo" if you plan to install in a location like /usr/share. However, when asked to launch STS at the end, say "no" and launch STS explicitly. The executable is /usr/share/springsource/sts-2.3.0.RELEASE/STS

Once you have STS installed, go back to this page and follow the instructions to install the Groovy and Grails plug-ins. Note: If you installed STS as "sudo" in the previous step, you may want to invoke STS using "sudo" to install the plug-ins. Before I did this, it hung at about 67% for no apparent reason. For example, execute "sudo /usr/share/springsource/sts-2.3.0.RELEASE/STS" from a shell and use that session to install the plug-ins.

Wednesday, November 18, 2009

Use Basic Types for Web Services

Today I encountered the following error message:

org.apache.axis2.databinding.ADBException: Any type element type has not been given

I have defined my Web Service code as follows:

public ArrayList ListNamesService();

When you generate the WSDL using wsdl2java, it creates a data type called, "anyType", which is WSDL's way of saying you'll be passing through an Object (of some indeterminate type). This generates the above runtime error.

The solution is to do this:

public String[] ListNamesService();

which may seem archaic given the Java Collections classes, but at least an array of Strings is compatible across all platforms (which is a great benefit). So, aside from getting the error messages to go away, use basic types for Web Services.

Tuesday, November 17, 2009

It's the CLASSPATH, stupid!

I've been tearing my hair out for the past two days struggling with the Apache Axis2 Web Services engine. After having had figured out how to integrate Axis2 with Tomcat (see prior blog), the next step involved writing a client to access the Web Service, then integrating that functionality into a servlet.

First off, follow this tutorial.

Following are my tips for getting it done the easy way. Note, I'm sure server administrators will cringe when they see some of my solutions but I'm only looking to prove out the code. This is a development setup on my home computer. 'nuff said.
  1. Create a separate project for your Web App (UI, servlets), each Web Service, and each prototype Client code.
  2. Getting the Web Service to work is easy: follow steps 1 through 4 of the tutorial.
  3. When going through step 5 (generating Java code from the WSDL), set the destination directory to your Client project /src directory. Note: the generated package name is "org.apache.ws.axis2". At first I thought this was a bug and it was the single biggest source of my headaches.
  4. In the client project, make 100% certain you've added every-single-jar in $AXIS_HOME/lib to your project CLASSPATH (Project > Properties > Libraries > Add External JARs...). If the Eclipse auto-compiler stops complaining about your imports, you're good to go.
  5. Compile your Client project. Note, in the tutorial, you run your test program at this point and it "just works". That's BS because they took a serious shortcut by putting the Client code in the same package as the Stub code. In real applications, you won't have that luxury. Package the resulting classes using "jar cvf MyJar.jar org". You will need to be in the /bin directory of your client project for this to work correctly.
  6. At this point, you can compile and run your servlet, but you'll get a run-time error. This is because the Tomcat servlet runtime does not have the same CLASSPATH as what you've configured in Eclipse. This is the key point that took me days to discover
  7. Copy that JAR file to $TOMCAT_HOME/lib (yes, you heard correctly... just do it... it works)
  8. Copy all JAR files in $AXIS_HOME/lib to $TOMCAT_HOME/lib (sacrilege!). If it makes you feel better, make a copy of the $TOMCAT_HOME/lib directory before making any changes.
Instead of steps 7 and 8, you can modify the CLASSPATH of the Tomcat servlet runtime. However, I don't know how to do that and was pretty burnt out of the topic by the time I'd figured out the workaround...

It should "just work" now.

Sunday, November 8, 2009

No Targets Available for the Android SDK

The Android SDK uses an integer to identify the minimum SDK version for which your application is compiled. Without it, older versions of the Android OS could attempt to launch a program written for a newer version of Android and it might not be pretty.

When you first install the Android SDK (version 2.0 pre-release) and the Eclipse ADT, then attempt to create a new Android Project, you might see this warning: "Error: Target id is not valid. Use 'android list targets' to get the target ids". Following this instruction leads you to find that no target SDKs have been installed.

I believe Googled has packaged the 2.0 release to be an upgrade to the 1.6 release. However, they don't make that notion clear one way or the other. My solution? Skip it, go to the SDK v1.6 download page and get that instead. This becomes really obvious if you examine the size of the tarballs (2.0 = 24Mb, 1.6 = 573Mb).

Thursday, November 5, 2009

Getting Apache Axis2 to work from within a Tomcat servlet engine

I generally prefer to have my application services hosted from a single source. It seems like overkill to have an Apache server (port 80) a Tomcat servlet engine (port 8080), and an Axis2 Web Services server (also on port 8080). What's even crazier is that all three servers come from the Apache Foundation yet getting them to cooperate can be much more troublesome than you'd expect.

I successfully installed Axis2 using these instructions, which worked well up to and including "Building a Standalone Server". The one caveat being that you need to remember to stop Tomcat:

sudo /etc/init.d/tomcat6 stop

because the Axis2 server is configured to run on port 8080 by default. You could change the port by editing $AXIS2_HOME/conf/axis2.xml... but the instructions don't tell you that. I figured it out on my own.

Moving on... so now I want to run the Axis2 Web Services engine within my servlet context. In other words, I want Tomcat to delegate WS calls to Axis2. The instruction for doing this is to copy the axis2.war file into the webapps directory of Tomcat. Here's the kicker: There are TWO webapps directories! One is located in TOMCAT_HOME (which, on Ubuntu is /usr/share/tomcat6) and the other is located in TOMCAT_BASE (which is /var/lib/tomcat6). The latter is the correct location btw.

If this worked correctly, Tomcat will expand the axis2.war file into a directory structure starting with TOMCAT_BASE/webapps/axis2/.

At this point, the above instruction set said I supposed to see the Axis page magically via Tomcat but what I saw was an HTTP 500 error indicating something about permissions. After some Googling, I found this forum, the final post contained the solution to the last roadblock: to disable TOMCAT6_SECURITY.

It now works, and you get the Axis2 "Happiness Page" as originally indicated in the instructions. Barf.

Wednesday, September 16, 2009

Gem install errors

When installing gems, sometimes you get the following message:

dean@Dean-Ubuntu:~$ sudo gem install mongrel
Building native extensions. This could take a while...
ERROR: Error installing mongrel:
ERROR: Failed to build gem native extension.

/usr/bin/ruby1.8 extconf.rb install mongrel
extconf.rb:8:in `require': no such file to load -- mkmf (LoadError)
from extconf.rb:8

The quick answer is:

sudo apt-get install ruby-dev

I guess ruby-dev contains the native headers that the finished product "just Ruby..." doesn't have.

Installing Rails on Ubuntu

After install Rails using apt-get, I received the following message:

dean@Dean-Ubuntu:~$ rails -v
getopt: invalid option -- 'v'
Terminating...

This is definitely unusual and not the way rails works on my Mac. I found this blog post, which describes a perfect method for getting rid of the problem. Basically, it seems that it is preferable to install rails using gem, not using apt-get. Go figure...

Installing PostgreSQL

On a Debian Linux distribution such as Ubuntu, you can install postgresql (and a graphical administration tool) by using:

sudo apt-get install postgresql pgadmin3

and it merrily does its thing. It even starts the server for you. However, the default installation of PostgreSQL creates the root user "postgres" with no password. Furthermore, PGAdminIII requires that you enter at least one character in the password field or it complains. Doh!

After having experienced this twice (once in Mac OS X and once in Ubuntu Linux) I thought I'd jot this down for generations of administrators to come. Essentially, this post gives the best description of what to do:

  • Edit the pg_hba.conf file. The post gives the most useful information: the directory in which this file is located! (/etc/postgres...)
  • Instead of "md5", other posters say to change it to "trust". If you're running a dev system like me, "trust" is supposed to have fewer auth checks
  • To get the config changes to stick, restart using "/etc/init.d/postgresql-8.3 restart
  • To change the password, use "psql -U postgres". The master database is the default. psql should be in /usr/bin, which should be in your path
  • The semi-colon in the blog is important. You should get the response, "ALTER ROLE" if it worked properly

Trying to open PGAdminIII again, I was able to give it a non-blank password, which made it really happy.

Tuesday, August 4, 2009

vi cheatsheet

I try to avoid "vi", but sometimes it really is the most convenient editor to use when you're in an xterm window. So here's a cheatsheet I found on the Web. There might be better, but this seems good enough for now.

Thursday, July 30, 2009

"The bundled mysql.rb driver has been removed from Rails 2.2. Please install the mysql gem and try again"

I encountered this problem before but apparently forgot to write a blog on the topic. So... after having re-searched Google and re-lived the pain, here is the short story...

This message appears under the following situations: You don't have MySQL 5.0.77, you don't have Rails 2.2.2, and you did not build the Gem: mysql-2.7. There are a number of posts on this topic, most of which take you absolutely nowhere. Just do the following (in order, and assuming you are running Mac OS 10.5.x):

  1. Install MySQL 5.0.77. To check your current version, type: 'mysql --version'
  2. Switch to your administrator user account using: 'su - Admin' (or whatever the admin account name is)
  3. Verify that the following line exists in .bash_profile: 'export GEM_HOME="/usr/lib/ruby/gems/1.8"
  4. Verify that the following lines exist in .gemrc: 'gempath:' and ' - /usr/lib/ruby/gems/1.8'
  5. Type the following set of commands:

    • cd /usr/lib/ruby/gems
    • sudo chmod 777 1.8
    • cd 1.8
    • sudo chmod 777 gems
    • sudo chmod 777 cache
    • sudo chmod 777 specifications
    • sudo chmod 777 doc
    • cd ..
    • gem install -v=2.2.2 rails
    • gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config


    The chmods are there because in Mac OS, the "Admin" user is different from the "root" user. Because they might have different GEM_HOME environments, it is easier to just make sure the Admin user paths are set properly and execute gem installs as Admin. Trying to enforce gem install paths on the root user is bothersome, to say the least.

    If you don't upgrade Rails to 2.2.2, you get an error message when you try to use 'mongrel_rails start'.

    If you don't upgrade the mysql gem you get the error in the title of this blog entry

    Important note: At this time, 'mongrel_rails start' should work but if 'rake db:create' still shows the error, copy the mysql-2.7 gem directory to /Library/Ruby/Gems/1.8/gems/. This indicates that the Web server is pointing to a different gem directory and I haven't figure out yet how to change that.

Wednesday, July 8, 2009

Compiling ffmpeg and ffplay

Wow, this topic can go on and on... Let me see if I can distill it to the very essentials.

First, to code in C or C++ effectively, get Eclipse for C/C++ Developers. That said, you don't need Eclipse for the rest of this blog entry.

Download these three things: LAME, SDL, and FFmpeg. You may have trouble downloading LAME as the SourceForge server seems to be unreliable. Compile them in that exact order (this is very important). Use the instructions here as well as the instructions included in the downloads. I'm distilling days of effort into a single paragraph so I'll update this entry or add a new one if I try this again...

When you're done, a successful adventure will mean you can invoke the ffmpeg transcoder as well as the sample ffplay by entering them as a Unix command.

Friday, May 29, 2009

Creating a UIBarButtonItem programmatically

This counts as one of those things that I'll want to do again in the future but will have to re-research it by poring through old code or Googling (yet again). Sometimes for brevity, it isn't ideal to have a View Controller *and* a XIB for every little thing you want to present. The XIB is an extra file and the symbolic links to the controller can be a pain to maintain. To create your own action button (say, in the upper-right corner), use the following code:

- (void)viewDidLoad {
UINavigationBar *navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:@"Load Colors"];
[navBar pushNavigationItem:navItem animated:NO];
UIBarButtonItem *editButton = [[UIBarButtonItem alloc] initWithTitle:@"Edit"
style:UIBarButtonItemStyleBordered
target:self
action:@selector(toggleEdit:)];
navItem.rightBarButtonItem = editButton;

[self.view addSubview:navBar];

[editButton release];
[navItem release];
[navBar release];
[super viewDidLoad];
}

Thursday, May 28, 2009

Using @class and #import

The iPhone SDK contains two directives that use can use to declare other classes in your project. They are:

@class YourClassName;

and

#import "YourClassName.h"

The differences between the two are not clearly explained (in anything I've read) but the impact is very substantial. While many writers dismiss these as interchangeable, they are not! This might be a situational example, but this is how I use those directives.

First, use @class only in the header file. This notifies the compiler that you are instantiating variables for use. For example:

@class YourClassName;
@interface TheCurrentClass {
YourClassName *instanceVar;
}
@property (nonatomic, retain) YourClassName *instanceVar;
@end

While you get a nice way to define your class instance, the @class directive does not provide any of the underlying methods and variables available to that class. To access anything meaningful in your instance, you must use #import in your implementation. For example:

#import "TheCurrentClass.h"
#import "YourClassName.h"
@implementation TheCurrentClass
@synthesize instanceVar;
-(void)viewDidLoad {
YourClassName *tempInstance = [[YourClassName alloc] init];
self.instanceVar = tempInstance;
[tempInstance release];

[self.instanceVar someMethod:value];
}

Again, this is situational, and the actual code will vary depending on your need, but the point is that the #import gives you access to "someMethod:". If you don't use #import in this case, you will get the error I referred to in the previous post.

Unable to find instance method in another class

I'm refactoring my code because I need a better understanding of retain/release of static variables, but that will be another post...

I decided to implement a trick I learned *after* I started ColorMatcher, which was to instantiate between classes using "@class" (as opposed to "#import"). A new compiler warning appeared:

warning: no '-setDialType' method found

I'm not sure about the reasons just yet, but when you see that warning, use #import instead.

Wednesday, May 27, 2009

Determining the dimensions of a text string before display

With 2D graphical rendering, such as Apple's Quartz SDK, you occasionally want to display text. However, the text position is something you do manually and could change, depending on circumstances (for example, if the text is centered on the screen). The short answer, is this is how you do it.

The big epiphany for me was that I was trying too hard to stick purely with Core Graphics and shying away from Objective-C. However, Apple has taken pains to ensure that, even though the syntax and nomenclature is somewhat of a mish-mash, they do interoperate nicely. Here is an example of my final code:

-(void)drawText:(CGContextRef)context text:(NSString*)text color:(UIColor*)color {
UIFont *font = [UIFont systemFontOfSize:24.0];
CGSize size = [text sizeWithFont:font];
CGPoint center = CGPointMake(160.0, 100.0);
CGPoint origin = CGPointMake(center.x - (size.width / 2.0), center.y - (size.height / 2.0));
CGContextSetFillColorWithColor(context, color.CGColor);
[text drawAtPoint:origin withFont:font];
}

It took way too long to get this code. I hope it doesn't happen again... *sigh*

Tuesday, May 26, 2009

Converting a NSString to a char array

I spent the better part of today wrestling with this problem. In fact, I'm the poster of that question. The short of it is that I have have a lot to learn about the retain/release cycle of Cocoa variables. What's weird is that I could swear I was re-initializing the variable each cycle but who am I to argue against a working solution? I'll figure out the root cause someday...

Wednesday, May 13, 2009

Re-initializing a View

When switching between multiple views using a UITabBarController, by default the view is only initialized the very first time (viewDidLoad). If a state changes that impacts a view the second time you visit it, the appropriate method to overload is:

(void)viewWillAppear:(bool)animated;

Tuesday, May 12, 2009

Accessing the Root Controller from a sub view

One of the harder concepts to grasp (as someone who is new to Cocoa and the iPhone SDK) is how to navigate through the class and object hierarchy. Sometimes you feel like a rat in a maze with dead-ends every which way. In one example I wanted to do something seemingly simple: programmatically change from one tab (in a UITabView) to another, as if the user had done so themselves.

Surprisingly, this was a difficult problem to Google because the questions and answers never aligned to match my specific needs. In an unusual burst of insight, combined with some clues from Apple documentation and user posts, I came up with the following technique.

First, in the AppDelegate @interface (the main class), there is the line:

UITabBarController *rootController;

Next, in one of my subview controller interfaces, I have:

ColorMatcherAppDelegate *app;

which provides a pointer from a minor class to the main class. Next, I add the following to the @implementation of that same class:

app = [[UIApplication sharedApplication] delegate];
app.rootController.selectedIndex = 0;

When all is said and done, it only involves a few lines of code, but they sure were hard to find!

Thursday, April 30, 2009

The UIView class and the View XIB

One of the harder concepts to absorb when first learning the iPhone SDK is the "directionality" and control flow of UIView objects and UIViewController objects. Both can be created using the Interface Builder and both can be created entirely from code. I can't possibly go into all of that right now, but let's just say that if you stick to one technique or another, you'll "get it" pretty quickly but you won't be able to solve all the problems that arise.

One such problem is when you need to programmatically change a View (such as, refreshing 2D graphics using Quartz) but you also want a XIB for that view, making it easier to embed standard controls. I found a great answer to this question at this Web site.

In short, you create both a custom View (derived from UIView) then you point the XIB's View's Identity to that custom class. When you refresh graphics using drawRect(), it refreshes right onto the View you created with Interface Builder. Refer to the above link for code samples.

Monday, April 27, 2009

Forgetting Regular Expressions

It has been quite some time since I've used Regular Expressions. I've never been such an expert that I could make code practically wash dishes using just one line, but I used to be able to do some pretty cool tricks with minimal coding effort.

Coming to the rescue is Rubular: "A Ruby Regular Expression Editor". This is a very handy Web-based tool that allows you to enter an expression and to provide a sample string. It's all coming back to me...

Friday, April 24, 2009

Redirecting a database update using Rails

I learned a handy trick today.

Rails contains a convenience method that allows you to redirect page requests (or submissions) called "redirect_to". Rails also contains a submission method called "PUT" in addition to the "GET" and "POST" supported by HTTP.

When you want to update a record in the database, the technique for doing so is to establish that the submission type of the update method is a "PUT". However, if you want to create a delegate method in between the submission and the actual deed, you need to "POST" to your delegate method then have that method send it's redirection using "PUT".

This is *not obvious* and the solution is best explained by this blog. I've tried it and it works.

Tuesday, April 21, 2009

Using Rails scaffolding

A handy tool that comes with Rails is its ability to create fully functional, dynamic Web sites based on the database schema. Knowing that there are standard CRUD operations, scaffolding creates the controllers and helper code you need to make a site work (without all the branding and AJAX, of course...)

A problem I experienced was this error message:

The name 'TasksHelper' is either already used in your application or reserved by Ruby on Rails.

A little Googling revealed that this is a "bug" that appeared in recent Rails releases (I'm currently using v2.2). Here is a link to the most useful post I found. Pay particular attention to the poster who says to rename the helper files. It's kludgy but better than creating all that code manually.

Tuesday, April 7, 2009

Kudos to Apple

Sometimes things just click... and it's really nice when they do. I needed to set up my MacPro (Leopard) as a development machine running Ruby on Rails and MySQL. At first I estimated 2 to 4 hours.

I had already installed MySQL plus a GUI front end called CocoaMySQL (Note that Google has since purchased CocoaMySQL and renamed its successors to SequelPro. This is good news for Mac heads like me because it shows a growing commitment to both MySQL and Macs.) so I wasn't worried about that.

I guess I didn't read the release notes too carefully, but Ruby and Rails are both pre-installed on Leopard. I opened a terminal window and typed "ruby --version" and "rails --version" and got the expected responses.

Auto-generating a Rails project seems to point ActiveRecord to the SQLite database engine, but editing the database.yml file is a simple thing to correct.

That was it! Even a developer environment using a local Web server "just worked"! I think the whole process took me less than 20 minutes and that's because I spent most of that time incredulous at how easy it was... Kudos to Apple.

Using Delegates in Objective-C

I was following a tutorial on implementing UIPickerViews. For those who have seen or used an iPhone, it's the control that looks like a collection of spinning wheels. The approach Apple takes with the implementation of that particular control is that you must specify a Delegate and a Datasource for the control to function properly. In code, it looks like this:
@interface MyController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> { ... } @end

The tutorial continued to walk me through NIB creation and, most importantly, connecting the NIB objects to the class. Spoiler alert: What I'm writing about is that I failed to realize three important concepts:

  1. the delegate and datasource declarations were standard components of the framework,
  2. those declarations provide a clue to the NIB that you can "control-drag" to specify the delegate class,
  3. you must "override" certain methods to guarantee that the code compiles properly

When I was running through the tutorial, I was under the preconception that the delegate class the authors were referring to was a *custom* class so I was already behind the 8-ball on point #1. I got point #2 easily enough but then failed to understand where the methods in point #3 came from. This is definitely one of those "you had to have been there" moments. I'm sure you're yawning by now...

Suffice it to say that I found my answer when I looked up UIPickerViewDataSource and UIPickerDelegate in the Apple documentation. The instance methods described should be overridden with custom treatment.

Friday, April 3, 2009

"Privatizing" your WHOIS record

When you register a domain for your own personal use, you are asked to provide your home address, phone number, and email address. Unless you have a valid yet anonymous identity most of us would choose to use our (truthful) personal information.

This is problematic because the WHOIS database can be scrubbed for such information and used for telemarketing purposes... or worse. Many domain hosting sites allow you to anonymize your information (for a fee) which is my recommended course of action.

When transferring a domain, however, be sure that you turn this off. Otherwise, the transfer authentication emails go to some bogus email address and restarting the process can be more effort than the initial transfer request. I have learned this from experience... I'll keep you posted.

Free UML modeler for the Mac -- ArgoUML

For those of us who are "Windows-challenged", being Mac users, there are few alternatives to Microsoft's Visio. Two very good open-source applications are StarUML and ArgoUML. The former, however, is not available for the Mac. Too bad. For you Windows users looking for UML depiction that is superior to Visio, I encourage you to check it out because it actually is a pretty good tool.

For those of you who are Enterprise-minded (e.g., you have the budget or you need Visio-compatibility) you may want to check out ConceptDraw. I haven't used it, but it appears to be more fully featured than ArgoUML and therefore very similar to Visio, which is targeted to a larger audience than just those interested in UML.

I've used ArgoUML for 2 hours now to create Class Diagrams. I have only experienced a couple of annoyances so far but those were not deal killers given the (did I say free?) price.

First, annotation tools are too basic. If there is a way to create a generic arrow (as opposed to an Association) I couldn't find it. With a growing trend towards MVC you'd think there would be a way to incorporate visual elements into a Class Diagram. For example, you can't insert a picture (screenshot, icon, etc.)

Second, there is no copy/paste functionality... for anything! If you have 5 similar Operations, forget about copying, pasting, and editing the differences. You have to create each one. This is most annoying with annotations.

GDB: Program Loaded.

This is the cryptic error I see when I forget to create a connection between a NIB object (say, a UIView object) and the associated class. This was difficult to track down because the application compiles and runs, but the moment you interact with the interface, it goes into a locked state with this (very uninformative) message.

Transferring Domains

Increased awareness of the value, and advantages, of personal branding has led many to create their own Web sites. It is easiest to use MySpace or Facebook but I'm a little more old school and decided to have my own domain and to create my own Web pages. Once that choice is out of the way, the question becomes, "how do I my manage my domain?"

I originally created a domain for a friend using Yahoo's Business services. However, I quickly discovered that the Yahoo Web site is a labyrinth that requires a good memory or strategic use of bookmarks. Heaven help you if you lose the bookmark. While I give credit to Yahoo for being a leader with such types of offerings, their Web site is horribly outdated and is not prone to revisions or improvements once deployed to the public.

I next created my own domain using old, yet trustworthy, Network Solutions. I hearken from the old days when NS didn't offer hosted Web sites or e-commerce solutions so one can imagine my surprise when I discovered that I can not only manage multiple domains using NS but that they satisfy *most* of my Internet needs. I created an e-commerce solution for another friend and became familiar with their interface and shopping cart tools. While the NS administrative site could use some polish, it's organized and easy to navigate. Kudos.

Transferring my domain managed by Yahoo to Network Solutions was a piece of cake. In the NS Web site, in a menu off the home page, is Transfer Domain Names. You enter one or more names and provide an "authorization code". To get that code, open your Yahoo Domain Control Panel and click on "View your authorization code". The resulting page includes instructions for transferring the domain as well as the authorization code you'll need. You pay $19 for the honor but when all is said and done, your domain will be in NS's much-easier-to-use domain management interface.