Try to straighten out the View::TT docs
[catagits/Catalyst-View-TT.git] / lib / Catalyst / View / TT.pm
CommitLineData
8077080c 1package Catalyst::View::TT;
2
3use strict;
6229ce0d 4use warnings;
5
7d8aa5ec 6use base qw/Catalyst::View/;
9e739e1e 7use Data::Dump 'dump';
8077080c 8use Template;
9use Template::Timer;
e8693f1b 10use MRO::Compat;
316f014a 11use Scalar::Util qw/blessed/;
8077080c 12
5c2affa4 13our $VERSION = '0.34';
8077080c 14
15__PACKAGE__->mk_accessors('template');
e2bbd784 16__PACKAGE__->mk_accessors('include_path');
8077080c 17
9d574573 18*paths = \&include_path;
19
8077080c 20=head1 NAME
21
22Catalyst::View::TT - Template View Class
23
24=head1 SYNOPSIS
25
bd4ee63a 26# use the helper to create your View
ad50568f 27
226c1dd3 28 myapp_create.pl view Web TT
8077080c 29
226c1dd3 30# add custom configration in View/Web.pm
8cd017a8 31
940a2e8a 32 __PACKAGE__->config(
226c1dd3 33 # any TT configuration items go here
34 INCLUDE_PATH => [
35 MyApp->path_to( 'root', 'src' ),
36 MyApp->path_to( 'root', 'lib' ),
37 ],
38 TEMPLATE_EXTENSION => '.tt',
39 CATALYST_VAR => 'c',
40 TIMER => 0,
41 # Not set by default
42 PRE_PROCESS => 'config/main',
43 WRAPPER => 'site/wrapper',
44 render_die => 1, # Default for new apps, see render method docs
ae035767 45 );
f5b61ad7 46
6229ce0d 47# render view from lib/MyApp.pm or lib/MyApp::Controller::SomeController.pm
f5b61ad7 48
8cd017a8 49 sub message : Global {
94b3529a 50 my ( $self, $c ) = @_;
51 $c->stash->{template} = 'message.tt2';
52 $c->stash->{message} = 'Hello World!';
226c1dd3 53 $c->forward( $c->view('Web') );
8cd017a8 54 }
8077080c 55
8cd017a8 56# access variables from template
57
58 The message is: [% message %].
f5b61ad7 59
8cd017a8 60 # example when CATALYST_VAR is set to 'Catalyst'
f5b61ad7 61 Context is [% Catalyst %]
62 The base is [% Catalyst.req.base %]
63 The name is [% Catalyst.config.name %]
64
8cd017a8 65 # example when CATALYST_VAR isn't set
66 Context is [% c %]
67 The base is [% base %]
68 The name is [% name %]
69
bd4ee63a 70=cut
71
72sub _coerce_paths {
73 my ( $paths, $dlim ) = shift;
74 return () if ( !$paths );
75 return @{$paths} if ( ref $paths eq 'ARRAY' );
76
77 # tweak delim to ignore C:/
78 unless ( defined $dlim ) {
79 $dlim = ( $^O eq 'MSWin32' ) ? ':(?!\\/)' : ':';
80 }
81 return split( /$dlim/, $paths );
82}
83
84sub new {
85 my ( $class, $c, $arguments ) = @_;
86 my $config = {
87 EVAL_PERL => 0,
88 TEMPLATE_EXTENSION => '',
89 %{ $class->config },
90 %{$arguments},
91 };
92 if ( ! (ref $config->{INCLUDE_PATH} eq 'ARRAY') ) {
93 my $delim = $config->{DELIMITER};
94 my @include_path
95 = _coerce_paths( $config->{INCLUDE_PATH}, $delim );
96 if ( !@include_path ) {
97 my $root = $c->config->{root};
98 my $base = Path::Class::dir( $root, 'base' );
99 @include_path = ( "$root", "$base" );
100 }
101 $config->{INCLUDE_PATH} = \@include_path;
102 }
103
104 # if we're debugging and/or the TIMER option is set, then we install
105 # Template::Timer as a custom CONTEXT object, but only if we haven't
106 # already got a custom CONTEXT defined
107
108 if ( $config->{TIMER} ) {
109 if ( $config->{CONTEXT} ) {
110 $c->log->error(
111 'Cannot use Template::Timer - a TT CONTEXT is already defined'
112 );
113 }
114 else {
115 $config->{CONTEXT} = Template::Timer->new(%$config);
116 }
117 }
118
119 if ( $c->debug && $config->{DUMP_CONFIG} ) {
9e739e1e 120 $c->log->debug( "TT Config: ", dump($config) );
bd4ee63a 121 }
6175bba7 122
e8693f1b 123 my $self = $class->next::method(
f5b61ad7 124 $c, { %$config },
6175bba7 125 );
126
127 # Set base include paths. Local'd in render if needed
128 $self->include_path($config->{INCLUDE_PATH});
f5b61ad7 129
6175bba7 130 $self->config($config);
131
132 # Creation of template outside of call to new so that we can pass [ $self ]
133 # as INCLUDE_PATH config item, which then gets ->paths() called to get list
134 # of include paths to search for templates.
f5b61ad7 135
6175bba7 136 # Use a weakend copy of self so we dont have loops preventing GC from working
137 my $copy = $self;
138 Scalar::Util::weaken($copy);
139 $config->{INCLUDE_PATH} = [ sub { $copy->paths } ];
140
bd4ee63a 141 if ( $config->{PROVIDERS} ) {
142 my @providers = ();
143 if ( ref($config->{PROVIDERS}) eq 'ARRAY') {
144 foreach my $p (@{$config->{PROVIDERS}}) {
145 my $pname = $p->{name};
146 my $prov = 'Template::Provider';
147 if($pname eq '_file_')
148 {
149 $p->{args} = { %$config };
150 }
151 else
152 {
51199593 153 if($pname =~ s/^\+//) {
154 $prov = $pname;
155 }
156 else
157 {
158 $prov .= "::$pname";
159 }
6175bba7 160 # We copy the args people want from the config
161 # to the args
162 $p->{args} ||= {};
163 if ($p->{copy_config}) {
164 map { $p->{args}->{$_} = $config->{$_} }
165 grep { exists $config->{$_} }
166 @{ $p->{copy_config} };
167 }
bd4ee63a 168 }
fc0ffed0 169 local $@;
bd4ee63a 170 eval "require $prov";
171 if(!$@) {
172 push @providers, "$prov"->new($p->{args});
173 }
174 else
175 {
176 $c->log->warn("Can't load $prov, ($@)");
177 }
178 }
179 }
180 delete $config->{PROVIDERS};
181 if(@providers) {
182 $config->{LOAD_TEMPLATES} = \@providers;
183 }
184 }
f5b61ad7 185
186 $self->{template} =
bd4ee63a 187 Template->new($config) || do {
188 my $error = Template->error();
189 $c->log->error($error);
190 $c->error($error);
191 return undef;
192 };
193
194
195 return $self;
196}
197
198sub process {
199 my ( $self, $c ) = @_;
200
201 my $template = $c->stash->{template}
202 || $c->action . $self->config->{TEMPLATE_EXTENSION};
203
204 unless (defined $template) {
205 $c->log->debug('No template specified for rendering') if $c->debug;
206 return 0;
207 }
208
fc0ffed0 209 local $@;
cad820fe 210 my $output = eval { $self->render($c, $template) };
211 if (my $err = $@) {
c5c3c6bd 212 return $self->_rendering_error($c, $template . ': ' . $err);
316f014a 213 }
214 if (blessed($output) && $output->isa('Template::Exception')) {
215 $self->_rendering_error($c, $output);
bd4ee63a 216 }
217
218 unless ( $c->response->content_type ) {
219 $c->response->content_type('text/html; charset=utf-8');
220 }
221
222 $c->response->body($output);
223
224 return 1;
225}
226
316f014a 227sub _rendering_error {
228 my ($self, $c, $err) = @_;
229 my $error = qq/Couldn't render template "$err"/;
230 $c->log->error($error);
231 $c->error($error);
232 return 0;
233}
234
bd4ee63a 235sub render {
236 my ($self, $c, $template, $args) = @_;
237
cbb149dc 238 $c->log->debug(qq/Rendering template "$template"/) if $c && $c->debug;
bd4ee63a 239
240 my $output;
f5b61ad7 241 my $vars = {
bd4ee63a 242 (ref $args eq 'HASH' ? %$args : %{ $c->stash() }),
243 $self->template_vars($c)
244 };
245
f5b61ad7 246 local $self->{include_path} =
bd4ee63a 247 [ @{ $vars->{additional_template_paths} }, @{ $self->{include_path} } ]
248 if ref $vars->{additional_template_paths};
249
596ff245 250 unless ( $self->template->process( $template, $vars, \$output ) ) {
251 if (exists $self->{render_die}) {
252 die $self->template->error if $self->{render_die};
253 return $self->template->error;
254 }
131a8e59 255 $c->log->debug('The Catalyst::View::TT render() method will start dying on error in a future release. Unless you are calling the render() method manually, you probably want the new behaviour, so set render_die => 1 in config for ' . blessed($self) . '. If you wish to continue to return the exception rather than throwing it, add render_die => 0 to your config.') if $c->debug;
596ff245 256 return $self->template->error;
257 }
cad820fe 258 return $output;
bd4ee63a 259}
260
261sub template_vars {
262 my ( $self, $c ) = @_;
263
cbb149dc 264 return () unless $c;
bd4ee63a 265 my $cvar = $self->config->{CATALYST_VAR};
266
267 defined $cvar
268 ? ( $cvar => $c )
269 : (
270 c => $c,
271 base => $c->req->base,
272 name => $c->config->{name}
273 )
274}
275
276
2771;
278
279__END__
280
8cd017a8 281=head1 DESCRIPTION
282
283This is the Catalyst view class for the L<Template Toolkit|Template>.
284Your application should defined a view class which is a subclass of
226c1dd3 285this module. Throughout this manual it will be assumed that your application
286is named F<MyApp> and you are creating a TT view named F<Web>; these names
287are placeholders and should always be replaced with whatever name you've
288chosen for your application and your view. The easiest way to create a TT
289view class is through the F<myapp_create.pl> script that is created along
290with the application:
8cd017a8 291
226c1dd3 292 $ script/myapp_create.pl view Web TT
8cd017a8 293
226c1dd3 294This creates a F<MyApp::View::Web.pm> module in the F<lib> directory (again,
8cd017a8 295replacing C<MyApp> with the name of your application) which looks
296something like this:
297
226c1dd3 298 package FooBar::View::Web;
f5b61ad7 299
8cd017a8 300 use strict;
c18eae32 301 use warnings;
f5b61ad7 302
c18eae32 303 use base 'Catalyst::View::TT';
8077080c 304
a1b7968f 305 __PACKAGE__->config(DEBUG => 'all');
8077080c 306
8cd017a8 307Now you can modify your action handlers in the main application and/or
308controllers to forward to your view class. You might choose to do this
309in the end() method, for example, to automatically forward all actions
310to the TT view class.
722fede4 311
8cd017a8 312 # In MyApp or MyApp::Controller::SomeController
f5b61ad7 313
8cd017a8 314 sub end : Private {
94b3529a 315 my( $self, $c ) = @_;
226c1dd3 316 $c->forward( $c->view('Web') );
8cd017a8 317 }
8077080c 318
2844488f 319But if you are using the standard auto-generated end action, you don't even need
320to do this!
321
322 # in MyApp::Controller::Root
323 sub end : ActionClass('RenderView') {} # no need to change this line
324
325 # in MyApp.pm
326 __PACKAGE__->config(
327 ...
226c1dd3 328 default_view => 'Web',
2844488f 329 );
330
331This will Just Work. And it has the advantages that:
332
333=over 4
334
335=item *
336
337If you want to use a different view for a given request, just set
338<< $c->stash->{current_view} >>. (See L<Catalyst>'s C<< $c->view >> method
339for details.
340
341=item *
342
343<< $c->res->redirect >> is handled by default. If you just forward to
226c1dd3 344C<View::Web> in your C<end> routine, you could break this by sending additional
2844488f 345content.
346
347=back
348
349See L<Catalyst::Action::RenderView> for more details.
350
8cd017a8 351=head2 CONFIGURATION
4687ac0d 352
8cd017a8 353There are a three different ways to configure your view class. The
354first way is to call the C<config()> method in the view subclass. This
355happens when the module is first loaded.
8077080c 356
226c1dd3 357 package MyApp::View::Web;
f5b61ad7 358
8cd017a8 359 use strict;
360 use base 'Catalyst::View::TT';
722fede4 361
226c1dd3 362 __PACKAGE__->config({
7d8aa5ec 363 INCLUDE_PATH => [
364 MyApp->path_to( 'root', 'templates', 'lib' ),
365 MyApp->path_to( 'root', 'templates', 'src' ),
366 ],
8cd017a8 367 PRE_PROCESS => 'config/main',
368 WRAPPER => 'site/wrapper',
369 });
370
226c1dd3 371You may also override the configuration provided in the view class by adding
372a 'View::Web' section to your application config (either in the application
373main class, or in your configuration file). This should be reserved for
374deployment-specific concerns. For example:
8cd017a8 375
226c1dd3 376 # MyApp_local.conf (Config::General format)
f5b61ad7 377
226c1dd3 378 <View Web>
379 WRAPPER "custom_wrapper"
380 INCLUDE_PATH __path_to('root/templates/custom_site')__
381 INCLUDE_PATH __path_to('root/templates')__
382 </View>
8cd017a8 383
226c1dd3 384might be used as part of a simple way to deploy different instances of the
385same application with different themes.
8cd017a8 386
e2bbd784 387=head2 DYNAMIC INCLUDE_PATH
388
f7dfca06 389Sometimes it is desirable to modify INCLUDE_PATH for your templates at run time.
f5b61ad7 390
f7dfca06 391Additional paths can be added to the start of INCLUDE_PATH via the stash as
392follows:
393
394 $c->stash->{additional_template_paths} =
395 [$c->config->{root} . '/test_include_path'];
396
397If you need to add paths to the end of INCLUDE_PATH, there is also an
398include_path() accessor available:
399
226c1dd3 400 push( @{ $c->view('Web')->include_path }, qw/path/ );
f7dfca06 401
402Note that if you use include_path() to add extra paths to INCLUDE_PATH, you
403MUST check for duplicate paths. Without such checking, the above code will add
404"path" to INCLUDE_PATH at every request, causing a memory leak.
405
406A safer approach is to use include_path() to overwrite the array of paths
407rather than adding to it. This eliminates both the need to perform duplicate
408checking and the chance of a memory leak:
e2bbd784 409
226c1dd3 410 @{ $c->view('Web')->include_path } = qw/path another_path/;
e2bbd784 411
f5b61ad7 412If you are calling C<render> directly then you can specify dynamic paths by
9d574573 413having a C<additional_template_paths> key with a value of additonal directories
1bc9fc55 414to search. See L<CAPTURING TEMPLATE OUTPUT> for an example showing this.
415
8cd017a8 416=head2 RENDERING VIEWS
417
418The view plugin renders the template specified in the C<template>
f5b61ad7 419item in the stash.
8cd017a8 420
421 sub message : Global {
94b3529a 422 my ( $self, $c ) = @_;
423 $c->stash->{template} = 'message.tt2';
226c1dd3 424 $c->forward( $c->view('Web') );
8cd017a8 425 }
722fede4 426
c969f23a 427If a stash item isn't defined, then it instead uses the
428stringification of the action dispatched to (as defined by $c->action)
429in the above example, this would be C<message>, but because the default
430is to append '.tt', it would load C<root/message.tt>.
8cd017a8 431
432The items defined in the stash are passed to the Template Toolkit for
433use as template variables.
434
8cd017a8 435 sub default : Private {
94b3529a 436 my ( $self, $c ) = @_;
437 $c->stash->{template} = 'message.tt2';
438 $c->stash->{message} = 'Hello World!';
226c1dd3 439 $c->forward( $c->view('Web') );
8cd017a8 440 }
7b592fc7 441
8cd017a8 442A number of other template variables are also added:
8077080c 443
8cd017a8 444 c A reference to the context object, $c
445 base The URL base, from $c->req->base()
446 name The application name, from $c->config->{ name }
447
448These can be accessed from the template in the usual way:
449
450<message.tt2>:
451
452 The message is: [% message %]
453 The base is [% base %]
454 The name is [% name %]
455
8cd017a8 456
1bc9fc55 457The output generated by the template is stored in C<< $c->response->body >>.
458
459=head2 CAPTURING TEMPLATE OUTPUT
460
461If you wish to use the output of a template for some other purpose than
462displaying in the response, e.g. for sending an email, this is possible using
463L<Catalyst::Plugin::Email> and the L<render> method:
464
465 sub send_email : Local {
466 my ($self, $c) = @_;
f5b61ad7 467
1bc9fc55 468 $c->email(
469 header => [
470 To => 'me@localhost',
471 Subject => 'A TT Email',
472 ],
226c1dd3 473 body => $c->view('Web')->render($c, 'email.tt', {
9d574573 474 additional_template_paths => [ $c->config->{root} . '/email_templates'],
1bc9fc55 475 email_tmpl_param1 => 'foo'
476 }
477 ),
478 );
479 # Redirect or display a message
480 }
8cd017a8 481
482=head2 TEMPLATE PROFILING
483
1bc9fc55 484See L<C<TIMER>> property of the L<config> method.
485
caa61517 486=head2 METHODS
8077080c 487
b63ddd04 488=head2 new
2774dc77 489
f5b61ad7 490The constructor for the TT view. Sets up the template provider,
2774dc77 491and reads the application config.
492
81b7f2a2 493=head2 process($c)
8077080c 494
1bc9fc55 495Renders the template specified in C<< $c->stash->{template} >> or
ad50568f 496C<< $c->action >> (the private name of the matched action). Calls L<render> to
1bc9fc55 497perform actual rendering. Output is stored in C<< $c->response->body >>.
8077080c 498
81b7f2a2 499It is possible to forward to the process method of a TT view from inside
500Catalyst like this:
501
226c1dd3 502 $c->forward('View::Web');
81b7f2a2 503
504N.B. This is usually done automatically by L<Catalyst::Action::RenderView>.
f2ee4d6c 505
b63ddd04 506=head2 render($c, $template, \%args)
1bc9fc55 507
cad820fe 508Renders the given template and returns output. Throws a L<Template::Exception>
f5b61ad7 509object upon error.
1bc9fc55 510
75dc0329 511The template variables are set to C<%$args> if C<$args> is a hashref, or
512C<< $c->stash >> otherwise. In either case the variables are augmented with
3d543eda 513C<base> set to C<< $c->req->base >>, C<c> to C<$c>, and C<name> to
1bc9fc55 514C<< $c->config->{name} >>. Alternately, the C<CATALYST_VAR> configuration item
515can be defined to specify the name of a template variable through which the
3d543eda 516context reference (C<$c>) can be accessed. In this case, the C<c>, C<base>, and
1bc9fc55 517C<name> variables are omitted.
518
f5b61ad7 519C<$template> can be anything that Template::process understands how to
1bc9fc55 520process, including the name of a template file or a reference to a test string.
521See L<Template::process|Template/process> for a full list of supported formats.
522
f59953e1 523To use the render method outside of your Catalyst app, just pass a undef context.
cbb149dc 524This can be useful for tests, for instance.
525
81b7f2a2 526It is possible to forward to the render method of a TT view from inside Catalyst
527to render page fragments like this:
528
226c1dd3 529 my $fragment = $c->forward("View::Web", "render", $template_name, $c->stash->{fragment_data});
f2ee4d6c 530
3715305f 531=head3 Backwards compatibility note
532
533The render method used to just return the Template::Exception object, rather
534than just throwing it. This is now deprecated and instead the render method
535will throw an exception for new applications.
536
537This behaviour can be activated (and is activated in the default skeleton
538configuration) by using C<< render_die => 1 >>. If you rely on the legacy
539behaviour then a warning will be issued.
540
541To silence this warning, set C<< render_die => 0 >>, but it is recommended
542you adjust your code so that it works with C<< render_die => 1 >>.
543
544In a future release, C<< render_die => 1 >> will become the default if
545unspecified.
546
b63ddd04 547=head2 template_vars
850ee226 548
1bc9fc55 549Returns a list of keys/values to be used as the catalyst variables in the
850ee226 550template.
551
b63ddd04 552=head2 config
8077080c 553
8cd017a8 554This method allows your view subclass to pass additional settings to
4729c102 555the TT configuration hash, or to set the options as below:
556
b63ddd04 557=head2 paths
558
559The list of paths TT will look for templates in.
4729c102 560
f5b61ad7 561=head2 C<CATALYST_VAR>
4729c102 562
563Allows you to change the name of the Catalyst context object. If set, it will also
564remove the base and name aliases, so you will have access them through <context>.
565
226c1dd3 566For example, if CATALYST_VAR has been set to "Catalyst", a template might
567contain:
4729c102 568
569 The base is [% Catalyst.req.base %]
570 The name is [% Catalyst.config.name %]
571
b63ddd04 572=head2 C<TIMER>
4729c102 573
574If you have configured Catalyst for debug output, and turned on the TIMER setting,
575C<Catalyst::View::TT> will enable profiling of template processing
576(using L<Template::Timer>). This will embed HTML comments in the
577output from your templates, such as:
578
579 <!-- TIMER START: process mainmenu/mainmenu.ttml -->
580 <!-- TIMER START: include mainmenu/cssindex.tt -->
581 <!-- TIMER START: process mainmenu/cssindex.tt -->
582 <!-- TIMER END: process mainmenu/cssindex.tt (0.017279 seconds) -->
583 <!-- TIMER END: include mainmenu/cssindex.tt (0.017401 seconds) -->
584
585 ....
586
587 <!-- TIMER END: process mainmenu/footer.tt (0.003016 seconds) -->
588
589
b63ddd04 590=head2 C<TEMPLATE_EXTENSION>
4729c102 591
747f2b6d 592a sufix to add when looking for templates bases on the C<match> method in L<Catalyst::Request>.
4729c102 593
594For example:
595
6229ce0d 596 package MyApp::Controller::Test;
f5b61ad7 597 sub test : Local { .. }
4729c102 598
599Would by default look for a template in <root>/test/test. If you set TEMPLATE_EXTENSION to '.tt', it will look for
600<root>/test/test.tt.
601
51199593 602=head2 C<PROVIDERS>
603
604Allows you to specify the template providers that TT will use.
605
606 MyApp->config({
607 name => 'MyApp',
608 root => MyApp->path_to('root'),
226c1dd3 609 'View::Web' => {
51199593 610 PROVIDERS => [
611 {
612 name => 'DBI',
613 args => {
614 DBI_DSN => 'dbi:DB2:books',
615 DBI_USER=> 'foo'
616 }
617 }, {
618 name => '_file_',
619 args => {}
620 }
621 ]
622 },
623 });
624
625The 'name' key should correspond to the class name of the provider you
626want to use. The _file_ name is a special case that represents the default
627TT file-based provider. By default the name is will be prefixed with
628'Template::Provider::'. You can fully qualify the name by using a unary
629plus:
630
631 name => '+MyApp::Provider::Foo'
632
6175bba7 633You can also specify the 'copy_config' key as an arrayref, to copy those keys
634from the general config, into the config for the provider:
f5b61ad7 635
6175bba7 636 DEFAULT_ENCODING => 'utf-8',
637 PROVIDERS => [
638 {
639 name => 'Encoding',
640 copy_config => [qw(DEFAULT_ENCODING INCLUDE_PATH)]
641 }
642 ]
f5b61ad7 643
6175bba7 644This can prove useful when you want to use the additional_template_paths hack
645in your own provider, or if you need to use Template::Provider::Encoding
646
8cd017a8 647=head2 HELPERS
648
649The L<Catalyst::Helper::View::TT> and
650L<Catalyst::Helper::View::TTSite> helper modules are provided to create
651your view module. There are invoked by the F<myapp_create.pl> script:
652
226c1dd3 653 $ script/myapp_create.pl view Web TT
8cd017a8 654
226c1dd3 655 $ script/myapp_create.pl view Web TTSite
8cd017a8 656
657The L<Catalyst::Helper::View::TT> module creates a basic TT view
658module. The L<Catalyst::Helper::View::TTSite> module goes a little
659further. It also creates a default set of templates to get you
660started. It also configures the view module to locate the templates
661automatically.
662
02c64502 663=head1 NOTES
664
665If you are using the L<CGI> module inside your templates, you will
666experience that the Catalyst server appears to hang while rendering
667the web page. This is due to the debug mode of L<CGI> (which is
668waiting for input in the terminal window). Turning off the
669debug mode using the "-no_debug" option solves the
670problem, eg.:
671
672 [% USE CGI('-no_debug') %]
673
8077080c 674=head1 SEE ALSO
675
8cd017a8 676L<Catalyst>, L<Catalyst::Helper::View::TT>,
677L<Catalyst::Helper::View::TTSite>, L<Template::Manual>
8077080c 678
c0eb0527 679=head1 AUTHORS
8077080c 680
681Sebastian Riedel, C<sri@cpan.org>
c0eb0527 682
d938377b 683Marcus Ramberg, C<mramberg@cpan.org>
c0eb0527 684
722fede4 685Jesse Sheidlower, C<jester@panix.com>
c0eb0527 686
8cd017a8 687Andy Wardley, C<abw@cpan.org>
8077080c 688
689=head1 COPYRIGHT
690
f5b61ad7 691This program is free software. You can redistribute it and/or modify it
2774dc77 692under the same terms as Perl itself.
8077080c 693
694=cut