developerBlog by Mark Fenoglio http://dblog.istarelworkshop.com/ Technology musings on practical PHP, PostgreSQL, and Cocoa development. Wed, 17 Mar 2010 03:29:57 -0400 en Changing PostgreSQL ownership http://www.istarelworkshop.com/2010/01/08/changing_postgresql_ownership Fri, 08 Jan 2010 00:00:00 -0500 PostgreSQL http://www.istarelworkshop.com/2010/01/08/changing_postgresql_ownership Functions and SQL commands to change the owner of PostgreSQL tables.

Sometimes, during the changes inevitable in the progress of a PostgreSQL-based project, the ownership of a database or the tables in a database must change. Preventing Actions http://www.istarelworkshop.com/2010/01/05/preventing_actions Tue, 05 Jan 2010 00:00:00 -0500 PHP http://www.istarelworkshop.com/2010/01/05/preventing_actions Show how to completely eliminate an action.

In the previous blog entry, I showed how to prevent actions on an object-by-object basis. Suppose, however, that you wanted to entirely eliminate an action? Restricting Actions http://www.istarelworkshop.com/2010/01/01/restricting_actions Fri, 01 Jan 2010 00:00:00 -0500 PHP http://www.istarelworkshop.com/2010/01/01/restricting_actions Learn about the optional permission methods for restricting actions in a list.

In the last two blog entries, I illustrated the key methods in displaying lists of objects in the list mode that is part of an IWLeadWorkflow. One thing that might have been particularly concerning is that there is a delete action enabled for each object. PreviewAction for PageModule http://www.istarelworkshop.com/2009/12/29/previewaction_for_pagemodule Tue, 29 Dec 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/12/29/previewaction_for_pagemodule Create a custom action for the list mode of an application module supported by an IWLeadWorkflow instance.

In the last blog entry, I showed how easy it is to prepare a list view for an application module. By default, there are two actions available for each object: Edit and Delete. You might imagine that "Preview" might prove to be a useful action for our PageEditor module. ListMode for PageEditor http://www.istarelworkshop.com/2009/12/25/listmode_for_pageeditor Fri, 25 Dec 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/12/25/listmode_for_pageeditor Examine the initial design of PageEditor that satisfies the requirements of the list mode in a page driven by an IWLeadWorkflow.

Implementing an application module in support of an IWLeadWorkflow instance forces you to consider many required and optional methods. I am embarking on a series of blog entries that attempts to encompass the entire design process for an application module supported by IWLeadWorkflow. Setting up a remote git repository http://www.istarelworkshop.com/2009/12/22/setting_up_a_remote_git_repository Tue, 22 Dec 2009 00:00:00 -0500 Git Mac OS X http://www.istarelworkshop.com/2009/12/22/setting_up_a_remote_git_repository Create a remote git repository that will be a deploy destination for a primary git repository.

While a subversion repository typically manages many projects, git is a project-centered technology. For each project I create, I want to be able to manage my local repository such that I can push production-ready versions out to remote servers. For example, several client applications are built using the Istarel Workshop frameworks: When a new stable release is ready, I want to be able to easily deploy that new version to client servers to replace the previous framework release.

]]>
Installing and using Git http://www.istarelworkshop.com/2009/12/18/installing_and_using_git Fri, 18 Dec 2009 00:00:00 -0500 Git Mac OS X http://www.istarelworkshop.com/2009/12/18/installing_and_using_git Install git and save a project.

Installing git is always a simple procedure, but with MacPorts, it becomes a one line Unix command. I also want to set some key configuration settings for git. Adding Google Analytics http://www.istarelworkshop.com/2009/12/15/adding_google_analytics Tue, 15 Dec 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/12/15/adding_google_analytics Add GoogleAnalytics support to your website.

Now that the developerBlog and www.istarelworkshop.com have been relaunched, I want to be able to learn more about who visits the web site. The Istarel Workshop Frameworks makes it simple to add support for Google Analytics to your web site.

]]>
Creating and Applying a Patch http://www.istarelworkshop.com/2009/12/11/creating_and_applying_a_patch Fri, 11 Dec 2009 00:00:00 -0500 Mac OS X PHP PostgreSQL http://www.istarelworkshop.com/2009/12/11/creating_and_applying_a_patch Use the patch system to implement a patch for the developerBlog application.

Creating a developer-focused blog application turned out to be a great learning experience. I am generally happy with the design and layout, but there seems to be a glaring omission: the urls to specific articles are not terribly search-engine friendly. So, I want to add a database table that properly maps the public url to the private application module invocation. Clearly, I already have several articles written, for which there is no search-engine friendly url. That means I also need to populate that new database table with appropriate information for existing articles. I can use the patch system to deploy these changes once they are ready.

]]>
Creating a Patch System http://www.istarelworkshop.com/2009/12/08/creating_a_patch_system Tue, 08 Dec 2009 00:00:00 -0500 Mac OS X PHP PostgreSQL Subversion http://www.istarelworkshop.com/2009/12/08/creating_a_patch_system Implement a patch system using Unix shell scripts and the Istarel Workshop Frameworks.

One inevitable activity in any web application is updates. I am always refactoring code, adding new features, and improving existing features. I get everything working the way I want in my development environment and then need to deploy the changes. Typically, that deployment has three components: update the scripts via subversion, modify the database, and use php to update database records. Editor Pages http://www.istarelworkshop.com/2009/12/04/editor_pages Fri, 04 Dec 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/12/04/editor_pages Introduce the pages used by most of the editor modules in the Big Nerd Ranch application.

In previous blog entries, I demonstrated how to create the components of a login process; a Login Page and its associated login.html template, and the Login module that utilizes an IWLoginWorkflow to make everything happen. IWLeadWorkflow http://www.istarelworkshop.com/2009/12/01/iwleadworkflow Tue, 01 Dec 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/12/01/iwleadworkflow Introduce a workflow more complex than the IWLoginWorkflow already briefly shown.

Just as design patterns exist to frame common programming problems, a series of workflows exist in the Istarel Workshop Framework to address common page-mode problems. One seen in an earlier blog entry is the IWLoginWorkflow, which considers a workflow with two modes: edit (where the user provides credentials) and login (where those credentials are verified or rejected by the ApplicationSecurityDelegate). Handling Logout http://www.istarelworkshop.com/2009/11/27/handling_logout Fri, 27 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/27/handling_logout Modify the ApplicationDelegate to handle a Logout action.

To enable logout, the handlePageRequest() method of the ApplicationDelegate is modified. Since DoLogout represents an action and not a view, the ApplicationDelegate will intercept that page request and instead ask the ApplicationSecurityDelegate to perform the logout action.

]]>
Remembering the User's Destination http://www.istarelworkshop.com/2009/11/24/remembering_the_user's_destination Tue, 24 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/24/remembering_the_user's_destination Show how the ApplicationSecurityDelegate can be modified to remember a user's intended destination such that after a successful login, the user is redirected to the desired page.

In any content management system, most of the pages will be protected by some form of security (or at least they should be). Users, on the other hand, often bookmark pages within that safe cocoon. In addition, a member of the team may want to send a preview link to someone. Whatever the circumstances, it would be nice for the system to remember the desired destination after authentication.

]]>
Page Security http://www.istarelworkshop.com/2009/11/20/page_security Fri, 20 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/20/page_security Illustrate the implementation of role-based security in the Istarel Workshop Frameworks.

In any content management system, certain users are intended to have access only to certain pages. In the Big Nerd Ranch, there are several "roles" that define the kind of content which an individual can modify. Content Editors are responsible for editing instructor and course pages, modifying the class schedule, and so on. Administrators manage the registration process and handle page archives. Superusers have the same priveleges as Administrators but are also responsible for user accounts. Breadcrumbs http://www.istarelworkshop.com/2009/11/17/breadcrumbs Tue, 17 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/17/breadcrumbs Create a more sophisticated custom component that generates a breadcrumb for an index page.

The custom component used to show a welcome message for the index modules had one key feature: an XML() method expected by the IWPageRenderer object responsible for composing the page. As mentioned before, an XML() method is not the only display mechanism for components. A component can also have its own renderer (for example, an IWForm depends on an IWFormRenderer, which expects the underlying template to implement the FormTemplateProtocol interface). Command Line vs. Web PHP http://www.istarelworkshop.com/2009/11/15/command_line_vs_web_php Sun, 15 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/15/command_line_vs_web_php How to modify session_start so that it is not executed when invoking PHP from a command-line shell.

In many environments, session_start() is either meaningless or will generate permission errors for PHP scripts being executed from the command line. Fortunately, the $_SERVER global variable contains data that make it possible to differentiate where a PHP script is being run: Custom Page Components http://www.istarelworkshop.com/2009/11/13/custom_page_components Fri, 13 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/13/custom_page_components Create a simple custom component in a module.

In the last blog entry, I discussed the shared page template for the various index modules. What about the modules themselves? Each has a unique message and a unique place in the website's page hierarchy, but those distinctions can be managed in an abstract index superclass called MasterIndex. Creating an Index Page http://www.istarelworkshop.com/2009/11/10/creating_an_index_page Tue, 10 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/10/creating_an_index_page Create the infrastructure for simple role-based landing pages.

The default home page for Big Nerd Ranch team members is a simple landing page that features a short welcome message and shows a menu of areas to which a member has access as well as a breadcrumb that shows where in the page hierarchy the member is. The index page to which a team member is directed depends on their application role (e.g., AdminIndex for a superuser or administrator, EditorIndex for a content editor, and so on). Regular Expression Replace of Primary Key http://www.istarelworkshop.com/2009/11/08/regular_expression_replace_of_primary_key Sun, 08 Nov 2009 00:00:00 -0500 PostgreSQL Regex http://www.istarelworkshop.com/2009/11/08/regular_expression_replace_of_primary_key Using regular expressions in TextMate to intelligently replace specified primary key values.

For a lot of application that I create, I have a series of shell scripts that essentially help me rebuild the database contents from scratch. One component of that is SQL reports for various entities in the application, the delivery of which is simple INSERT INTO statements. Login Validation http://www.istarelworkshop.com/2009/11/06/login_validation Fri, 06 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/06/login_validation Modify the ApplicationSecurityDelegate to consider user credentials supplied from the Login application module.

With the LoginAttempt module and its associated LoginPage template created, the next step is making the form actually work. For an ordinary form that saves data, a model object is directly responsible for validating its properties and saving itself to the underlying database. A form that is part of a IWLoginWorkflow, however, performs validation differently since the ultimate goal is not to save information to the database but rather to authenticate a potential user. As such, the IWLoginController's LoginMode object instantiates the ApplicationSecurityDelegate and calls its validateLogin() method. Creating the Login Page http://www.istarelworkshop.com/2009/11/03/creating_the_login_page Tue, 03 Nov 2009 00:00:00 -0500 PHP http://www.istarelworkshop.com/2009/11/03/creating_the_login_page Create the page named in the LoginAttempt module.

The LoginAttempt module relies on a page templating system to display its components, one ultimately controlled by IWPageRenderer. The IWFrameworks provides a top-level page class called IWPage which assumes simple head and body components (and registers them with the page renderer). Creating the Login Module http://www.istarelworkshop.com/2009/10/30/creating_the_login_module Fri, 30 Oct 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/10/30/creating_the_login_module Create an application module that uses the IWLoginWorkflow to provide a login form.

An IWFrameworks application works by pairing a workflow with an application module. The module defines which workflow it needs, and the type of workflow determines whether a model object is required. Depending on the modes that comprise the workflow, the application module may have additional required methods.

]]>
Introduction to Security Modeling in the IWFrameworks http://www.istarelworkshop.com/2009/10/27/introduction_to_security_modeling_in_the_iwframeworks Tue, 27 Oct 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/10/27/introduction_to_security_modeling_in_the_iwframeworks Use the simple security model implementation utilized by the Istarel Workshop frameworks.

Although the Big Nerd Ranch has a vital public-facing web site, the first thing I'll build is the security infrastructure. When the application installer creates the ApplicationSecurityDelegate class, it is essentially a shell with which application developers can implement their security model.

]]>
Front Controller Design Pattern http://www.istarelworkshop.com/2009/10/23/front_controller_design_pattern Fri, 23 Oct 2009 00:00:00 -0400 Apache PHP http://www.istarelworkshop.com/2009/10/23/front_controller_design_pattern Illustrate the implementation of the Front Controller design pattern used to route web traffic in web applications built using the IWFrameworks.

In order for our bootstrap to work, and for the Front Controller to get all the information it needs, I first have to ensure that all the traffic to the application is routed through a single place: in this case, index.php. That "forced routing" is handled by the mod_rewrite extension to Apache. The mechanism I have chosen to handle this is to create httpd.conf files at the root level of each application folder.

]]>
Singleton Design Pattern http://www.istarelworkshop.com/2009/10/20/singleton_design_pattern Tue, 20 Oct 2009 00:00:00 -0400 PHP PostgreSQL http://www.istarelworkshop.com/2009/10/20/singleton_design_pattern Illustrate the singleton design pattern in the context of database connections used by the Istarel Workshop frameworks.

One of the most common (and useful) design patterns is the Singleton. The idea is simple: you often only want one instance of a particular resource, and the Singleton pattern makes that possible. For the frameworks, we want to ensure that there is always only one active connection to our PostgreSQL database (for any given client).

]]>
Smarter Model Object Classes http://www.istarelworkshop.com/2009/10/16/smarter_model_object_classes Fri, 16 Oct 2009 00:00:00 -0400 PHP PostgreSQL http://www.istarelworkshop.com/2009/10/16/smarter_model_object_classes Apply a switch in the model object creation process to have friendly accessor methods.

Absent any special switches used when creating the model object classes, there are two standard methods used as accessors for instance properties: valueForProperty('property_name') and setValueForProperty('property_name', $value). Reviewing Model Object Classes http://www.istarelworkshop.com/2009/10/13/reviewing_model_object_classes Tue, 13 Oct 2009 00:00:00 -0400 PHP PostgreSQL http://www.istarelworkshop.com/2009/10/13/reviewing_model_object_classes

In a previous blog entry, I used the DBOM tools to create the model object classes that will be needed by my developerBlog application. These DBOM tools examine the application database and create default classes that represent individual objects and the factories that produce them. Fluent Interfaces http://www.istarelworkshop.com/2009/10/11/fluent_interfaces Sun, 11 Oct 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/10/11/fluent_interfaces Describe the fluent interface and its use in the Istarel Workshops frameworks.

A term first introduced by Martin Fowler and Eric Evans, a fluent interface is one in which a class is self-referencial wherever possible, resulting in cleaner code. Wherever possible, the Istarel Workshop Application Framework utilizes fluent interfaces. Placeholders using Javascript http://www.istarelworkshop.com/2009/10/09/placeholders_using_javascript Fri, 09 Oct 2009 00:00:00 -0400 CSS Javascript http://www.istarelworkshop.com/2009/10/09/placeholders_using_javascript Show how to combine Javascript, HTML, and CSS to provide text field placeholders in a web form.

One standard feature on most blogs (and lots of other places, of course) is a search widget. I wanted to make sure that its functionality was obvious without having to resort to a label sitting on top of it (or next to it). So, I experimented with a little Javascript to create some placeholder text to make clear what purpose the field served. Once the user clicks in the field, I also want the placeholder text to go away (and then return when the user leaves the field if it is empty).

]]>
Authors http://www.istarelworkshop.com/2009/10/06/authors Tue, 06 Oct 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/10/06/authors This entry shows how the Istarel Workshop Application Framework uses an IWModule, IWPage, and an html template to render a login page.

For the moment, Home is fine as a default starting point for the application. However, we need a place for an author to provide details about his book: how many pages it has, the chapter content, any errata that need to be published, and uploading of solutions to exercises (with perhaps a hint or two for any challenges). Commit in Git http://www.istarelworkshop.com/2009/10/04/commit_in_git Sun, 04 Oct 2009 00:00:00 -0400 Git Mac OS X http://www.istarelworkshop.com/2009/10/04/commit_in_git A quick trick for handling all the modified files in a Git repository.

In Git, each commit is a product of all the modifications and new files added to the working copy. Unlike with Subversion, where all modified files are assumed to be part of the commit, Git requires you to explicitly add them. Fortunately, there is a handy shortcut for adding everything. Exploring Techstra http://www.istarelworkshop.com/2009/10/02/exploring_techstra Fri, 02 Oct 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/10/02/exploring_techstra Examine the default state of Techstra as created by the installer. Discussion the basics of rendering in the Istarel Workshop Application Frameworks.

As part of the installation, a few default classes are created that implement the simplest mechanism of page creation. (The contents of the dbom/ directory are not listed, but will be discussed at length in future blog entries. I promise.)

]]>
Creating Techstra http://www.istarelworkshop.com/2009/10/01/creating_techstra Thu, 01 Oct 2009 00:00:00 -0400 Mac OS X PHP PostgreSQL http://www.istarelworkshop.com/2009/10/01/creating_techstra Use the Istarel Workshop Application Frameworks to create an application called Techstra, designed to foster communication between technical authors and their readers.

Techstra offers the perfect opportunity to trace the development of a PHP and PostgreSQL web application from its inception, using the Istarel Workshop Application Frameworks. Creating Model Object Classes http://www.istarelworkshop.com/2009/09/29/creating_model_object_classes Tue, 29 Sep 2009 00:00:00 -0400 PHP PostgreSQL http://www.istarelworkshop.com/2009/09/29/creating_model_object_classes Show the results of the Istarel Workshop Application Framework dbom_install command line tool, which parses a PostgreSQL database and autogenerates ready-to-use PHP classes that enable easy interaction with a back-end database.

Like most modern frameworks, the Istarel Workshop frameworks uses the Model-View-Controller design pattern (with some noted upgrades to solve problems inherent in creating web-based applications). With the skeleton of the developerBlog application in place, we can turn to the developerBlog's Model. An earlier blog entry described how the developerBlog PostgreSQL database was restored.

]]>
Countable http://www.istarelworkshop.com/2009/09/27/countable Sun, 27 Sep 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/09/27/countable Make your classes work with the count function.

One important part of my frameworks is foundation classes designed to manage collections of data: they all inherit from IWIterator and adhere to the SPL-defined Iterator interface. FrontController http://www.istarelworkshop.com/2009/09/25/frontcontroller Fri, 25 Sep 2009 00:00:00 -0400 PHP http://www.istarelworkshop.com/2009/09/25/frontcontroller Describe how the Istarel Workshop Application Framework implements the Front Controller design pattern.

One way to more efficiently and securely manage a web application is to take advantage of the Front Controller design pattern. This pattern calls for a single object to route web traffic: for the developerBlog (and other applications I build with the Istarel Workshop Application Framework), this means there must be an entry point for the application and the Front Controller object to which it defers control.

]]>
Creating developerBlog http://www.istarelworkshop.com/2009/09/22/creating_developerblog Tue, 22 Sep 2009 00:00:00 -0400 Apache Mac OS X http://www.istarelworkshop.com/2009/09/22/creating_developerblog Illustrate how the developerBlog was created using the Istarel Workshop Application Frameworks.

With the developerBlog postrgesql database now restored to the active development server, the website application project can be created. Installing PostGIS http://www.istarelworkshop.com/2009/09/20/installing_postgis Sun, 20 Sep 2009 00:00:00 -0400 Mac OS X PostgreSQL http://www.istarelworkshop.com/2009/09/20/installing_postgis Install PostGIS to enable powerful geography handling capability to PostgreSQL databases.

PostGIS is an open-source project http://postgis.refractions.net/ that enables GIS capability in PostgreSQL databases. Subversion on the Network http://www.istarelworkshop.com/2009/09/18/subversion_on_the_network Fri, 18 Sep 2009 00:00:00 -0400 Mac OS X Subversion http://www.istarelworkshop.com/2009/09/18/subversion_on_the_network Make Subversion accessible on a local network.

If I were always going to use Apple's file sharing to connect to my development server, I would never have to expose my subversion repository to the network. However, I like to have my laptop serve as a mobile development server. Previously, I performed my own synchronization of websites. Subversion provides a more elegant solution.

]]>
Creating the Subversion Repository http://www.istarelworkshop.com/2009/09/15/creating_the_subversion_repository Tue, 15 Sep 2009 00:00:00 -0400 Mac OS X Subversion http://www.istarelworkshop.com/2009/09/15/creating_the_subversion_repository Set up a simple Subversion repository.

To help maintain a consistent code base for the myriad projects in which I'm involved, I decided to create a subversion repository on my development server.

]]>
Autofocus When A Page Loads http://www.istarelworkshop.com/2009/09/13/autofocus_when_a_page_loads Sun, 13 Sep 2009 00:00:00 -0400 Javascript http://www.istarelworkshop.com/2009/09/13/autofocus_when_a_page_loads Many times, you want to have a field grab focus when a page loads. A little javascript gets you there.

Ever been to Google's home page? The moment the page finishes loading, the cursor is happily blinking in the search field. This can be done with a little simple javascript.

]]>
Leopard Development Server: PHP 5 http://www.istarelworkshop.com/2009/09/11/leopard_development_server_php_5 Fri, 11 Sep 2009 00:00:00 -0400 Mac OS X PHP http://www.istarelworkshop.com/2009/09/11/leopard_development_server_php_5 Describe how to install and initialize the MacPorts version of PHP 5.

With the database and web server in place, I can turn my attention to PHP 5, my tool of choice for web development. Because I am using PostgreSQL, I need to look to see which port variants are available for PHP 5. Each variant can be included in the PHP installation by appending it to the command. Leopard Development Server: Apache 2 http://www.istarelworkshop.com/2009/09/08/leopard_development_server_apache_2 Tue, 08 Sep 2009 00:00:00 -0400 Apache Mac OS X http://www.istarelworkshop.com/2009/09/08/leopard_development_server_apache_2 Use MacPorts to install Apache 2 as an independent web server on Mac OS X Leopard.

Next up is the web server. Apache 2 comes pre-installed on Leopard systems, but I want all my open source projects to work alongside one another.

]]>
Google Analytics Website Profile http://www.istarelworkshop.com/2009/09/06/google_analytics_website_profile Sun, 06 Sep 2009 00:00:00 -0400 Analysis http://www.istarelworkshop.com/2009/09/06/google_analytics_website_profile Update a Google Analytics profile to get cleaner results.

From your account page, click on the Analytics link. This brings up a list of "Website Profiles". Click on the Edit link on the right to update a profile. There are a couple of simple settings in the profile configuration that can prevent one page being treated as many]]> Leopard Development Server: PostgreSQL http://www.istarelworkshop.com/2009/09/04/leopard_development_server_postgresql Fri, 04 Sep 2009 00:00:00 -0400 Mac OS X PostgreSQL http://www.istarelworkshop.com/2009/09/04/leopard_development_server_postgresql Describe how to install and initialize the MacPorts version of PostgreSQL 8.3.

The first MacPort to be installed will be postgresql. The latest version available is PostgreSQL 8.3, and installation involves both MacPorts work and some command line activity.

]]>
Leopard Development Server: MacPorts http://www.istarelworkshop.com/2009/09/01/leopard_development_server_macports Tue, 01 Sep 2009 00:00:00 -0400 Mac OS X http://www.istarelworkshop.com/2009/09/01/leopard_development_server_macports Create a development server using Leopard, Apple's Developer Tools, and MacPorts.

With the release of Leopard, I had started to make a laundry list of the features I wanted my development server to have. In previous incarnations, I had built everything from source code. In some respects, I approached it this way as a learning experience. Now, however, I want as little down time on the server as possible.

]]>