Initial commit
authorMarius Gavrilescu <marius@ieval.ro>
Tue, 19 Nov 2013 21:06:47 +0000 (23:06 +0200)
committerMarius Gavrilescu <marius@ieval.ro>
Tue, 19 Nov 2013 21:06:47 +0000 (23:06 +0200)
13 files changed:
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
gruntmaster-genpage [new file with mode: 0755]
lib/Gruntmaster/Page.pm [new file with mode: 0644]
lib/Gruntmaster/Page/Index.pm [new file with mode: 0644]
lib/Gruntmaster/Page/Log.pm [new file with mode: 0644]
lib/Gruntmaster/Page/Log/Entry.pm [new file with mode: 0644]
lib/Gruntmaster/Page/Pb.pm [new file with mode: 0644]
lib/Gruntmaster/Page/Pb/Entry.pm [new file with mode: 0644]
lib/Gruntmaster/Page/Submit.pm [new file with mode: 0644]
t/Gruntmaster-Page.t [new file with mode: 0644]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..d1033b4
--- /dev/null
+++ b/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension Gruntmaster::Page.
+
+0.001  Thu Oct 24 14:32:13 2013
+       - original version; created by h2xs 1.23 with options
+               -AX -b 5.14.0 -v 0.001 Gruntmaster::Page
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..1464eb1
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,14 @@
+
+Changes
+gruntmaster-genpage
+lib/Gruntmaster/Page/Index.pm
+lib/Gruntmaster/Page/Log/Entry.pm
+lib/Gruntmaster/Page/Log.pm
+lib/Gruntmaster/Page/Pb/Entry.pm
+lib/Gruntmaster/Page/Pb.pm
+lib/Gruntmaster/Page.pm
+lib/Gruntmaster/Page/Submit.pm
+Makefile.PL
+MANIFEST
+README
+t/Gruntmaster-Page.t
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..ea97420
--- /dev/null
@@ -0,0 +1,13 @@
+use 5.014000;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+    NAME              => 'Gruntmaster::Page',
+    VERSION_FROM      => 'lib/Gruntmaster/Page.pm', # finds $VERSION
+    PREREQ_PM         => {}, # e.g., Module::Name => 1.1
+    ($] >= 5.005 ?     ## Add these new keywords supported since 5.005
+      (ABSTRACT_FROM  => 'lib/Gruntmaster/Page.pm', # retrieve abstract from module
+       AUTHOR         => 'Marius Gavrilescu <marius@ieval.ro>') : ()),
+       EXE_FILES => [ qw/gruntmaster-genpage/ ]
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..bbfc1d9
--- /dev/null
+++ b/README
@@ -0,0 +1,40 @@
+Gruntmaster-Page version 0.001
+==============================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+  blah blah blah
+
+COPYRIGHT AND LICENCE
+
+Put the correct copyright and licence information here.
+
+Copyright (C) 2013 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.18.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
diff --git a/gruntmaster-genpage b/gruntmaster-genpage
new file mode 100755 (executable)
index 0000000..bac0eb4
--- /dev/null
@@ -0,0 +1,6 @@
+#!/usr/bin/perl -w
+use v5.14;
+
+use Gruntmaster::Page qw/generate/;
+
+generate $_ for @ARGV;
diff --git a/lib/Gruntmaster/Page.pm b/lib/Gruntmaster/Page.pm
new file mode 100644 (file)
index 0000000..5c63f64
--- /dev/null
@@ -0,0 +1,147 @@
+package Gruntmaster::Page;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate header footer/;
+
+use File::Basename qw/fileparse/;
+use File::Slurp qw/write_file/;
+use IO::Compress::Gzip qw/gzip/;
+
+our $VERSION = '0.001';
+our @generators;
+
+use constant LANGUAGES => [ 'en' ];
+use constant CONTENT_TYPES => {
+  html => 'text/html; charset=UTF-8',
+  txt => 'text/plain; charset=UTF-8',
+};
+
+my %header_templates = (
+  en => <<'HTML',
+<!DOCTYPE html>
+<title>TITLE_GOES_HERE</title>
+<link rel="stylesheet" href="/gm.css">
+<script src="/jquery-2.0.3.min.js"></script>
+<script src="/view.js"></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="/">Home</a><li><a href="/log/">View job log</a><li><a href="/submit.var">Submit job</a><li><a href="/pb/">Problem list</a></ul></nav>
+
+HTML
+);
+
+my %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 header{
+  my ($language, $title) = @_;
+  $header_templates{$language} =~ s/TITLE_GOES_HERE/$title/ger;
+}
+
+sub footer{
+  $footer_templates{$_[0]};
+}
+
+sub declaregen{
+  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];
+}
+
+declaregen Index => qr'^index$';
+declaregen Log => qr'^log/index$';
+declaregen 'Log::Entry' => qr'^log/.*/index$';
+declaregen Submit => qr'^submit$';
+declaregen Pb => qr'^pb/index$';
+declaregen 'Pb::Entry' => qr'^pb/.*/index$';
+
+sub generate{
+  my ($path) = @_;
+  my ($path_noext, $ext) = $path =~ m/^(.*)\.(.*)$/;
+  my $basename = fileparse $path_noext;
+
+  open my $typemap, ">$path_noext.var";
+  say $typemap "URI: $basename\n";
+  for my $gen(@generators) {
+       my ($regex, $generator) = @$gen;
+       next unless $path_noext =~ $regex;
+       for my $lang (@{LANGUAGES()}) {
+         my $page = $generator->($path, $lang);
+         write_file "$path_noext.$lang.$ext", $page;
+         say $typemap "URI: $basename.$lang.$ext\nContent-Language: $lang\nContent-Type: " . CONTENT_TYPES->{$ext} . "\n";
+         gzip \$page => "$path_noext.$lang.gz.$ext", Minimal => 1;
+         say $typemap "URI: $basename.$lang.gz.$ext\nContent-Language: $lang\nContent-Encoding: gzip\nContent-Type: " . CONTENT_TYPES->{$ext} . "\n";
+       }
+  }
+  close $typemap;
+}
+
+1;
+__END__
+# Below is stub documentation for your module. You'd better edit it!
+
+=head1 NAME
+
+Gruntmaster::Page - Perl extension for blah blah blah
+
+=head1 SYNOPSIS
+
+  use Gruntmaster::Page;
+  blah blah blah
+
+=head1 DESCRIPTION
+
+Stub documentation for Gruntmaster::Page, created by h2xs. It looks like the
+author of the extension was negligent enough to leave the stub
+unedited.
+
+Blah blah blah.
+
+=head2 EXPORT
+
+None by default.
+
+
+
+=head1 SEE ALSO
+
+Mention other useful documentation such as the documentation of
+related modules or operating system documentation (such as man pages
+in UNIX), or any relevant external documentation such as RFCs or
+standards.
+
+If you have a mailing list set up for your module, mention it here.
+
+If you have a web site set up for your module, mention it here.
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@E<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2013 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.18.1 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/lib/Gruntmaster/Page/Index.pm b/lib/Gruntmaster/Page/Index.pm
new file mode 100644 (file)
index 0000000..5cf282d
--- /dev/null
@@ -0,0 +1,33 @@
+package Gruntmaster::Page::Index;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate/;
+our $VERSION = '0.001';
+
+use constant TITLE => 'Gruntmaster 6000';
+
+use Fcntl qw/:flock/;
+use HTML::Template::Compiled;
+use IO::File;
+use Gruntmaster::Page qw/header footer/;
+
+my %templates = (
+  en => <<'HTML',
+HTML
+);
+
+$templates{$_}  = header($_, TITLE) . $templates{$_} for keys %templates;
+$templates{$_} .= footer $_ for keys %templates;
+
+sub generate{
+  my $template = $templates{$_[1]};
+  my $htc = HTML::Template::Compiled->new(scalarref => \$template);
+  IO::File->new('>meta.yml')->close unless -f 'meta.yml';
+  flock my $metafh = IO::File->new('<meta.yml'), LOCK_SH;
+  $htc->output
+}
+
+1
diff --git a/lib/Gruntmaster/Page/Log.pm b/lib/Gruntmaster/Page/Log.pm
new file mode 100644 (file)
index 0000000..b12d779
--- /dev/null
@@ -0,0 +1,60 @@
+package Gruntmaster::Page::Log;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate/;
+our $VERSION = '0.001';
+
+use constant TITLE => 'Job log';
+
+use Fcntl qw/:flock/;
+use HTML::Template::Compiled;
+use IO::File;
+use POSIX qw/strftime/;
+use YAML::Any qw/LoadFile/;
+use Gruntmaster::Page qw/header footer/;
+
+my %templates = (
+  en => <<'HTML',
+<table border>
+<thead>
+<tr><th>ID<th>Problem<th>Date<th>Size<th>User<th>Result
+<tbody>
+<tmpl_loop log><tr><td><a href="<tmpl_var id>"><tmpl_var id></a>
+<td><a href="/pb/<tmpl_var problem>"><tmpl_var name></a>
+<td><tmpl_var date>
+<td><a href="<tmpl_var id>/in/<tmpl_var filename>"<tmpl_if private> data-private</tmpl_if>><tmpl_var size></a>
+<td><tmpl_var user><td class="r<tmpl_var result>"><tmpl_var result_text>
+</tmpl_loop>
+</table>
+HTML
+);
+
+$templates{$_}  = header($_, TITLE) . $templates{$_} for keys %templates;
+$templates{$_} .= footer $_ for keys %templates;
+
+sub generate{
+  my $template = $templates{$_[1]};
+  my $htc = HTML::Template::Compiled->new(scalarref => \$template);
+  IO::File->new('>log/meta.yml')->close unless -f 'log/meta.yml';
+  flock my $metafh = IO::File->new('<log/meta.yml'), LOCK_SH;
+  my $meta = LoadFile 'log/meta.yml';
+  my @log = sort { $b->{id} <=> $a->{id} } map {
+       my $meta = LoadFile "log/$_/meta.yml";
+       +{ id => $_,
+          date => strftime ('%c' => localtime $meta->{date}),
+          user => $meta->{user},
+          result => $meta->{result},
+          name => $meta->{name},
+          problem => $meta->{problem},
+          filename => $meta->{files}{prog}{name},
+          (defined $meta->{private} ? (private => $meta->{private}) : ()),
+          size => sprintf ("%.2f KiB", (-s "log/$_/in/" . $meta->{files}{prog}{name}) / 1024),
+          result_text => $meta->{result_text}} } 1 .. $meta->{last};
+  $htc->param(log => \@log);
+  $htc->output
+}
+
+1
diff --git a/lib/Gruntmaster/Page/Log/Entry.pm b/lib/Gruntmaster/Page/Log/Entry.pm
new file mode 100644 (file)
index 0000000..08230bf
--- /dev/null
@@ -0,0 +1,53 @@
+package Gruntmaster::Page::Log::Entry;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate/;
+our $VERSION = '0.001';
+
+use constant TITLE => 'Job <tmpl_var id>';
+
+use Fcntl qw/:flock/;
+use HTML::Template::Compiled;
+use IO::File;
+use POSIX qw/strftime/;
+use YAML::Any qw/LoadFile/;
+use Gruntmaster::Page qw/header footer/;
+
+my %templates = (
+  en => <<'HTML',
+<table border>
+<thead>
+<tr><th>Test number<th>Result<th>Time
+<tbody>
+<tmpl_loop tests><tr><td><tmpl_var id><td class="r<tmpl_var result>"><tmpl_var result_text><td><tmpl_var time>
+</tmpl_loop>
+</table>
+HTML
+);
+
+$templates{$_}  = header($_, TITLE) . $templates{$_} for keys %templates;
+$templates{$_} .= footer $_ for keys %templates;
+
+sub generate{
+  my ($path, $lang) = @_;
+  $path = ($path =~ m,log/(.*)/index,)[0];
+  my $template = $templates{$lang};
+
+  my $htc = HTML::Template::Compiled->new(scalarref => \$template);
+  flock my $metafh = IO::File->new("<log/$path/meta.yml"), LOCK_SH;
+  my $meta = LoadFile "log/$path/meta.yml";
+
+  my @tests = map {
+       $_->{time} = sprintf "%.4fs", $_->{time};
+       $_
+  } @{$meta->{results}};
+
+  $htc->param(id => $path);
+  $htc->param(tests => \@tests);
+  $htc->output
+}
+
+1
diff --git a/lib/Gruntmaster/Page/Pb.pm b/lib/Gruntmaster/Page/Pb.pm
new file mode 100644 (file)
index 0000000..efe7d26
--- /dev/null
@@ -0,0 +1,43 @@
+package Gruntmaster::Page::Pb;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate/;
+our $VERSION = '0.001';
+
+use constant TITLE => 'Problems';
+
+use Fcntl qw/:flock/;
+use HTML::Template::Compiled;
+use IO::File;
+use POSIX qw/strftime/;
+use YAML::Any qw/LoadFile/;
+use Gruntmaster::Page qw/header footer/;
+
+my %templates = (
+  en => <<'HTML',
+<ul>
+<tmpl_loop problems><li><a href="<tmpl_var id>"><tmpl_var name></a>
+</tmpl_loop></ul>
+HTML
+);
+
+$templates{$_}  = header($_, TITLE) . $templates{$_} for keys %templates;
+$templates{$_} .= footer $_ for keys %templates;
+
+sub generate{
+  my $template = $templates{$_[1]};
+  my $htc = HTML::Template::Compiled->new(scalarref => \$template);
+  IO::File->new('>pb/meta.yml')->close unless -f 'pb/meta.yml';
+  flock my $metafh = IO::File->new('<pb/meta.yml'), LOCK_SH;
+  my @problems = sort { $b->{name} cmp $a->{name} } map {
+       my $meta = LoadFile $_;
+       my $id = (m,^pb/(.*)/meta.yml$,)[0];
+       +{ id => $id, name => $meta->{name} } } <pb/*/meta.yml>;
+  $htc->param(problems => \@problems);
+  $htc->output
+}
+
+1
diff --git a/lib/Gruntmaster/Page/Pb/Entry.pm b/lib/Gruntmaster/Page/Pb/Entry.pm
new file mode 100644 (file)
index 0000000..0f91c01
--- /dev/null
@@ -0,0 +1,57 @@
+package Gruntmaster::Page::Pb::Entry;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate/;
+our $VERSION = '0.001';
+
+use Fcntl qw/:flock/;
+use HTML::Template::Compiled;
+use IO::File;
+use POSIX qw/strftime/;
+use YAML::Any qw/LoadFile/;
+use File::Basename qw/fileparse/;
+use File::Slurp qw/slurp/;
+use Gruntmaster::Page qw/header footer/;
+
+use constant FORMATS => [qw/CPP/];
+use constant TITLE => '<tmpl_var name>';
+
+my %templates = (
+  en => <<'HTML',
+<tmpl_var statement>
+
+<h1>Submit solution</h1>
+<form action="https://gm.ieval.ro/action/submit" method="POST" enctype="multipart/form-data">
+<input type="hidden" name="problem" value="<tmpl_var id>">
+<label>File: <input name="prog" required type="file"></label>
+
+<label>File format: <select name="prog_format" required>
+<tmpl_loop formats><option value="<tmpl_var _>"><tmpl_var _></option>
+</tmpl_loop></select></label>
+
+<input type="submit" value="Submit job">
+HTML
+);
+
+$templates{$_}  = header($_, TITLE) . $templates{$_} for keys %templates;
+$templates{$_} .= footer $_ for keys %templates;
+
+sub generate{
+  my ($path, $lang) = @_;
+  $path = ($path =~ m,pb/(.*)/index,)[0];
+  my $template = $templates{$_[1]};
+  my $htc = HTML::Template::Compiled->new(scalarref => \$template);
+  flock my $metafh = IO::File->new("<pb/$path/meta.yml"), LOCK_SH;
+  my $meta = LoadFile "pb/$path/meta.yml";
+
+  $htc->param(formats => FORMATS);
+  $htc->param(id => $path);
+  $htc->param(name => $meta->{name});
+  $htc->param(statement => scalar slurp "pb/$path/statement.$lang");
+  $htc->output
+}
+
+1
diff --git a/lib/Gruntmaster/Page/Submit.pm b/lib/Gruntmaster/Page/Submit.pm
new file mode 100644 (file)
index 0000000..e6f44de
--- /dev/null
@@ -0,0 +1,56 @@
+package Gruntmaster::Page::Submit;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/generate/;
+our $VERSION = '0.001';
+
+use constant FORMATS => [qw/CPP/];
+use constant TITLE => 'Submit job';
+
+use Fcntl qw/:flock/;
+use HTML::Template::Compiled;
+use IO::File;
+use YAML::Any qw/LoadFile/;
+use Gruntmaster::Page qw/header footer/;
+
+my %templates = (
+  en => <<'HTML',
+<form action="https://gm.ieval.ro/action/submit" method="POST" enctype="multipart/form-data">
+<label>Problem:<br>
+<select name="problem" required>
+<tmpl_loop problems><option value="<tmpl_var id>"><tmpl_var name></option>
+</tmpl_loop></select></label><p>
+
+<label>File:<br>
+<input name="prog" required type="file"></label><p>
+
+<label>File format:<br>
+<select name="prog_format" required>
+<tmpl_loop formats><option value="<tmpl_var _>"><tmpl_var _></option>
+</tmpl_loop></select></label><p>
+
+<input type="submit" value="Submit job">
+HTML
+);
+
+$templates{$_}  = header($_, TITLE) . $templates{$_} for keys %templates;
+$templates{$_} .= footer $_ for keys %templates;
+
+sub generate{
+  my $template = $templates{$_[1]};
+  my $htc = HTML::Template::Compiled->new(scalarref => \$template);
+  IO::File->new('>meta.yml')->close unless -f 'meta.yml';
+  flock my $metafh = IO::File->new('<meta.yml'), LOCK_SH;
+  my @problems = map {
+       my $meta = LoadFile $_;
+       my $id = (m,^pb/(.*)/meta.yml$,)[0];
+       +{ id => $id, name => $meta->{name} } } <pb/*/meta.yml>;
+  $htc->param(problems => \@problems);
+  $htc->param(formats => FORMATS);
+  $htc->output
+}
+
+1
diff --git a/t/Gruntmaster-Page.t b/t/Gruntmaster-Page.t
new file mode 100644 (file)
index 0000000..284698d
--- /dev/null
@@ -0,0 +1,18 @@
+# Before 'make install' is performed this script should be runnable with
+# 'make test'. After 'make install' it should work as 'perl Gruntmaster-Page.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+BEGIN { use_ok('Gruntmaster::Page') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
This page took 0.023594 seconds and 4 git commands to generate.