=head1 NAME

Catalyst::Manual::Tutorial - Getting started with Catalyst

=head1 DESCRIPTION

This document aims to get you up and running with Catalyst.

=head2 Installation

The first step is to install Catalyst, and the simplest way to do this 
is to install the Catalyst bundle from CPAN:

    $ perl -MCPAN -e 'install Task::Catalyst'

This will retrieve Catalyst and a number of useful extensions and 
install them for you.


=head2 Setting up your application

Catalyst includes a helper script, C<catalyst.pl>, that will set up a 
skeleton application for you:

    $ catalyst MyApp
    
    created "MyApp"
    created "MyApp/script"
    created "MyApp/lib"
    created "MyApp/root"
    created "MyApp/root/static"
    created "MyApp/root/static/images"
    created "MyApp/t"
    created "MyApp/t/Model"
    created "MyApp/t/View"
    created "MyApp/t/Controller"
    created "MyApp/lib/MyApp"
    created "MyApp/lib/MyApp/Model"
    created "MyApp/lib/MyApp/View"
    created "MyApp/lib/MyApp/Controller"
    created "MyApp/lib/MyApp.pm"
    created "MyApp/Build.PL"
    created "MyApp/Makefile.PL"
    created "MyApp/README"
    created "MyApp/Changes"
    created "MyApp/t/01app.t"
    created "MyApp/t/02pod.t"
    created "MyApp/t/03podcoverage.t"
    created "MyApp/root/static/images/catalyst_logo.png"
    created "MyApp/root/static/images/btn_120x50_built.png"
    created "MyApp/root/static/images/btn_120x50_built_shadow.png"
    created "MyApp/root/static/images/btn_120x50_powered.png"
    created "MyApp/root/static/images/btn_120x50_powered_shadow.png"
    created "MyApp/root/static/images/btn_88x31_built.png"
    created "MyApp/root/static/images/btn_88x31_built_shadow.png"
    created "MyApp/root/static/images/btn_88x31_powered.png"
    created "MyApp/root/static/images/btn_88x31_powered_shadow.png"
    created "MyApp/root/favicon.ico"
    created "MyApp/script/myapp_cgi.pl"
    created "MyApp/script/myapp_fastcgi.pl"
    created "MyApp/script/myapp_server.pl"
    created "MyApp/script/myapp_test.pl"
    created "MyApp/script/myapp_create.pl"

This creates the directory structure shown, populated with skeleton 
files.

=head2 Testing out the sample application

You can test out your new application by running the server script that
Catalyst provides:

    $ cd MyApp
    $ script/myapp_server.pl 

    [...] [catalyst] [debug] Debug messages enabled
    [...] [catalyst] [debug] Loaded plugins:
    .------------------------------------------------------------------------------.
    | Catalyst::Plugin::Static::Simple                                             |
    '------------------------------------------------------------------------------'
    [...] [catalyst] [debug] Loaded dispatcher "Catalyst::Dispatcher"
    [...] [catalyst] [debug] Loaded engine "Catalyst::Engine::HTTP"
    [...] [catalyst] [debug] Found home "/home/users/me/MyApp"
    [...] [catalyst] [debug] Loaded Private actions:
    .--------------------------------------+---------------------------------------.
    | Private                              | Class                                 |
    +--------------------------------------+---------------------------------------+
    | /default                             | MyApp                                 |
    '--------------------------------------+---------------------------------------'
    
    [...] [catalyst] [info] MyApp powered by Catalyst 5.5
    You can connect to your server at http://localhost:3000

(Note that each line logged by Catalyst begins with a timestamp, which has
been replaced here with "C<...>" so that the text fits onto the lines.)

The server is now waiting for you to make requests of it.  Try using 
telnet to manually make a simple GET request of the server (when 
telnet responds with "Escape character is '^]'.", type "GET / HTTP/1.0"
and hit return twice):

    $ telnet localhost 3000
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    GET / HTTP/1.0
    
    HTTP/1.0 200 OK
    Date: Mon, 07 Nov 2005 14:57:39 GMT
    Content-Length: 5525
    Content-Type: text/html; charset=utf-8
    Status: 200
    X-Catalyst: 5.5

    [...]
    Connection closed by foreign host.
    $

You can see the full welcome message by visting
http://localhost:3000/ with your browser.

More trace messages will appear in the original terminal window:

    [...] [catalyst] [debug] **********************************
    [...] [catalyst] [debug] * Request 1 (0.063/s) [2148]
    [...] [catalyst] [debug] **********************************
    [...] [catalyst] [debug] Arguments are ""
    [...] [catalyst] [debug] "GET" request for "" from localhost
    [...] [catalyst] [info] Request took 0.046883s (21.330/s)
    .------------------------------------------------------------------+-----------.
    | Action                                                           | Time      |
    +------------------------------------------------------------------+-----------+
    | /default                                                         | 0.000000s |
    '------------------------------------------------------------------+-----------'

The server will continue running until you interrupt it.

The application can also be tested from the command line using the generated
helper script, C<script/myapp_test.pl>.

=head2 Getting started

So you picked Catalyst. Good choice. I assume you've installed it as
well. For this tutorial you will also need the following modules:

L<Catalyst::Plugin::Session>

L<Catalyst::Plugin::Session::Store::File>

L<Catalyst::Plugin::Session::State::Cookie>

L<Catalyst::Plugin::Authentication>

L<Catalyst::Plugin::Authorization::Roles>

L<DBD::SQLite>

...

To get started all you need to do is type:

B<catalyst.pl tutorial>

This should create a directory called F<tutorial> and fill it with the
default (standard) Catalyst installation. Change to this directory
because we will be running all further commands from inside the
F<tutorial> directory.

If you now run the built-in mini-server with
B<script/tutorial_server.pl>, it will show some standard debug messages
in the console screen (more about those in a minute), and then inform
you that you can now connect to the test server on port 3000. Point your
browser at localhost:3000 to see the built-in catalyst welcome screen.

The other important thing catalyst.pl did was create your root
controller. This file is a standard perl module like all the other
controllers that you might add to your application.  It lives in the
F<lib/> directory, and will have the same name as you supplied to the
command above, in our case it is F<tutorial.pm>. Alongside this file is
a directory of the same name, which is the top level namespace for the
entire application. Thus every other module we create will be
"tutorial::something";

The root controller is used to load plugins, to configure the
application and its plugins, and for generic private actions.  We will
explain more about those later.

=head2 Debugging

The simplest way to debug your Catalyst application is to run it using
the built-in mini-server as described in L</Getting Started>. 

If you want to output any debugging information to the console, then
call C<< $context->log->debug() >>, passing it a string to output. For
data structures, use Data::Dumper and call C<<
$context->log->debug(Dumper($structure)) >>

=head2 Model/View/Controller

The recommended method for code organization in a Catalyst application
is known as the "Model View Controller" design pattern (also referred to
"MVC"). The point of the MVC pattern is to divorce the dependencies of
parts of the application from each other, and give them standard
interfaces. Following this theory of organization should give your code
all the benefits of modularity.  The main benefits are interchangability
of parts and reusable code.

Thus you could replace your file data storage with a database or your
oracle database with a mysql database and not have to change any of your
controlling or view logic. Or you could later decide to output
information from your application as RSS instead of HTML just by adding
a new view module.

=head3 Model

Models deal with the storage of data. For a complex website, you may
need multiple varied data sources, each will have it's own model class
that provides an abstracted interface to it. In this tutorial we are
going to be using a simple database.

=head3 View

Views are used to display information to the user. In a web framework,
it is generally used to output HTML to the browser. As mentioned
previously, views can also be used to output RSS or any other kind of
data format.  One easy way to do this with Catalyst is to use a
templating system such as Template Toolkit. If outputting HTML is all
you are going to do, then you will probably only need one view.

=head3 Controller

A controller deals with reacting to user choices, and thus controls what
the application does. Since this is a web framework, Catalyst
controllers are frequently used to react directly to URLs requested by
the user. This tutorial will describe the simplest way of using
controllers, where each path or part of a path is assigned its own
action (or subroutine). More complex controlling mechanisms will be
mentioned briefly, and can be read about in detail in the manual.


=head2 Controlling

Now lets write our first bit of application code. First, we would like
our application to greet our users. We'll assume for now that our users
will be sent to the I<users/greet> URL. To create a controller that
serves the I<users> namespace, we run the following command in our
F<tutorial> directory:

B<script/tutorial_create.pl controller Users>

This will create a Users.pm in F<lib/tutorial/Controller>. Open this
file in an editor and take a look. You will notice there is some
commented out code which we will ignore for now. To make something
happen when our URL is visited, we will write a "greet" action which
looks like this:

 sub greet : Local
 {
    my ($self, $context) = @_;

    my $name = $context->req->params->{name};
    $context->log->debug("Got name: $name\n");

    if(!$name)
    {
       $context->stash->{message} = 'Please fill in a name!';
    }
    else
    {
        $context->stash->{message} = "Hello $name!";     
    }
    $context->stash->{template} = 'greet.tt';
 }

Whew! So, what does all this do? Lets take it one step at a time.
The subroutine declaration gives the action a name.  To the right of the
name there is an attribute type that looks like this:  " : Local".  That
defines which URIs will translate to this action.  "Local", matches
exactly one URI: /users/greet. The URI matched by "Local" is composed
from the namespace minus the tutorial::controller portion, that is
common to all controllers, and the action name itself.  Because it is a
URI, we use forward slashes instead of double colons.  So, in summary,
when a user requests http://localhost:3000/users/greet" the "greet"
action defined above in the users controller will be executed.

The second line retrieves the parameters Catalyst gives us when it calls
our method. The first is the instance of our Users class, and the second
is commonly called the context. The context is the magical object
containing any information you need from catalyst, or want to send to
it. You will see it used frequently in Catalyst applications, and a list
of all its methods is available in the L<Catalyst> POD.

On the third line we use the ->params method of the $context request
object to retrieve one of the query parameters, just like in L<CGI>.

On the fourth, we make a debug output of this object on the server console. 
(NB where does ->debug go if we're running under CGI or mod_perl?)
(NB what is $self good for under CGI/mod_perl/anything?)

Next, we check if the name field contains anything (or is "true"), if it
isnt, we assign an error message to a "message" field in the stash. The
stash is yet another method of the context object, it allows us to pass
data on to other methods we call later, most usefully the View modules.

If the username did contain a value, then we just set our message to
greet the user by name.

Finally, we set the special "template" variable in the stash to the name
of the template we want our view to use to display this page.
(NB doing the param name checking this way will also complain when we
visit the form for the first time, check for presence of params at all?)

=head2 Viewing

Ok, so reacting and checking the users data is all fine, but how do we
actually display the page/form in the first place, and our results? As
previously mentioned, we'll use Template Toolkit for our viewing. To
create out TT based view, just run the following command:

B<script/tutorial_create.pl view TToolkit TT>

Notice that this time we not only gave it the type of module we wanted
to create (a view), and a name, but also a third argument, "TT". This is
a Catalyst helper module, which will make a standard template toolkit
module for you. And that's all you need to do there.

To use the view, the easiest way is to set up a standard "end" action.
This a private action which will not be matched to a path like our
"greet" action, but instead will be called after all other processing is
done. Only one end action will be called, if there is one in a
controller, it will be prefered over one in the application module, and
so on.
 
Since we're writing a simple application, just add an end action like
this to F<tutorial.pm>:

 sub end : Private
 {
   my ($self, $context) = @_;
   $context->forward('tutorial::View::TToolkit');
 }

The first line declares the end sub, and marks it as a Private action.
(The second and last attribute type we'll be using). The second line
collects our standard parameters as shown in the controller's greet action.

The third line directs Catalyst to pass processing on to our TToolkit
view. The forward method, when just passed a class name, calls process
on that classs. The standard TT view's process method renders the
template named in the templare variable in the stash, using all the
other variables in the stash as values to fill it in.

NB: This is such a common way to end you processing that there is a
plugin which does it for you: L<Catalyst::Plugin::DefaultEnd>.

Template Toolkit also has access to the entire context object via "c",
for example, using [% c.config.name %] in our template will output
"tutorial", our project name.

All that remains is to create a simple template called "greet.tt",
containing a form with a text field called "name", and place it in the
F<root> directory. By default, templates are searched for here, but we
can change that, which brings us to..

(NB Can we ask catalyst which paths exist to provide a dynamic list of
them? (eg greet, age etc .. regexed paths??)

=head2 Configuring

As previously mentioned, the configuration of modules, plugins and so on
is done in the main application file. This is especially true for bits
which need to be done before an instance of them is created, for example
Template Toolkit.

The TT View looks for its templates in the F<root> directory by default.
Since this is also the directory that static files go in, we'd rather
have a separate F<templates> directory. To do this, change the config
call in F<tutorial.pm> like this:

 __PACKAGE__->config( name => 'tutorial',
                      'View::TToolkit' => {
                          'INCLUDE_PATH' => __PACKAGE__->path_to('templates')
     }
  );

And move the F<greet.tt> file from F<root> to the F<templates> directory
(after creating it).

Now we can run our application again by killing (ctrl-c) and restarting
B<script/tutorial_server.pl>. Try connecting to
I<localhost:3000/users/greet> with a browser and see what happens. What
happens if you try to visit I<localhost:3000/users> ? 

=head2 Users and Authenticating

One of the many reasons to write dynamic websites instead of just using static 
HTML, is to allow us to produce different content for different users, as well
 as just restricting access to pages (which we could do with just Apaches 
htpasswd system).

In this tutorial, we will just be using basic authentication, when writing 
a real application, you'll want to use a database or other secure store to 
contain your user data.

To add authentication, all we need to do is add the
L<Catalyst::Plugin::Authentication> module to our main application file. Then
we need to pick a storage method (one of the
L<Catalyst::Plugin::Authentication::Store> modules), and a method of verifying
the users credentials (one of the
L<Catalyst::Plugin::Authentication::Credential> modules), so just edit
F<tutorial.pm> to look like this: 

 use Catalyst qw/-Debug Static::Simple Authentication 
                Authentication::Store::Minimal 
                Authentication::Credential::Password/;

To configure, add some users to the config call, for example: 

 authentication => { 'users' =>
                       { 'fred' =>
                           { 'password' => 'fred1234',
                           }
                       }
                   }

Generally, setting up configuration data for plugins is done based on the 
type of plugin. Check the documentation of the plugin for exact details. The 
details of this one are in L<Catalyst::Plugin::Authentication::Store::Minimal>.

Since our user data is in the config, we can update it at runtime, and thus 
add users dynamically. (Of course, to keep them permanently we'll need to 
export our data to disk and read it back into the config on startup)

To allow creation of new users we'll add a create action to our Users 
controller.

 sub create : Local
 {
    my ($self, $context) = @_;
    my ($username, $passwd1, $passwd2) = map { $context->req->param($_)} 
       ('username', 'password', 'passwordverify');

    if($username && $passwd1 && $passwd2)
    {
       if($context->config->{authentication}{users}{$username})
       {
          $context->stash->{message} = 'Sorry that user already exists';
          $context->stash->{username} = $username;
       }
       elsif($passwd1 eq $passwd2)
       {
          $context->config->({%{$context->config},
             ($username => { password => $passwd1}});
          $context->stash->{message} = 'User created!';
       }
       else
       {
          $context->stash->{username} = $username;
          $context->stash->{message} = 'Passwords don't match!';
       }
    }
    $context->stash->{template} = 'usercreate.tt';
 }

All this is doing is checking that all the appropriate fields are filled, 
the password fields contain the same data, and then adding the user to the 
config hash.  All the checks produce a message which can be displayed to 
the user via the View.

So our that users can login, we need a login page: 

 sub login : Local
 {
    my ($self, $context) = @_;
    $context->stash->{template} = 'userlogin.tt';
    if(!$context->login())
    {
       $context->stash->{message} = 'Login failed.';
    }
 }

Verrrry simple. Since Credential::Password's "login" call extracts the 
username/password data from the query itself (assuming we use a standard 
name for our form fields), we don't have to do anything but call it.

To keep the user logged in, all we need to do is add the Session modules to 
our collection, and the Auth modules will automatically use them; 

 use Catalyst qw/-Debug Static::Simple Authentication 
                 Authentication::Store::Minimal 
                 Authentication::Credential::Password
                 Session Session::Store::File Session::State::Cookie/;

Magic!

=head2 Authorising

Authentication is about verifying users, Authorisation is about allowing
them to do things. Catalyst currently has two Authorisation modules,
Roles and ACL. The Roles module allows you to define groups which you
can assign your users to, and then allow access to areas of your website
to the groups. The ACL module lets you do more fine grained
access/restriction by allowing of denying access however you like. (It
also supports Roles as done by the roles module.)

Adding Roles via the Minimal store we are already using is quite simple,
we just add a roles key to each user, defining the names of the roles
they belong to.

 authentication => { 'users' =>
                            { 'fred' => 
                               { 'password' => 'fred1234',
                                 'roles'       => ['admin'] 
                               }
                            }
                         }

We need an interface for our admins to administer the roles, i.e. assign
the users to groups. To restrict access to certain actions, we just need
to call C<< $context->check_user_roles() >> in each action. So we can
make a restricted I<localhost:3000/users/groups> page like this:

 sub groups : Local
 {
    my ($self, $context) = @_;
    if($context->check_user_roles('admin'))
    {
       # Now we can do things only an admin will see
       if(my $params = $context->req->params)
       {
          my $users = $context->config->{authentication}{users};
          foreach my $u (keys %$params)
          {
             $users->{$u}{roles} = $params->{$u} if($users->{$u});
          }
          $context->stash->{message} = 'Updated user roles!';
       }
       else
       {
           $context->stash->{users} = $context->config->{authentication};
       }
       $context->stash->{template} = 'usersgroups.tt';
    }
    else
    {
        $context->stash->{message} = 'Admins Only!';
        $context->stash->{template} = 'error.tt';
    }
 }

What we are doing here is checking whether the logged in user (used by
default in the check_user_roles method), is a member of the admin group.
If it is, then we display the usergroups template, and update the users
hash as required. Otherwise, we just show the user an error page.

And that's all there is to it.

=head2 Data Storage (Modelling)

Whether we want our users to be able to contribute to our website, or just
create it from changeable data, we need to store the data somewhere. Generally
this is done using a database, models can also be other data sources, for
example another website, or RSS feeds. 

If you have or want a database, there are still choices to be made, there are
several modules about for accessing databases via OO. The best known are
probably L<Class::DBI> and L<DBIx::Class>. Catalyst supports making models
using either of these.  

For a simple example, we will allow our users to store their favourite
greeting in our database. Create a table called "greetings" in a database,
that contains a "user" field and a "greeting" field. The simplest way to
create a model of your database is to use these helper modules, for example
with L<DBIx::Class>: 

B<script/tutorial_create.pl model UserData DBIC dbi:SQLite:/path/to/mydb.db>

This will cause the DBIx::Class Loader to inspect your database, and create a
module in the Model::UserData namespace for each table in your database. 

Now we need a form for our users to enter/edit their personal greetings in,
we'll make a I<localhost:3000/users/editgreeting> page: 

 sub editgreeting : Local
 {
    my ($self, $context) = @_;
    if($context->req->params->{greeting})
    {
       if(!$context->user_exists)
       {
          $context->stash->{message} = "You're not logged in!";
       }
       else
       {
          my $grtable = $context->model('UserData::Greetings');
          my $record = $grtable->find_or_create(user => $context->user->id);
          $record->greeting($context->req->params->{greeting};
          $record->update;
          $context->stash->{message} = 'Greeting updated';
       }
    }
    $context->stash->{template} = 'usersgreeting.tt';
 }

Using C<< $context->user_exists >> from the Authentication plugin, this checks
whether the user is logged in already. If they are, if they are, and they have
entered a new greeting, we use DBIx::Class' C<find_or_create> to fetch or
create a new record in the greetings table for the user. Once we have the
record, we change the value of the greeting field, and call C<update> to store
the new value in the database. 

=head2 Engines (Apache and FastCGI)

Now that we have the basics together, we can try running our application on a
"real" server instead of just using the test server that catalyst comes
with. L<Catalyst::Engine> is the module used to implement various types of
servers to run it on. The currect popular ones are Apache and FastCGI. To
force the use of a particular engine we can use the -Engine flag to Catalyst: 

 use Catalyst qw/-Engine=Apache/;

or

 use Catalyst qw/-Engine=FastCGI/;

=head3 Apache

Apache also needs configuring, we need to tell it to load your
application. You can either use Catalyst for your entire website, or
subsections. Use the Location directive to choose a path to run your
application under: 

 <Location />
   SetHandler                perl-script
   PerlResponseHandler  MyApp
 </Location>

You will need to install the perl modules of your application into one of
perls library directories, as listed by B<perl -V>, so that Apache can find
them. Alternatively you can use the C<PerlSwitches> directive to tell Apache
where to look: 

 PerlSwitches -I/path/to/MyApp/

These instructions are for using Apache2 and mod_perl 2.0. If you are using
mod_perl 1.3 or 1.99, please refer to either L<Catalyst::Engine::Apache::MP13>
or L<Catalyst::Engine::Apache2::MP19> for slightly different ways to do it. 

If you wish to ensure that Apache pre-loads your application, use the
PerlModule directive. This means that there will be less of a delay when your
application is accessed. 

 PerlModule MyApp

=head3 FastCGI

These instructions apply to the use of C<mod_fastcgi> under Apache (either 1 or 2 series).

There are 3 ways to attach a program to a URL with C<mod_fastcgi>; we'll examine all of them, and explain how to avoid having the C<myapp_fastcgi.pl> substring in the user-visible URLs.

In all of these examples, we assume that the C<DocumentRoot> is C</var>, that our app is called C<MyApp> and is kept in C</usr>, that you want the users to access the app either from the root of the server-uri-space, or from C</theapp>. We also assume that the general FastCGI settings (C<FastCgiIpcDir>, loading the module) are already correct (they don't depend on Catalyst or your application layout).

=head4 static application

In this setup, you tell C<mod_fastcgi> that a particular I<file> is to be run as a FastCGI handler. Put this somewhere in Apache's configuration:

  FastCgiServer /usr/apps/MyApp/script/myapp_fastcgi.pl
  Alias / /usr/apps/MyApp/script/myapp_fastcgi.pl/

If you want your app under C</theapp>, change the C<Alias> line to:

  Alias /theapp /usr/apps/MyApp/script/myapp_fastcgi.pl

Note the detail of the trailing C</ >: this is a general rule af the C<Alias> directive, both sides must end with C</ >, or both must not; you can't have one with C</ > and the other without, or strange things happen.

=head4 dynamic application

In this setup, you tell C<mod_fastcgi> that certain files are to be treated as FastCGI handlers, in the same way you have to tell C<mod_cgi>. Put this in the configuration:

  FastCgiConfig -autoUpdate

  <Directory /usr/apps/MyApp/script>
   Options +ExecCGI
   <Files *_fastcgi.pl>
    SetHandles fastcgi-script
   </Files>
  </Directory>

  Alias / /usr/apps/MyApp/script/myapp_fastcgi.pl/

Again, if you want your app under C</theapp>, change the C<Alias> line to:

  Alias /theapp /usr/apps/MyApp/script/myapp_fastcgi.pl

=head4 external server

In this setup, the application is started separately from Apache, and communicates via a socket with C<mod_fastcgi>. This can be useful if you need to have a particular environment for your application (maybe different between applications), or you want to run them on different machines, or under different users for security reasons.

If you want to use a UNIX socket (on the filesystem), put this in Apache's configuration:

  FastCgiExternalServer /tmp/somewhere -socket /tmp/myapp-socket
  Alias / /tmp/somewhere/

Note that C</tmp> should I<not> exist: it's just a name to connect the two parts.

Again, if you want your app under C</theapp>, change the C<Alias> line to:

  Alias /theapp /tmp/somewhere

Then start your Catalyst application:

  $ cd /usr/apps/MyApp
  $ ./script/myapp_fastcgi -l /tmp/myapp-socket

If you want to use a TCP socket, simply change the C</tmp> to a C<host:port> pair, both in Apache's configuration and on the command line of your application.

=head2 Upgrading

Upgrading your application to newer Catalyst versions is quite simple. After
installing the new Catalyst package, just run: 

B<catalyst.pl -scripts>

One level above your application directory. This will update the scripts
directory only, and leave the rest of your app alone, If you wish to make use
of other parts of Catalyst that have been updated, leave off the B<-scripts>
argument, this will cause .new files to appear, for each module that has
either been updated, or is different to the original because you have changed
it. To find out what these changes are, type: 

B<diff MyApp/lib/MyApp/View/TT.pm MyApp/lib/MyApp/View/TT.pm.new>

for each of the changed files. (This is a Unix command, Windows users will
need to find some equivalent). Copy any changes you need into your original
file, then remove the .new files. (This makes life less complicated when the
next upgrade comes around.) 

=head1 AUTHOR

Jess Robinson, C<jrobinson@cpan.org>
Andrew Ford, C<A.Ford@ford-mason.co.uk>
Marcus Ramberg, C<mramberg@cpan.org>

Please send comments, corrections and suggestions for improvements to
jrobinson@cpan.org

=head1 TODO

Add template examples.

Many other things..

=head1 COPYRIGHT

This program is free software, you can redistribute it and/or modify 
it under the same terms as Perl itself.
