NAME
WWW::Autosite - support subroutines for autosite handlers, router, and misc cgi scripts
SYNOPSIS
In /var/www/cgi-bin/wraphtm.cgi:
#!/usr/bin/perl -w
use strict;
use WWW::Autosite ':all';
my $tmpl = handler_tmpl();
feed_META( $tmpl, $ENV{PATH_TRANSLATED} );
feed_ENV( $tmpl);
feed_FILE( $tmpl, $ENV{PATH_TRANSLATED} );
feed_PLUGIN_PATH_NAVIGATION($tmpl, $ENV{PATH_TRANSLATED});
$tmpl->param( BODY => slurp($ENV{PATH_TRANSLATED}));
print "Content-Type: text/html\n\n";
print $tmpl->output;
exit;
In /var/www/html/barebones.htm:
<h1>Welcome!</h1>
<p>This is some wonderful html content here.</p>
In /var/www/html/barebones.htm.meta:
---
title: BareBones file.
description: This is one lonely file.
keywords: bare,bare bones,barebone
author: Myself A I
In /var/www/html/.htaccess:
Action wraphtm /cgi-bin/wraphtm.cgi
AddHandler wraphtm .htm
DESCRIPTION
Support subroutines for building cgi with HTML::Template.
Subroutines
No subs are exported by default. None.
get_tmpl()
Takes two arguments. Returns HTML::Template object.
First is a path or filename to an HTML::Template file. If the path to template is not absolute (if it's just a filename, ie:'this.html') it will seek it inside ENV AUTOSITE_TMPL.
Second argument, optional, is a scalar with default code for the template. This is what allows a user to override the default look by simply creating a file inside the ENV AUTOSITE_TMPL.
Returns HTML::Template object. The HTML::Template object returned will have a die_on_bad_params set to 0.
(If you are creating a handler, you can use get_tmpl() to provide a default template to feed stuff into. This also allows user to place a template of their own in the AUTOSITE_TMPL directory.)
Example 1
In the following example, if main.html does not exist in ENV AUTOSITE_TMPL, the '$default' code provided is used as the template.
my $default = "<html>
<head>
<title>Hi.</title>
</head>
<body>
<TMPL_VAR BODY>
</body>
</html>";
my $tmpl = get_tmpl('main.html',$default);
To override that template, one would create the file main.html in ENV AUTOSITE_TMPL. The perl code need not change. This merely lets you provide a default, optionally.
Again, if main.html is not in AUTOSITE_TMPL, it will use default string provided- if no default string provided, and filename is not found, croaks.
Example 2
In the following example, the template file 'awesome.html' must exist in ENV AUTOSITE_TMPL. Or the application croaks.
my $tmpl = get_tmpl('awesome.html');
_path_to_hash()
argument is full file path returns hash with useful file info, moslty intended to further transform to feed into the template
icon()
argument is abs path to file, returns icon name for resource.
script_dir()
Accepts no arguments. Returns absolute location of running script. I said absolute 'location', which is the directory it resides in.
slurp()
argument is abs path to a -t text file returns content
my $src - slurp('/path/to/default.css');
abs_path_n()
just like Cwd::abs_path() but, does not resolve symlinks. Just cleans up the path. argument is an abs path.
get_meta()
argument is absolute path to a file on disk returns metadata hash if found.
set_meta()
argument is absolute path and hash ref with metadata does NOT check to see if the file exists.
set_meta('/home/file',{ name => 'hi', age => 4 });
Above example creates meta file '/home/file.meta' :
---
name: hi
age: 4
See also: YAML
Html Block Subroutines
These functions should be useful for general purpose. They all look for a template that overrides the look and feel provided by default. That is, you can use all these as is to insert a 'navigation path' for the top of the page, these all return html blocks. To change the look, you must create the matching HTML::Template file.
get_plugin_file_info()
Required argument is abs path. Feeds some data on file. Looks for template 'plugin_file_info.html' in ENV AUTOSITE_TMPL If not found, uses default template.
get_plugin_file_info('/path/to/file');
Default template is:
<style>
._info {}
</style>
<div class="_info">
<ul>
<li><TMPL_VAR FILE_FILENAME></li>
<li><TMPL_VAR FILE_MTIME_PRETTY></li>
<li><TMPL_VAR FILE_FILESIZE_PRETTY></li>
</ul>
</div>
get_plugin_path_navigation()
Required argument is absolute path to file.
Builds a step through of the hierarchy navigation for the path. for example if your content is http://domain/files/document.pdf The default output is something like
home >> files >> document.pdf
With links. Self explanatory. Returns html block.
The default template (if 'plugin_path_navigation.html' is not in your templates dir) is:
<div id="path_navigation">
<TMPL_LOOP NAVIGATION>
<span>»
<a href="<TMPL_VAR REL_PATH>"><TMPL_VAR FILENAME></a>
</span>
</TMPL_LOOP>
<span>»
<TMPL_VAR FILE_FILENAME>
</span>
</div>
If DOCUMENT_ROOT is not set, warns with carp and returns undef. If the argument *is* document root, returns undef.
CONCEPTS
Autosite is meant to create content on the fly. It may be triggered by a 404 not found error, in which case, ideally, autosite generates the content and saves to disk, so subsequest requests do not trigger a 404 error- and also, do not use valuable cpu time by calling a script.
Maybe Joe wants to have a website for his 'pigeon salon beauty' business. So he sends you pictures of his pigeons, and some text blurb about his business, maybe some info about his address and hours of operation. You piece all this together in to html and create a site. You are the designer. The picture and text Joe gave you is the content. The html you pieced together was an ungodly act of horror- And instead should be server generated content, or sgc for short. Which is what autosite is all about.
The main concepts of this system are:
"Concept 1: The Content" "Concept 2: The Router" "Concept 3: The Handler" "Concept 4: The SGC"
What does this do?
Joe's about us blurb is placed inside about_us.txt. This is not a formatted text file, this is text exactly as would be sent by Joe himself to you over email. It is uploaded to http://joesbirds.com/about_us.txt. Joe goes online, and punches in http://joesbirds.com/about_us.txt, all he sees is a text file. What you would expect. But then Joe enters this url in the address bar: http://joesbirds.com/about_us.txt.html Now, his 'about us' information is presented beautifully embedded into a webpage. Full formatting is present. It's a professional webpage.
The same can be done with image files, audio files, etc. The designer just tweaks the look and feel in the template system. As desired. And has no worry or concern at all whatsoever about the content of the website. Because now, anybody that knows how to use email, can use fpt or some other method to upload text files, images, whatever junk they would normally give the designer.
How it does it do it?
1) 'about_us.txt' is the content file.
2) 'about_us.txt.html' is the request for a server generated content file sgc which does not exist, and thus triggers a 404 error.
3) The .htaccess file says 404 errors are handled by the router script.
4) The router script tries to match up the sgc request with a content file on disk. In this case, it checks that about_us.txt really is on disk. Then the router tries some heuristic and then mime checking methods to see if you have a handler script present for creating a 'about_us.txt.html' sgc file from the 'about_us.txt' content file.
5) If found, the handler script is asked to create the sgc data.
6) if we are configured to write server generated content (sgc), we write to disk and redirect, otherwise we send to browser.
Flowchart
404 error \ `-> router script -> (does not match sgc request) -> 404 error page \ `-> (matches sgc request) -> (no handler found) -> 404 error page \ `-> handler script -> (WRITE_SGC is on) -> save sgc file, redirect \ `-> (WRITE_SGC is off) -> print output to browser
Concept 1: The Content
Concept 2: The Router
The purpose of the router is to coordinate what the client browser asked for with what the server is configured to offer. The client browser may ask for sgc, the router will determine if a handler is present and act accordingly.
Imagine you upload filex.pdf to:
http://domain.com/filex.pdf
And a client browser requests url:
http://domain.com/filex.pdf.html
This file does not exist. Apache will trigger a 404 error. In our .htaccess file we want a directive that says all 404 errors will be handled by our router:
ErrorDocument 404 /cgi-bin/autosite/router.cgi
The ENV REQUEST_URI (in this case: '/filex.pdf.html') Is analized, and in this case a handler called pdf.html.pl would be searched for. Second, a binary.html.pl handler would be searched for.
This makes it so if you want to add a handler, you just drop it alongside router.cgi.
The subroutines in this section are primarily meant to be used with the router script. Being functional oriented, they can be used elsewhere.
The Router Steps
How does the router work? The router will:
- 1) use heuristics to see if the request looks like it might have a handler
-
filex.pdf.html would be judged to possibly have a handler. two extensions suggests a handler
- 2) determine if the content file exists
-
In this example, we could see if the file filex.pdf exists on the server.
- 3) find a handler
-
Now for finding the handler. First we would look for
pdf.html.pl
Then
pdf.html.cgi
Then before we give up, we would analize the content file- and look for a 'text' or 'binary' handler for this type.
binary.html.pl
This way, if you wanted to have a 'catchall' for zipping up binary files, you would have a handler named
binary.zip.pl
This would allow any xxx.avi.zip, xxx.mp3.zip ,etc (binary content files) to be turned into zip files to be send to the browser.
You could have had a avi.zip.pl and mp3.zip.pl individual handlers, this is just a shortcut.
- 4) ask the handler to make the sgc
- 5) send sgc to the browser
-
If WWW::Autosite::WRITE_SGC is set to 1, attempts to write to sgc location. otherwise, prints to browser.
More about sgc requests to the router
these are example sgc requests:
/demo/doc1.pod.html
/demo/picture.jpg.html
/great/video.avi.zip
/dira/song1.mp3.html
/demo/doc1.pod.hi # syntax highlighting
the ENV PATH TRANSLATED would hold these urls, which would have triggered a 404 error inside the .htaccess file is an entry that reads
ErrorDocument 404 /cgi-bin/autosite/router.cgi
which is this script. in the above examples, this script would look for
first, second:
pod.html.pl text.html.pl
jpg.html.pl binary.html.pl
avi.zip.pl binary.zip.pl
mp3.html.pl binary.html.pl
pod.hi.pl text.hi.pl
In the same directory as this script. It would do a system call to one of these scripts and the client would be redirected to the now existand server generated content (sgc).
To handle other types of conversions, the appropriate script would have to be present in cgi-bin/autosite The argument sent to the script is the abs path to the content file
Concept 3: The Handler
A handler is a script that takes as argument an absolute file path. The handler by default does one thing with one type of file. It may convert simple text to html. It may generate a zip file for the argument.
Concept 4: The SGC
sgc is short for server generated content.
Router Subroutines
request_sgc()
takes no argument. returns absolute path to request, which will be a sgc file. if this does not make sense as an sgc file, returns undef.
For example, if you request 'http://domain.com/file1.jpg.html' Then this returns '/home/xxx/public_html/file1.jpg.html'
If the request was 'http://domain.com/file1.jghtml' This returns nothing.
request_sgc() does not test for existance of a handler, it just uses heuristics to see if the request could have a handler.
request_exts()
Optional argument is request abs path or filename. Otherwise uses ENV REQUEST_URI. tests ENV REQUEST_URI to see if we have 'from' and 'to' extensions. returns fromext and toext. returns undef if no ext tuple is matched.
my ($tuplefrom, $tupleto) = request_exts();
my ($tuplefrom, $tupleto) = request_exts('filename.html.hi');
request_exts() or die('useless request');
request_has_handler()
Optional argument is abs path of the requested sgc, and optional scripts directory
uses heuristics and file tests to see if the requested sgc has a handler. returns abs path to handler script.
request_has_handler('/var/www/html/wonderful.pod.html','/var/www/cgi-gin/autosite');
returns false if no handler found
pseudomime()
argument is abs path to a file returns first chunk of mime type, so for a jpg file returns 'image'
request_abs_content()
optional argument is abs path to sgc. if argument is missing, builds path from ENV REQUEST_URI eturns absolute path to content. returns undef if sgc file requested does not have an equivalent content file on disk
That is, if you request http://domain.com/file1.jpg.zip, it returns http://domain.com/file1.jpg if it exists.
request_route()
takes no argument routes.
if WWW::Autosite::WRITE_SGC is 1, then it attempts to write the sgc file, so subsequent requests do not issue a 404 error.
otherwise, sends sgc to browser as stream. not very cpu friendly, but.. good for development and testing.
Handler Subroutines 1
They inject stuff into your HTML::Template, provided your template is set up to show it. All these subs take your tmpl object as argument.
feed_ENV()
argument is a tmpl object ref returns tmpl object
feed_ENV($tmpl)
feeds all ENV variables to template as
<TMPL_VAR ENV_DOCUMENT_ROOT>
<TMPL_VAR ENV_REQUEST_URI>
<TMPL_VAR ...
feed_PLUGIN_PATH_NAVIGATION()
Required argument is tmpl object. Optional argument is abs path. If no path argument is provided, uses the content file.
Provided your template has <TMPL_VAR PLUGIN_PATH_NAVIGATION>, it is fed with the output of get_plugin_path_navigation()
feed_PLUGIN_FILE_INFO()
Required argument is tmpl object. Optional argument is abs path. If no path argument is provided, uses the content file. Feeds output of get_plugin_file_info() to template.
Your template object should have the variable <TMPL_VAR PLUGIN_FILE_INFO>
feed_PLUGIN_FILE_INFO($tmpl);
feed_PLUGIN_FILE_INFO($tmpl,'/home/my/files/thisone');
returns template object.
feed_META()
arguments are tmpl object and abs path If path argument is missing, uses content file. This is also for use by a handler. returns tmpl object
It seeks a matching YAML text file to treat as metadata to feed to your template.
feed_META($tmpl,'/abs/path/to/what.jpg');
feeds any META variables as
<TMPL_VAR META_TITLE>
<TMPL_VAR META_DESCRIPTION>
<TMPL_VAR ...
implies that if your file is
file.jpg
and you have a
file.jpg.meta
in that same dir, the template will be fed with any meta in that file the file must be YAML format.
Imagine you want your 'picture44.jpg' file to have an author and description caption. The your template would say somewhere:
<p><img src="/<TMPL_VAR FILE_REL_PATH>"></p>
<p>author: <TMPL_VAR META_AUTHOR></p>
<p><TMPL_VAR META_DESCRIPTION></p>
Your metafile would be 'picture44.jpg.meta' and it would contain:
___
author: Joe Schmoe
description: A wonderful picture.
The default handler does call feed_META() by default. Title, and description are looked for. If you want to add other meta tags, you should modify the template or create a new one. Imagine you wanted to add a 'location' meta tag. You would add
<p><img src="/<TMPL_VAR FILE_REL_PATH>"></p>
<p>author: <TMPL_VAR META_AUTHOR></p>
<p><TMPL_VAR META_DESCRIPTION></p>
<p>Shot at: <TMPL_VAR META_LOCATION></p>
And in your meta file
___
author: Joe Schmoe
description: A wonderful picture.
location: Kensington, MD.
This provides a very simple way of adding data to resources. Without using an application database, etc. It's very simple. Take the filename and add a .meta extension, without removing the file's extension. The meta file *must* reside in the same directory as the file you are setting metadata for. You can set metadata for directories as well.
You could also set a sitewide metadata file and have your hanlder feed it. In it you could place whatever info you want, such as contact or address information. Then, to change this data sitewide, you would only do it to that one YAML text file. And all your site would magically match up.
Meta files can also be hidden, starting with a dot.
Please see YAML
feed_FILE()
Required argument is tmpl object. Optional argument is abs path. If not provided, uses content file. Will populate the template with file information, such as filesize, file ctime, atime, rel path, rel location, etc.. returns tmpl object
feed_FILE($tmpl);
feed_FILE($tmpl,'/home/myself/public_html/file1.jpg');
feeds File::PathInfo variables to template as
<TMPL_VAR FILE_FILENAME>
<TMPL_VAR FILE_FILESIZE>
<TMPL_VAR FILE_CTIME>
<TMPL_VAR FILE_ABS_PATH>
<TMPL_VAR FILE_ABS_LOC>
<TMPL_VAR FILE_REL_LOC>
<TMPL_VAR FILE_REL_PATH>
<TMPL_VAR ...
Note that a directory is also a file. Here is a sample of the variables set for any file (or directory):
FILE_ABS_LOC = '/root/devel/autosite2/public_html/tmp'
FILE_ABS_PATH = '/root/devel/autosite2/public_html/tmp/test.pod'
FILE_ATIME = 1172618786
FILE_ATIME_PRETTY = '2007/02/27 18:26'
FILE_BLKSIZE = 4096
FILE_BLOCKS = 8
FILE_CTIME = 1172513325
FILE_CTIME_PRETTY = '2007/02/26 13:08'
FILE_DEV = 2049
FILE_EXT = 'pod'
FILE_FILENAME = 'test.pod'
FILE_FILENAME_ONLY = 'test'
FILE_FILESIZE = '361'
FILE_FILESIZE_PRETTY = '0k'
FILE_GID = 0
FILE_ICON = 'text'
FILE_INO = 1897024
FILE_IS_BINARY = 0
FILE_IS_DIR = 0
FILE_IS_DOCUMENT_ROOT = 0
FILE_IS_FILE = 1
FILE_IS_IN_DOCUMENT_ROOT = 1
FILE_IS_TEXT = 1
FILE_IS_TOPMOST = 0
FILE_MODE = 33188
FILE_MTIME = 1172513325
FILE_MTIME_PRETTY = '2007/02/26 13:08'
FILE_NLINK = 1
FILE_RDEV = 0
FILE_REL_LOC = 'tmp'
FILE_REL_PATH = '/tmp/test.pod.html'
FILE_SIZE = '361'
FILE_UID = 0
So, if you would like it when someone calls content 'file1.mpg' as 'file1.mpg.html' to also see the creation time, you would add this variable to main.html
<TMPL_VAR NAME="FILE_CTIME_PRETTY">
or
<tmpl_var name=file_ctime_pretty>
or
<TMPL_VAR FILE_CTIME_PRETTY>
See also File::PathInfo.
feed_PLUGIN_SITE_MAIN_MENU()
BETA
Required argument is tmpl (HTML::Template) object. Optional argument is a hash ref with options. Will populate the template with main menu for the site.
returns tmpl object
To override default layout, create a plugin_site_main_menu.html file in AUTOSITE_TMPL directory. This is the template that is populated and injected into your main template via the template variable PLUGIN_SITE_MAIN_MENU. Thus, your template needs to have <TMPL_VAR PLUGIN_SITE_MAIN_MENU> for this to be injected.
Opens up DOCUMENT ROOT, looks for any directories and html files and feeds them as main menu options.
feed_PLUGIN_SITE_MAIN_MENU($tmpl);
Optional arguments:
feed_PLUGIN_MAIN_MENU(
$tmpl,{
match => qr/^\w+$/,
text_files_only => 1,
},
);
If you provide a 'match' argument, then it is performed for the listing. In the above example, only files and directories with word characters beginning to end would shoud up as main menu items. The 'text_files_only' argument, means that only text files in DOCUMENT ROOT will be considered as menu items. This is the default. This means if you have movie.avi in your DOCUMENT ROOT directory, it would not show as a menu item.
Imagine only files and directories starting with uppercase letters should be considered to be main menu items..
feed_PLUGIN_MAIN_MENU($tmpl, { match => qr/^[A-Z]/ } );
No files or directories starting with a dot can be used as main menu items with this subroutine.
Handler Subroutines 2
handler_filename()
no arg, returns filename (no leading dirs) of the calling script (the handler).
handler_exts()
Determines what input extension (content) the handler will accept, and what kind of output extension (sgf) is should give. (Argument can be calling scripts filename. This is default.) This is determined from the running script's filename. If you want to determine this from the content request, use request_exts() instead
for example if the script makes sure a mp3 file has a zipped up version on disk.. the handler should be called mp3.zip.pl
my($content_ext,$sgc_ext) = handler_exts();
This would return for mp3.zip.pl
('mp3','zip')
First is what the script suggests it can handle, second is what it will output.
You script can also be called
text.*.pl (for example: text.hi.pl, text.html.pl)
Or
binary.*.pl (for example binary.zip.pl, binary.info.pl)
These are catchalls.
If you name any handler starting with text, the request content file must be -T (text).
If you name any handler starting with binary, the request must be not -T (text);
handler_content()
Preferably takes no arguments. Returns absolute path to content file.
my $abs_content = handler_content()
provided your handler should be passed one argument (the path to the content), this subroutine will attempt to read $ARGV[0] and resolve to absolute path. Optionally, you may give as argument a file path.
This resolves for symlinks etc.
Note that if the handler's filename is mp3.zip.pl, the argument to the handler must be an mp3 file This is ok:
perl mp3.zip.pl /home/xxx/public_html/music/mp3file.mp3
This is not ok:
perl mp3.zip.pl /home/xxx/public_html/music/mp3file.mpg
It will die. Which is good. Autosite handlers should not be called as cgi.
The file argument t othe handler script also must resolve to disk and must exist- or this dies.
Returns absolute path to content and method it found . For the method returns a number 0 through 4, which mean:
0 no argument
1 argument (to sub)
2 ARGV (cli)
3 ENV PATH TRANSLATED (apache handler)
4 REQUEST_URI (redirected via htaccess rewrite)
This is useful as..
my($method,$abs_content) = handler_content()
print "Content-Type: text/html\n\n" if $method > 2;
handler_sgc()
Optionally takes a file path argument. Returns absolute path to where the sgc should be for this content.
my $abs_sgc = handler_sgc();
In the above example for handler_content() you see
perl mp3.zip.pl /home/xxx/public_html/music/mp3file.mp3
The above $abs_sgc variable would in this example hold '/home/xxx/public_html/music/mp3file.mp3.zip'
handler_tmpl()
Takes no argument. Seeks for ENV AUTOSITE_TMPL / main.html Returns the main template HTML::Template object. If none exists at AUTOSITE_TMPL, default is used.
handler_write_sgc()
Argument is template object, optionally, the abs sgc. Returns true.
handler_write_sgc($tmpl); # save to path returned by handler_sgc()
handler_write_sgc($tmpl, $abs_sgc); # if you wanted to save elsewhere
Handlers should by default print to stdout?
GLOSSARY
- user
-
The person who manages the content on the site. This is the person who paid you to host and or design their site.
- designer
-
The person who manages look and feel of the site. This person is in charge of layout, graphic design, and altering the templates.
- handler
-
In this document a 'handler' is a script that creates sgc on the fly.
Example: If you have a pod-html handler. The user uploads file.pod. Then someone opens a browser and types in domain.com/file.pod.html, if the file does not exist, the handler creates the file. This is managed by the router.
The handler is in charge of fetching your templates, etc and generating content.
A handler is NOT a cgi script. It should function perfectly well as a cli tool. Various handlers are included in this distro.
One of the major highlights of this system is to allow you to easily add new handlers without doing more then dropping in a file.
- content
-
This is what the user uploads to the site. If your user is a band who paid you to host or design their site, then they may be uploading songs, for example. Then some of their content will be for example; song1.mp3, song2.mp3. Maybe they have a bio page, this would be bio.txt. Maybe they are uploading a press kit in zip format, press_kit.zip. These are all content files. When you are designing a site in a conventional manner, you have the client email you their 'about us' text, 'contact info'- maybe some pictures. With autosite, the user can upload all that content to the website and it is instantly presented with the layout you designed.
- sgc
-
The (s)erver (g)enereated (c)ontent. A 'server generated content' file is a file that was generated by a handler, about a content file. It is automated content, about user provided content.
Example: The user content is 'file.mp3'. This file resides in DOCUMENT ROOT. Thus, to download the file:
http://domain.com/file.mp3
However, what if you want to see a presentation about the file, maybe am excerpt, a link to a zip file?
http://domain.com/file.mp3.html
And maybe you just want to download a zipped up copy
http://domain.com/file.mp3.zip
The html and the zip files are what we refer to as sgc.
Sgc files should be regarded with contempt- they are not precious. They should not be edited directly. That would defeat the whole purpose of autosite.
The sgc files can be extremely fine tuned via the editing of HTML::Template files provided. New ones can be created. Also, you are welcome to code your own handler for whatever.
- router
-
The router takes the client browser requests and forwards them to the appropriate handler, if one exists. The router is a cgi script, an .htaccess file is required to forward 404 errors to this script.
- .htaccess
-
The htaccess file is crucial to the autosite system. It should catch 404 errors and send them to the router.
Example .htaccess file entry:
ErrorDocument 404 /cgi-bin/autosite/router.cgi
- ENV AUTOSITE_TMPL
-
Required for use with router, handlers. Environment variable. This is the absolute path to templates directory.
- main template
-
Required for use with router and handlers. Must reside in "ENV AUTOSITE_TMPL". Must be named main.html. This template's only required TMPL_VAR is BODY.
DEBUGGING
To debug, set DEBUG to 1
use WWW::Autosite;
WWW::Autosite::DEBUG = 1;
SEE ALSO
AUTHOR
Leo Charre
2 POD Errors
The following errors were encountered while parsing the POD:
- Around line 1674:
'=item' outside of any '=over'
- Around line 1762:
You forgot a '=back' before '=head1'