HDEL cp . "job.$_[0]", qw/result result_text results daemon/
}
-our @EXPORT_OK = do {
+our @EXPORT = do {
no strict 'refs';
grep { $_ =~ /^[a-zA-Z]/ and exists &$_ } keys %{__PACKAGE__ . '::'};
};
my ($generator, $regex) = @_;
$generator = "Gruntmaster::Page::$generator";
eval "require $generator";
- my $gensub = $generator->can('generate') or die "No such generator: $generator";
- push @generators, [$regex, $gensub];
+ push @generators, [$regex, $generator];
}
{
my ($regex, $generator) = @$gen;
next unless $path_noext =~ $regex;
for my $lang (@{LANGUAGES()}) {
- my $page = $generator->($path, $lang);
+ my $page = $generator->generate($path, $lang);
write_file "$path_noext.$lang.$ext.new", $page;
say $typemap "URI: $basename.$lang.$ext\nContent-Language: $lang\nContent-Type: " . CONTENT_TYPES->{$ext} . "\n";
gzip \$page => "$path_noext.$lang.gz.$ext.new", Minimal => 1;
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base account => 'Account';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-
-my %orig_templates = (
- en => <<'HTML',
+use constant TEMPLATES => {
+ en => <<'HTML',
<div id="result"></div>
<h1>Register</h1>
<input type="submit" value="Change password">
</form>
HTML
-);
-
-my %templates = cook_templates %orig_templates, account => 'Account';
-
-sub generate{
- %templates = cook_templates %orig_templates, account => 'Account' if reload_templates;
- HTML::Template::Compiled->new(scalarref => \$templates{$_[1]})->output
-}
+};
1
--- /dev/null
+package Gruntmaster::Page::Base;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use File::Slurp qw/read_file/;
+use HTML::Template::Compiled;
+
+##################################################
+
+use POSIX ();
+use Gruntmaster::Data ();
+use List::Util ();
+
+sub import {
+ my $caller = caller;
+ my ($self, $name, $title) = @_;
+
+ Gruntmaster::Data->export_to_level(1, $caller);
+ List::Util->export_to_level(1, $caller, qw/sum/);
+
+ no strict 'refs';
+ *{"${caller}::strftime"} = \&POSIX::strftime;
+ *{"${caller}::NAME"} = sub () { $name };
+ *{"${caller}::TITLE"} = sub () { $title };
+}
+
+##################################################
+
+my %orig_header_templates = (
+ en => <<'HTML',
+<!DOCTYPE html>
+<title>TITLE_GOES_HERE</title>
+<link rel="stylesheet" href="/gm.css">
+<script src="/zepto.var" defer></script>
+<script src="/view.js" defer></script>
+<script src="/form.js" defer></script>
+<meta charset="utf-8">
+
+<span id="admin"></span>
+<div id="title"><span class="i">i</span><span class="Eval">Eval</span></div>
+<div id="subtitle">TITLE_GOES_HERE</div>
+
+<nav><ul><li><a href="/learn.var">Learn</a><li><a href="/pb/">Practice</a><li><a href="/ct/">Compete</a><li><a href="/log/">Job log</a></ul></nav>
+
+HTML
+);
+
+my %orig_footer_templates = (
+ en => <<'HTML',
+
+<footer>
+Dilmom: Why don't you call your product the Gruntmaster 6000?
+Dilbert: What kind of product do you see when you imagine a Gruntmaster 6000?
+Dilmom: Well, it's a stripped-down version of the Gruntmaster 9000, of course. But it's software-upgradeable.
+</footer>
+HTML
+);
+
+sub patch_templates {
+ my $root = $ENV{GRUNTMASTER_TEMPLATE_ROOT} or return;
+ my ($templates, $name) = @_;
+ my %out = %$templates;
+ for (<$root/$name*>) {
+ m/\.(.+)$/;
+ $out{$1} = read_file $_
+ }
+
+ %out
+}
+
+sub reload_templates (){ $ENV{GRUNTMASTER_RELOAD_TEMPLATES} }
+
+my %header_templates = patch_templates \%orig_header_templates, 'header';
+my %footer_templates = patch_templates \%orig_footer_templates, 'footer';
+
+sub header{
+ my ($language, $title) = @_;
+ %header_templates = patch_templates \%orig_header_templates, 'header' if reload_templates;
+ $header_templates{$language} =~ s/TITLE_GOES_HERE/$title/ger;
+}
+
+sub footer{
+ %footer_templates = patch_templates \%orig_footer_templates, 'footer' if reload_templates;
+ $footer_templates{$_[0]};
+}
+
+sub cook_templates {
+ my ($templates, $name, $title) = @_;
+
+ my %out = patch_templates $templates, $name;
+ $out{$_} = header ($_, $title) . $out{$_} for keys %out;
+ $out{$_} .= footer $_ for keys %out;
+
+ %out
+}
+
+##################################################
+
+my %templates;
+
+sub generate{
+ my ($self, $path, $lang) = @_;
+
+ $templates{$self} = { cook_templates $self->TEMPLATES, $self->NAME => $self->TITLE } if !exists $templates{$self} or reload_templates;
+
+ my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$self}{$lang}, default_escape => 'HTML',);
+ $self->_generate($htc, $path, $lang);
+ $htc->output
+}
+
+sub _generate {}
+
+1
+++ /dev/null
-package Gruntmaster::Page::Common;
-
-use 5.014000;
-use strict;
-use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/header footer cook_templates reload_templates/;
-
-use File::Slurp qw/read_file/;
-
-my %orig_header_templates = (
- en => <<'HTML',
-<!DOCTYPE html>
-<title>TITLE_GOES_HERE</title>
-<link rel="stylesheet" href="/gm.css">
-<script src="/zepto.var" defer></script>
-<script src="/view.js" defer></script>
-<script src="/form.js" defer></script>
-<meta charset="utf-8">
-
-<span id="admin"></span>
-<div id="title"><span class="i">i</span><span class="Eval">Eval</span></div>
-<div id="subtitle">TITLE_GOES_HERE</div>
-
-<nav><ul><li><a href="/learn.var">Learn</a><li><a href="/pb/">Practice</a><li><a href="/ct/">Compete</a><li><a href="/log/">Job log</a></ul></nav>
-
-HTML
-);
-
-my %orig_footer_templates = (
- en => <<'HTML',
-
-<footer>
-Dilmom: Why don't you call your product the Gruntmaster 6000?
-Dilbert: What kind of product do you see when you imagine a Gruntmaster 6000?
-Dilmom: Well, it's a stripped-down version of the Gruntmaster 9000, of course. But it's software-upgradeable.
-</footer>
-HTML
-);
-
-sub patch_templates {
- my $root = $ENV{GRUNTMASTER_TEMPLATE_ROOT} or return;
- my ($templates, $name) = @_;
- my %out = %$templates;
- for (<$root/$name*>) {
- m/\.(.+)$/;
- $out{$1} = read_file $_
- }
-
- %out
-}
-
-my %header_templates = patch_templates \%orig_header_templates, 'header';
-my %footer_templates = patch_templates \%orig_footer_templates, 'footer';
-
-sub reload_templates () { $ENV{GRUNTMASTER_RELOAD_TEMPLATES} }
-
-sub header{
- my ($language, $title) = @_;
- %header_templates = patch_templates \%orig_header_templates, 'header' if reload_templates;
- $header_templates{$language} =~ s/TITLE_GOES_HERE/$title/ger;
-}
-
-sub footer{
- %footer_templates = patch_templates \%orig_footer_templates, 'footer' if reload_templates;
- $footer_templates{$_[0]};
-}
-
-sub cook_templates (\%@) {
- my ($templates, $name, $title) = @_;
-
- my %out = patch_templates $templates, $name;
- $out{$_} = header ($_, $title) . $out{$_} for keys %out;
- $out{$_} .= footer $_ for keys %out;
-
- %out
-}
-
-1;
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base ct => 'Contests';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/contests contest_name contest_start contest_end contest_owner/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<tmpl_if running>
<h1>Running contests</h1>
</table>
</tmpl_if>
HTML
-);
-
-my %templates = cook_templates %orig_templates, ct => 'Contests';
+};
-sub generate{
- %templates = cook_templates %orig_templates, ct => 'Contests' if reload_templates;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
my (@running, @pending, @finished);
for (contests) {
$htc->param(running => \@running);
$htc->param(pending => \@pending);
$htc->param(finished => \@finished);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base ct_entry => '<tmpl_var name>';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/contest_name contest_start contest_end/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
Contest start time: <tmpl_var start><br>
Contest end time: <tmpl_var end><p>
<a href="log/">Job log</a><br>
<a href="log/st.var">Standings</a></tmpl_if>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, ct_entry => '<tmpl_var name>';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, ct_entry => '<tmpl_var name>' if reload_templates;
- my ($path, $lang) = @_;
$path = ($path =~ m,ct/(.*)/index,)[0];
- my $template = $templates{$lang};
- my $htc = HTML::Template::Compiled->new(scalarref => \$template);
$htc->param(id => $path);
$htc->param(name => contest_name $path);
$htc->param(start => strftime '%c', contest_start);
$htc->param(end => strftime '%c', contest_end);
$htc->param(started => time >= contest_start);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base index => 'Gruntmaster 6000';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-
-my %orig_templates = (
- en => <<'HTML',
+use constant TEMPLATES => {
+ en => <<'HTML',
HTML
-);
-
-my %templates = cook_templates %orig_templates, index => 'Gruntmaster 6000';
-
-sub generate{
- %templates = cook_templates %orig_templates, index => 'Gruntmaster 6000' if reload_templates;
- HTML::Template::Compiled->new(scalarref => \$templates{$_[1]})->output
-}
+};
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base learn => 'Learn';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-
-my %orig_templates = (
- en => <<'HTML',
+use constant TEMPLATES => {
+ en => <<'HTML',
Install interactive-perl-tutorial from your nearest CPAN mirror. Run <code>cpan App::InteractivePerlTutorial</code>.
<p>You can also get the source from <a href="http://git.ieval.ro/?p=app-interactiveperltutorial.git">git.ieval.ro</a>
HTML
-);
-
-my %templates = cook_templates %orig_templates, learn => 'Learn';
-
-sub generate{
- %templates = cook_templates %orig_templates, learn => 'Learn' if reload_templates;
- HTML::Template::Compiled->new(scalarref => \$templates{$_[1]})->output;
-}
+};
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base log => 'Job log';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
use constant PAGE_SIZE => 10;
CPP => 'cpp',
};
-use HTML::Template::Compiled;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/jobcard job_date job_extension job_filesize problem_name job_private job_problem job_result job_result_text job_user/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<table border>
<thead>
</tmpl_loop>
</table>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, log => 'Job log';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, log => 'Job log' if reload_templates;
- $_[0] =~ m,^(?:ct/([^/]+)/)?log/(\w+)\.html$,;
+ $path =~ m,^(?:ct/([^/]+)/)?log/(\w+)\.html$,;
local $Gruntmaster::Data::contest = $1;
my $pages = jobcard / PAGE_SIZE;
my $page = $2 eq 'index' ? $pages : $2;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
my @log = sort { $b->{id} <=> $a->{id} } map +{
id => $_,
(job_private() ? (private => job_private) : ()),
size => sprintf ("%.2f KiB", job_filesize() / 1024),
user => job_user}, ($page - 1) * PAGE_SIZE + 1 .. $page == $pages ? jobcard : $page * PAGE_SIZE;
$htc->param(log => \@log);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base log_entry => 'Job <tmpl_var id>';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/job_results/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<table border>
<thead>
</tmpl_loop>
</table>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, log_entry => 'Job <tmpl_var id>';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, log_entry => 'Job <tmpl_var id>' if reload_templates;
- $_[0] =~ m,^(?:ct/([^/]+)/)?log/job/([^/]+)\.html$,;
+ $path =~ m,^(?:ct/([^/]+)/)?log/job/([^/]+)\.html$,;
local $Gruntmaster::Data::contest = $1;
my $id = $2;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
-
my @tests = map {
$_->{time} = sprintf "%.4fs", $_->{time};
$_
$htc->param(id => $id);
$htc->param(tests => \@tests);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base pb => 'Problems';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use Fcntl qw/:flock/;
-use HTML::Template::Compiled;
-use IO::File;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/problem_name problem_level problems/;
-
-my %orig_templates = (
- en => <<'HTML',
+use constant TEMPLATES => {
+ en => <<'HTML',
<tmpl_if levels>
<h2>Beginner</h2>
<ul>
</tmpl_loop></ul>
</tmpl_if>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, pb => 'Problems';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, pb => 'Problems' if reload_templates;
- $_[0] =~ m,^(?:ct/([^/]+)/)?pb/index.html$,;
+ $path =~ m,^(?:ct/([^/]+)/)?pb/index.html$,;
local $Gruntmaster::Data::contest = $1;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
my @problems = sort { $b->{name} cmp $a->{name} } map +{
id => $_,
name => problem_name,
level => problem_level}, problems;
+
for my $d (qw/beginner easy medium advanced hard/) {
$htc->param($d => [grep {$_->{level} and $_->{level} eq $d} @problems]);
}
$htc->param(levels => grep { $_->{level} } @problems);
$htc->param(problems => \@problems);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base pb_entry => '<tmpl_var name>';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/contest_start contest_end problem_name problem_statement/;
-
use constant FORMATS => [qw/CPP/];
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<tmpl_var statement>
</form>
</tmpl_if>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, pb_entry => '<tmpl_var name>';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, pb_entry => '<tmpl_var name>' if reload_templates;
- $_[0] =~ m,(?:ct/([^/])+/)?pb/(\w+)\.html$,;
+ $path =~ m,(?:ct/([^/])+/)?pb/(\w+)\.html$,;
my ($contest, $id) = ($1, $2);
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
$htc->param(cansubmit => 1);
if (defined $contest) {
local $Gruntmaster::Data::contest = $contest if $contest;
$htc->param(name => problem_name $id);
$htc->param(statement => problem_statement $id);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base st => 'Standings';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use List::Util qw/sum/;
-use POSIX qw/strftime/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/problems jobcard job_result_text job_result job_problem job_user/;
-
-my %orig_templates = (
+use constant => TEMPLATES => {
en => <<'HTML',
<table border>
<thead>
</tmpl_loop>
</table>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, st => 'Standings';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, st => 'Standings' if reload_templates;
- local $Gruntmaster::Data::contest = ($_[0] =~ m,^ct/([^/]+)/,)[0];
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
+ local $Gruntmaster::Data::contest = ($path =~ m,^ct/([^/]+)/,)[0];
my @problems = sort problems;
my %scores;
} keys %scores;
$htc->param(problems => \@problems);
$htc->param(st => \@st);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base submit => 'Submit job';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
use constant FORMATS => [qw/CPP/];
-use HTML::Template::Compiled;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-use Gruntmaster::Data qw/problem_name problems/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<form action="https://gm.ieval.ro/action/submit" method="POST" enctype="multipart/form-data">
<label>Problem:<br>
<input type="submit" value="Submit job">
HTML
-);
-
-my %templates = cook_templates %orig_templates, submit => 'Submit job';
+};
-sub generate{
- %templates = cook_templates %orig_templates, submit => 'Submit job' if reload_templates;
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
my @problems = map +{ id => $_, name => problem_name }, problems;
$htc->param(problems => \@problems);
$htc->param(formats => FORMATS);
- $htc->output
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base us => 'Users';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use Gruntmaster::Data qw/users user_name/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<ul><tmpl_loop users><li><a href="<tmpl_var id>.var"><tmpl_var name></a>
</tmpl_loop></ul>
HTML
-);
-
-my %templates = cook_templates %orig_templates, us => 'Users';
+};
-sub generate{
- %templates = cook_templates %orig_templates, us => 'Users' if reload_templates;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
$htc->param(users => [ map { {id => $_, name => user_name} } users ]);
- $htc->output;
}
1
use 5.014000;
use strict;
use warnings;
-use parent qw/Exporter/;
-our @EXPORT_OK = qw/generate/;
+use Gruntmaster::Page::Base us_entry => '<tmpl_var name>';
+our @ISA = qw/Gruntmaster::Page::Base/;
our $VERSION = '0.001';
-use HTML::Template::Compiled;
-use Gruntmaster::Data qw/users user_name user_town user_university user_level/;
-use Gruntmaster::Page::Common qw/cook_templates reload_templates/;
-
-my %orig_templates = (
+use constant TEMPLATES => {
en => <<'HTML',
<h1><tmpl_var name></h1>
Town: <tmpl_var town><br>
University: <tmpl_var university><br>
Level: <tmpl_var level>
HTML
-);
+};
-my %templates = cook_templates %orig_templates, us_entry => '<tmpl_var name>';
+sub _generate{
+ my ($self, $htc, $path, $lang) = @_;
-sub generate{
- %templates = cook_templates %orig_templates, us_entry => '<tmpl_var name>' if reload_templates;
- $_[0] =~ m,^us/([^/]+)\.html$,;
+ $path =~ m,^us/([^/]+)\.html$,;
local $_ = $1;
- my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$_[1]});
$htc->param(name => user_name);
$htc->param(town => user_town);
$htc->param(university => user_university);
$htc->param(level => user_level);
- $htc->output;
}
1