Initial commit
authorMarius Gavrilescu <marius@ieval.ro>
Tue, 19 Nov 2013 21:03:12 +0000 (23:03 +0200)
committerMarius Gavrilescu <marius@ieval.ro>
Tue, 19 Nov 2013 21:03:12 +0000 (23:03 +0200)
91 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]
gruntmasterd [new file with mode: 0755]
lib/Gruntmaster/Daemon.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Base.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Constants.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Format/CPP.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Generator/File.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Generator/Run.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Generator/Undef.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Judge/Absolute.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Judge/Points.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Runner/File.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Runner/Interactive.pm [new file with mode: 0644]
lib/Gruntmaster/Daemon/Runner/Verifier.pm [new file with mode: 0644]
log.conf [new file with mode: 0644]
selinux/gruntmasterd.te [new file with mode: 0644]
t/00-compile.t [new file with mode: 0644]
t/01-jobs.t [new file with mode: 0644]
t/problems/aminusb/1.in [new file with mode: 0644]
t/problems/aminusb/2.in [new file with mode: 0644]
t/problems/aminusb/3.in [new file with mode: 0644]
t/problems/aminusb/4.in [new file with mode: 0644]
t/problems/aminusb/5.in [new file with mode: 0644]
t/problems/aminusb/meta.yml [new file with mode: 0644]
t/problems/aminusb/tests/ac/meta.yml [new file with mode: 0644]
t/problems/aminusb/tests/ac/prog.cpp [new file with mode: 0644]
t/problems/aminusb/tests/wa/meta.yml [new file with mode: 0644]
t/problems/aminusb/tests/wa/prog.cpp [new file with mode: 0644]
t/problems/aminusb/ver.cpp [new file with mode: 0644]
t/problems/aplusb/1.in [new file with mode: 0644]
t/problems/aplusb/1.ok [new file with mode: 0644]
t/problems/aplusb/2.in [new file with mode: 0644]
t/problems/aplusb/2.ok [new file with mode: 0644]
t/problems/aplusb/3.in [new file with mode: 0644]
t/problems/aplusb/3.ok [new file with mode: 0644]
t/problems/aplusb/4.in [new file with mode: 0644]
t/problems/aplusb/4.ok [new file with mode: 0644]
t/problems/aplusb/5.in [new file with mode: 0644]
t/problems/aplusb/5.ok [new file with mode: 0644]
t/problems/aplusb/6.in [new file with mode: 0644]
t/problems/aplusb/6.ok [new file with mode: 0644]
t/problems/aplusb/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/40/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/40/prog.cpp [new file with mode: 0644]
t/problems/aplusb/tests/ac/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/ac/prog.cpp [new file with mode: 0644]
t/problems/aplusb/tests/compile-error/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/compile-error/prog.cpp [new file with mode: 0644]
t/problems/aplusb/tests/mle/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/mle/prog.cpp [new file with mode: 0644]
t/problems/aplusb/tests/nzx/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/nzx/prog.cpp [new file with mode: 0644]
t/problems/aplusb/tests/ole/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/ole/prog.cpp [new file with mode: 0644]
t/problems/aplusb/tests/tle/meta.yml [new file with mode: 0644]
t/problems/aplusb/tests/tle/prog.cpp [new file with mode: 0644]
t/problems/double/1.in [new file with mode: 0644]
t/problems/double/1.ok [new file with mode: 0644]
t/problems/double/10.in [new file with mode: 0644]
t/problems/double/10.ok [new file with mode: 0644]
t/problems/double/2.in [new file with mode: 0644]
t/problems/double/2.ok [new file with mode: 0644]
t/problems/double/3.in [new file with mode: 0644]
t/problems/double/3.ok [new file with mode: 0644]
t/problems/double/4.in [new file with mode: 0644]
t/problems/double/4.ok [new file with mode: 0644]
t/problems/double/5.in [new file with mode: 0644]
t/problems/double/5.ok [new file with mode: 0644]
t/problems/double/6.in [new file with mode: 0644]
t/problems/double/6.ok [new file with mode: 0644]
t/problems/double/7.in [new file with mode: 0644]
t/problems/double/7.ok [new file with mode: 0644]
t/problems/double/8.in [new file with mode: 0644]
t/problems/double/8.ok [new file with mode: 0644]
t/problems/double/9.in [new file with mode: 0644]
t/problems/double/9.ok [new file with mode: 0644]
t/problems/double/meta.yml [new file with mode: 0644]
t/problems/double/tests/wa/meta.yml [new file with mode: 0644]
t/problems/double/tests/wa/prog.cpp [new file with mode: 0644]
t/problems/increment/int.cpp [new file with mode: 0644]
t/problems/increment/meta.yml [new file with mode: 0644]
t/problems/increment/tests/ac/meta.yml [new file with mode: 0644]
t/problems/increment/tests/ac/prog.cpp [new file with mode: 0644]
t/problems/square/gen.cpp [new file with mode: 0644]
t/problems/square/meta.yml [new file with mode: 0644]
t/problems/square/tests/ac/meta.yml [new file with mode: 0644]
t/problems/square/tests/ac/prog.cpp [new file with mode: 0644]
t/problems/square/ver.cpp [new file with mode: 0644]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..b581aa3
--- /dev/null
+++ b/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension Gruntmaster::Daemon.
+
+0.001  Tue Oct 15 00:15:35 2013
+       - original version; created by h2xs 1.23 with options
+               -AX -v 0.001 -b 5.14.0 --skip-exporter Gruntmaster::Daemon
+
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..35714c3
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,91 @@
+Changes
+gruntmasterd
+lib/Gruntmaster/Daemon/Base.pm
+lib/Gruntmaster/Daemon/Constants.pm
+lib/Gruntmaster/Daemon/Format/CPP.pm
+lib/Gruntmaster/Daemon/Generator/File.pm
+lib/Gruntmaster/Daemon/Generator/Run.pm
+lib/Gruntmaster/Daemon/Generator/Undef.pm
+lib/Gruntmaster/Daemon/Judge/Absolute.pm
+lib/Gruntmaster/Daemon/Judge/Points.pm
+lib/Gruntmaster/Daemon.pm
+lib/Gruntmaster/Daemon/Runner/File.pm
+lib/Gruntmaster/Daemon/Runner/Interactive.pm
+lib/Gruntmaster/Daemon/Runner/Verifier.pm
+log.conf
+Makefile.PL
+MANIFEST
+README
+selinux/gruntmasterd.te
+t/00-compile.t
+t/01-jobs.t
+t/problems/aminusb/1.in
+t/problems/aminusb/2.in
+t/problems/aminusb/3.in
+t/problems/aminusb/4.in
+t/problems/aminusb/5.in
+t/problems/aminusb/meta.yml
+t/problems/aminusb/tests/ac/meta.yml
+t/problems/aminusb/tests/ac/prog.cpp
+t/problems/aminusb/tests/wa/meta.yml
+t/problems/aminusb/tests/wa/prog.cpp
+t/problems/aminusb/ver.cpp
+t/problems/aplusb/1.in
+t/problems/aplusb/1.ok
+t/problems/aplusb/2.in
+t/problems/aplusb/2.ok
+t/problems/aplusb/3.in
+t/problems/aplusb/3.ok
+t/problems/aplusb/4.in
+t/problems/aplusb/4.ok
+t/problems/aplusb/5.in
+t/problems/aplusb/5.ok
+t/problems/aplusb/6.in
+t/problems/aplusb/6.ok
+t/problems/aplusb/meta.yml
+t/problems/aplusb/tests/40/meta.yml
+t/problems/aplusb/tests/40/prog.cpp
+t/problems/aplusb/tests/ac/meta.yml
+t/problems/aplusb/tests/ac/prog.cpp
+t/problems/aplusb/tests/compile-error/meta.yml
+t/problems/aplusb/tests/compile-error/prog.cpp
+t/problems/aplusb/tests/mle/meta.yml
+t/problems/aplusb/tests/mle/prog.cpp
+t/problems/aplusb/tests/nzx/meta.yml
+t/problems/aplusb/tests/nzx/prog.cpp
+t/problems/aplusb/tests/ole/meta.yml
+t/problems/aplusb/tests/ole/prog.cpp
+t/problems/aplusb/tests/tle/meta.yml
+t/problems/aplusb/tests/tle/prog.cpp
+t/problems/double/10.in
+t/problems/double/10.ok
+t/problems/double/1.in
+t/problems/double/1.ok
+t/problems/double/2.in
+t/problems/double/2.ok
+t/problems/double/3.in
+t/problems/double/3.ok
+t/problems/double/4.in
+t/problems/double/4.ok
+t/problems/double/5.in
+t/problems/double/5.ok
+t/problems/double/6.in
+t/problems/double/6.ok
+t/problems/double/7.in
+t/problems/double/7.ok
+t/problems/double/8.in
+t/problems/double/8.ok
+t/problems/double/9.in
+t/problems/double/9.ok
+t/problems/double/meta.yml
+t/problems/double/tests/wa/meta.yml
+t/problems/double/tests/wa/prog.cpp
+t/problems/increment/int.cpp
+t/problems/increment/meta.yml
+t/problems/increment/tests/ac/meta.yml
+t/problems/increment/tests/ac/prog.cpp
+t/problems/square/gen.cpp
+t/problems/square/meta.yml
+t/problems/square/tests/ac/meta.yml
+t/problems/square/tests/ac/prog.cpp
+t/problems/square/ver.cpp
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..49a41f1
--- /dev/null
@@ -0,0 +1,48 @@
+use 5.014000;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+  NAME              => 'Gruntmaster::Daemon',
+  VERSION_FROM      => 'lib/Gruntmaster/Daemon.pm',
+  EXE_FILES         => [ 'gruntmasterd' ],
+  ABSTRACT_FROM     => 'lib/Gruntmaster/Daemon.pm',
+  AUTHOR            => 'Marius Gavrilescu <marius@ieval.ro>',
+  MIN_PERL_VERSION  => '5.14.0',
+  LICENSE           => 'perl',
+  BUILD_REQUIRES    => {
+       qw/Cwd 0
+          File::Copy 0
+          File::Copy::Recursive 0
+          File::Path 0
+          File::Temp 0
+          List::Util 0
+          Log::Log4perl 0
+          Test::More 0
+          YAML::Any 0/,
+  },
+  SIGN              => 1,
+  PREREQ_PM         => {
+       qw/Exporter 0
+          Fcntl 0
+          File::Basename 0
+          File::Copy 0
+          File::Spec::Functions 0
+          IO::File 0
+          IPC::Open3 0
+          List::Util 0
+          POSIX 0
+          Time::HiRes 0
+
+          BSD::Resource 0
+          File::Slurp 0
+          IPC::Signal 0
+          Linux::Inotify2 0
+          List::MoreUtils 0
+          Log::Log4perl 0
+          Try::Tiny 0
+          YAML::Any 0/,
+  },
+  META_MERGE        => {
+       dynamic_config => 0,
+  }
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1b0e7ab
--- /dev/null
+++ b/README
@@ -0,0 +1,40 @@
+Gruntmaster-Daemon 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/gruntmasterd b/gruntmasterd
new file mode 100755 (executable)
index 0000000..100a78e
--- /dev/null
@@ -0,0 +1,5 @@
+#!/usr/bin/perl -w
+use v5.14;
+use Gruntmaster::Daemon;
+
+Gruntmaster::Daemon->run;
diff --git a/lib/Gruntmaster/Daemon.pm b/lib/Gruntmaster/Daemon.pm
new file mode 100644 (file)
index 0000000..f0e66f2
--- /dev/null
@@ -0,0 +1,191 @@
+package Gruntmaster::Daemon;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.001';
+
+use Gruntmaster::Daemon::Constants qw/ERR/;
+use Gruntmaster::Daemon::Base qw/watch/;
+use Gruntmaster::Page qw/generate/;
+
+use Fcntl qw/:flock/;
+use File::Copy qw/cp/;
+use IO::File;
+use Time::HiRes qw/time/;
+use Try::Tiny;
+use YAML::Any qw/LoadFile DumpFile/;
+use Log::Log4perl qw/get_logger/;
+
+##################################################
+
+sub safe_can_nodie {
+  my ($type, $sub, $name) = @_;
+
+  return unless $name =~ /^\w+$/;
+  no strict 'refs';
+  my $pkg = __PACKAGE__ . "::${type}::${name}";
+  eval "require $pkg" or get_logger->warn("Error while requiring $pkg: $@");
+  $pkg->can($sub);
+}
+
+sub safe_can {
+  my ($type, $sub, $name) = @_;
+
+  safe_can_nodie @_ or get_logger->logdie("No such \l$type: '$name'");
+}
+
+sub prepare_files{
+  my ($dir, $meta) = @_;
+
+  for my $file (values $meta->{files}) {
+       my ($format, $name) = @{$file}{qw/format name/};
+
+       my $prepare = safe_can Format => prepare => $format;
+       $file->{run} = safe_can Format => run => $format;
+       die "No such file: '$name'" unless -e $name;
+       $prepare->($name);
+  }
+}
+
+sub process{
+  my $dir = $_[0];
+
+  chdir $dir;
+  mkdir "in";
+  for (<*>) {
+       cp $_, "in" unless $_ eq 'in' || $_ eq 'pidfile';
+  }
+
+  my @results;
+  my @full_results = ();
+  my $meta = {};
+  try {
+       $meta = LoadFile "meta.yml";
+       if (exists $meta->{problem}) {
+         my $problem = $meta->{problem};
+         die "No such problem: $problem" unless -d "../../pb/$problem";
+         for (<../../pb/$problem/*>) {
+               cp $_, '.' unless $_ eq "../../pb/$problem/meta.yml"
+         }
+
+         my $pbmeta = LoadFile "../../pb/$problem/meta.yml";
+         $meta = {%$meta, %$pbmeta};
+       }
+
+       my ($files, $generator, $runner, $judge, $testcnt) = map { $meta->{$_} or die "Required parameter missing: $_"} qw/files generator runner judge testcnt/;
+
+       $generator = safe_can Generator => generate => $generator;
+       $runner = safe_can Runner => run => $runner;
+       $judge = safe_can Judge => judge => $judge;
+
+       prepare_files $dir, $meta;
+       for my $test (1 .. $testcnt) {
+         my $start_time = time;
+         my $result;
+         try {
+               $generator->($test, $meta);
+               $result = $runner->($test, $meta);
+         } catch {
+               $result = $_;
+               unless (ref $result) {
+                 chomp $result;
+                 $result = [ERR, $result];
+               }
+         };
+
+         if (ref $result) {
+               get_logger->trace("Test $test result is " . $result->[1]);
+               push @full_results, {id => $test, result => $result->[0], result_text => $result->[1], time => time - $start_time}
+         } else {
+               get_logger->trace("Test $test result is $result");
+               push @full_results, {id => $test, result => 0, result_text => $result, time => time - $start_time}
+         }
+         push @results, $result;
+         last if $meta->{judge} eq 'Absolute' && ref $result
+       }
+
+       my %results = $judge->(@results);
+       $meta->{$_} = $results{$_} for keys %results;
+  } catch {
+       s,(.*) at .*,$1,;
+       chomp;
+       $meta->{result} = -1;
+       $meta->{result_text} = $_;
+  };
+
+  # Clean up
+  get_logger->info("Job result: " . $meta->{result_text});
+  delete $meta->{files}{$_}{run} for keys $meta->{files};
+  $meta->{date} = time;
+  $meta->{results} = \@full_results if scalar @full_results;
+  DumpFile "meta.yml", $meta;
+  for (<*>) {
+       unlink $_ unless $_ eq 'in' || $_ eq 'meta.yml';
+  }
+  chdir '../..';
+  mkdir 'log' unless -d 'log';
+  IO::File->new('>log/meta.yml')->close unless -f 'log/meta.yml';
+  flock my $logmetafh = IO::File->new('<log/meta.yml'), LOCK_EX;
+  my $logmeta = LoadFile 'log/meta.yml';
+  $logmeta->{last}++;
+  rename $dir, 'log/' . $logmeta->{last};
+  generate 'log/' . $logmeta->{last} . '/index.htm';
+  DumpFile 'log/meta.yml', $logmeta;
+  undef $logmetafh;
+  generate 'log/index.html'
+}
+
+sub run{
+  Log::Log4perl->init('log.conf');
+  watch 'jobs', \&process;
+}
+
+1;
+__END__
+# Below is stub documentation for your module. You'd better edit it!
+
+=head1 NAME
+
+Gruntmaster::Daemon - Perl extension for blah blah blah
+
+=head1 SYNOPSIS
+
+  use Gruntmaster::Daemon;
+  blah blah blah
+
+=head1 DESCRIPTION
+
+Stub documentation for Gruntmaster::Daemon, created by h2xs. It looks like the
+author of the extension was negligent enough to leave the stub
+unedited.
+
+Blah blah blah.
+
+
+=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/Daemon/Base.pm b/lib/Gruntmaster/Daemon/Base.pm
new file mode 100644 (file)
index 0000000..b7db789
--- /dev/null
@@ -0,0 +1,42 @@
+package Gruntmaster::Daemon::Base;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+our @EXPORT_OK = qw/watch/;
+our $VERSION = '0.001';
+
+use Fcntl qw/O_WRONLY O_EXCL O_CREAT/;
+use Linux::Inotify2;
+use Log::Log4perl qw/get_logger/;
+
+##################################################
+
+sub process{
+  my ($name, $dir, $cb) = @_;
+  my $logger = get_logger;
+  $logger->debug("Taking job $name...");
+  if (sysopen my $file, "$dir/$name/pidfile", O_WRONLY | O_EXCL | O_CREAT){
+       $logger->debug("Successfully taken job $name, executing callback");
+       $cb->("$dir/$name");
+  } else {
+       $logger->debug("Job $name already taken");
+  }
+}
+
+sub watch{
+  my ($dir, $cb) = @_;
+  for (<$dir/*>) {
+       s,$dir/,,;
+       process $_, $dir, $cb;
+  }
+
+  my $logger = Log::Log4perl->get_logger(__PACKAGE__);
+  my $inotify = Linux::Inotify2->new or $logger->logdie("Unable to create Linux::Inotify2 object: $!");
+  $inotify->watch($dir, IN_MOVED_TO, sub { process $_[0]->name, $dir, $cb }) or $logger->logdie("Error watching $dir: $!");
+  1 while $inotify->poll;
+  $logger->logdie("Inotify polling stopped: $!");
+}
+
+1
diff --git a/lib/Gruntmaster/Daemon/Constants.pm b/lib/Gruntmaster/Daemon/Constants.pm
new file mode 100644 (file)
index 0000000..189aabe
--- /dev/null
@@ -0,0 +1,26 @@
+package Gruntmaster::Daemon::Constants;
+
+use 5.014000;
+use strict;
+use warnings;
+use parent qw/Exporter/;
+
+our $VERSION = '0.001';
+
+use constant +{
+  # Accepted
+  AC => 0,
+
+  # Internal server error
+  ERR => -1,
+
+  # All other errors
+  WA => 1,
+  NZX => 2,
+  TLE => 3,
+  OLE => 4,
+  DIED => 5,
+  REJ => 10,
+};
+
+our @EXPORT_OK = qw/AC ERR WA NZX TLE OLE DIED REJ/;
diff --git a/lib/Gruntmaster/Daemon/Format/CPP.pm b/lib/Gruntmaster/Daemon/Format/CPP.pm
new file mode 100644 (file)
index 0000000..707af32
--- /dev/null
@@ -0,0 +1,76 @@
+package Gruntmaster::Daemon::Format::CPP;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use BSD::Resource qw/setrlimit RLIMIT_AS RLIMIT_FSIZE/;
+use POSIX qw//;
+use File::Basename qw/fileparse/;
+use Gruntmaster::Daemon::Constants qw/TLE OLE DIED NZX/;
+use Log::Log4perl qw/get_logger/;
+use Time::HiRes qw/alarm/;
+use List::MoreUtils qw/natatime/;
+use IPC::Signal qw/sig_name sig_num/;
+use IPC::Open3 qw/open3/;
+use File::Spec::Functions qw/devnull/;
+use Fcntl qw/F_GETFD F_SETFD FD_CLOEXEC/;
+
+our $VERSION = '0.001';
+
+##################################################
+
+sub prepare{
+  my $name = $_[0];
+  my $basename = fileparse $name, qr/\.[^.]*/;
+  get_logger->trace("Preparing file $name...");
+
+  open my $devnull, devnull;
+  open my $errors, '>compile-error';
+  my $ret = open3 $devnull, $errors, $errors, 'g++', '-o', $basename, $name;
+  local $SIG{ALRM} = sub {kill KILL => $ret};
+  alarm 5;
+  wait;
+  close $devnull;
+  close $errors;
+  die 'Compile error' if $?
+}
+
+sub run{
+  my ($name, %args) = @_;
+  my $basename = fileparse $name, qr/\.[^.]*/;
+  my $ret = fork // die 'Cannot fork';
+  if ($ret) {
+       my $tle;
+       local $SIG{ALRM} = sub { kill KILL => $ret; $tle = 1};
+       alarm $args{timeout} if exists $args{timeout};
+       wait;
+       alarm 0;
+       my $sig = $? & 127;
+       my $signame = sig_name $sig;
+       die [TLE, "Time Limit Exceeded"] if $tle;
+       die [OLE, 'Output Limit Exceeded'] if $sig && $signame eq 'XFSZ';
+       die [DIED, "Crash (SIG$signame)"] if $sig;
+       die [NZX, "Non-zero exit status: " . ($? >> 8)] if $?;
+  } else {
+       $^F = 50;
+       POSIX::close $_ for 0, 1, 3 .. $^F;
+       my @fds = exists $args{fds} ? @{$args{fds}} : ();
+       get_logger->trace("Running $basename with fds ". join ' ', @fds);
+       my $it = natatime 2, @fds;
+       while (my ($fd, $file) = $it->()) {
+         open my $fh, $file or die $!;
+         my $oldfd = fileno $fh;
+         if ($oldfd != $fd) {
+               POSIX::dup2 $oldfd, $fd or die $!;
+               POSIX::close $oldfd or die $!;
+         }
+       }
+#      POSIX::close 2;
+       setrlimit RLIMIT_AS, $args{mlimit}, $args{mlimit} if exists $args{mlimit};
+       setrlimit RLIMIT_FSIZE, $args{olimit}, $args{olimit} if exists $args{olimit};
+       exec "./$basename", exists $args{args} ? @{$args{args}} : ();
+  }
+}
+
+1
diff --git a/lib/Gruntmaster/Daemon/Generator/File.pm b/lib/Gruntmaster/Daemon/Generator/File.pm
new file mode 100644 (file)
index 0000000..1c37a8d
--- /dev/null
@@ -0,0 +1,20 @@
+package Gruntmaster::Daemon::Generator::File;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use File::Copy qw/cp/;
+use Log::Log4perl qw/get_logger/;
+
+our $VERSION = '0.001';
+
+##################################################
+
+sub generate{
+  my ($test, $meta) = @_;
+  get_logger->trace("Generating test $test ...");
+  cp "$test.in", 'input' or die "Cannot copy input for test $test: $!";
+}
+
+1
diff --git a/lib/Gruntmaster/Daemon/Generator/Run.pm b/lib/Gruntmaster/Daemon/Generator/Run.pm
new file mode 100644 (file)
index 0000000..8182729
--- /dev/null
@@ -0,0 +1,18 @@
+package Gruntmaster::Daemon::Generator::Run;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Log::Log4perl qw/get_logger/;
+
+our $VERSION = '0.001';
+
+##################################################
+
+sub generate{
+  my ($test, $meta) = @_;
+  my $gen = $meta->{files}{gen};
+  get_logger->trace("Generating test $test...");
+  $gen->{run}->($gen->{name}, args => [ $test ], fds => [qw/1 >input/]);
+}
diff --git a/lib/Gruntmaster/Daemon/Generator/Undef.pm b/lib/Gruntmaster/Daemon/Generator/Undef.pm
new file mode 100644 (file)
index 0000000..836a4be
--- /dev/null
@@ -0,0 +1,17 @@
+package Gruntmaster::Daemon::Generator::Undef;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Log::Log4perl qw/get_logger/;
+
+our $VERSION = '0.001';
+
+##################################################
+
+sub generate{
+  get_logger->trace("Pretending to generate test $_[0]...");
+}
+
+1
diff --git a/lib/Gruntmaster/Daemon/Judge/Absolute.pm b/lib/Gruntmaster/Daemon/Judge/Absolute.pm
new file mode 100644 (file)
index 0000000..010cf0b
--- /dev/null
@@ -0,0 +1,19 @@
+package Gruntmaster::Daemon::Judge::Absolute;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Gruntmaster::Daemon::Constants qw/AC/;
+
+our $VERSION = '0.001';
+
+##################################################
+
+sub judge{
+  $_ = pop;
+  ref $_ ? (result => $_->[0], result_text => $_->[1]) : (result => AC, result_text => 'Accepted')
+}
+
+1;
+__END__
diff --git a/lib/Gruntmaster/Daemon/Judge/Points.pm b/lib/Gruntmaster/Daemon/Judge/Points.pm
new file mode 100644 (file)
index 0000000..6d13ad0
--- /dev/null
@@ -0,0 +1,21 @@
+package Gruntmaster::Daemon::Judge::Points;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Gruntmaster::Daemon::Constants qw/AC REJ/;
+use List::Util qw/sum/;
+use Log::Log4perl qw/get_logger/;
+our $VERSION = '0.001';
+
+##################################################
+
+sub judge{
+  no warnings qw/numeric/;
+  get_logger->trace("Judging results: @_");
+  my $points = sum 0, grep { $_+0 eq "$_" } @_;
+  $points == 100 ? (result => AC, result_text => 'Accepted') : (result => REJ, result_text => "$points points", points => $points)
+}
+
+1
diff --git a/lib/Gruntmaster/Daemon/Runner/File.pm b/lib/Gruntmaster/Daemon/Runner/File.pm
new file mode 100644 (file)
index 0000000..57555ac
--- /dev/null
@@ -0,0 +1,31 @@
+package Gruntmaster::Daemon::Runner::File;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Gruntmaster::Daemon::Constants qw/WA/;
+use File::Slurp qw/slurp/;
+use Log::Log4perl qw/get_logger/;
+
+##################################################
+
+sub run{
+  my ($test, $meta) = @_;
+  get_logger->trace("Running on test $test...");
+  $meta->{files}{prog}{run}->($meta->{files}{prog}{name}, fds => [qw/0 input 1 >output/], map {defined $meta->{$_} ? ($_ => $meta->{$_}) : () } qw/timeout olimit mlimit/);
+  my $out = slurp 'output';
+  my $ok = slurp "$test.ok";
+
+  $out =~ s/^\s+//;
+  $ok  =~ s/^\s+//;
+  $out =~ s/\s+/ /;
+  $ok  =~ s/\s+/ /;
+  $out =~ s/\s+$//;
+  $ok  =~ s/\s+$//;
+
+  die [WA, "Wrong answer"] if $out ne $ok;
+  $meta->{tests}[$test - 1] // 0
+}
+
+1
diff --git a/lib/Gruntmaster/Daemon/Runner/Interactive.pm b/lib/Gruntmaster/Daemon/Runner/Interactive.pm
new file mode 100644 (file)
index 0000000..5edee04
--- /dev/null
@@ -0,0 +1,39 @@
+package Gruntmaster::Daemon::Runner::Interactive;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use File::Slurp qw/slurp/;
+use Gruntmaster::Daemon::Constants qw/WA/;
+use Log::Log4perl qw/get_logger/;
+use POSIX qw/mkfifo/;
+use Try::Tiny;
+
+##################################################
+
+sub run{
+  my ($test, $meta) = @_;
+  get_logger->trace("Running on test $test...");
+  my $ret = fork // get_logger->logdie("Fork failed: $!");
+
+  mkfifo 'fifo1', 0600 or die $! unless -e 'fifo1';
+  mkfifo 'fifo2', 0600 or die $! unless -e 'fifo2';
+  if ($ret) {
+       $meta->{files}{prog}{run}->($meta->{files}{prog}{name}, fds => [qw/0 fifo1 1 >fifo2/], map {defined $meta->{$_} ? ($_ => $meta->{$_}) : () } qw/timeout mlimit/);
+       wait;
+       die [WA, "Wrong Answer"] if $?;
+  } else {
+       try {
+         $meta->{files}{int}{run}->($meta->{files}{int}{name}, fds => [qw/1 >fifo1 0 fifo2 4 >result/]);
+       } catch {
+         exit 1;
+       };
+       exit
+  }
+
+  scalar slurp 'result'
+}
+
+1;
+__END__
diff --git a/lib/Gruntmaster/Daemon/Runner/Verifier.pm b/lib/Gruntmaster/Daemon/Runner/Verifier.pm
new file mode 100644 (file)
index 0000000..5a0b5ed
--- /dev/null
@@ -0,0 +1,27 @@
+package Gruntmaster::Daemon::Runner::Verifier;
+
+use 5.014000;
+use strict;
+use warnings;
+
+use Gruntmaster::Daemon::Constants qw/WA/;
+use File::Slurp qw/slurp/;
+use Log::Log4perl qw/get_logger/;
+use Try::Tiny;
+
+##################################################
+
+sub run{
+  my ($test, $meta) = @_;
+  get_logger->trace("Running on test $test...");
+  $meta->{files}{prog}{run}->($meta->{files}{prog}{name}, fds => [qw/0 input 1 >output/], map {defined $meta->{$_} ? ($_ => $meta->{$_}) : () } qw/timeout olimit mlimit/);
+
+  try {
+       $meta->{files}{ver}{run}->($meta->{files}{ver}{name}, fds => [qw/0 input 3 output 1 >result/]);
+  } catch {
+       die [WA, "Wrong answer"]
+  };
+  scalar slurp 'result';
+}
+
+1
diff --git a/log.conf b/log.conf
new file mode 100644 (file)
index 0000000..ab2c03a
--- /dev/null
+++ b/log.conf
@@ -0,0 +1,5 @@
+log4perl.category.Gruntmaster.Daemon = TRACE, stderr
+
+log4perl.appender.stderr                          = Log::Log4perl::Appender::Screen
+log4perl.appender.stderr.layout                   = Log::Log4perl::Layout::PatternLayout
+log4perl.appender.stderr.layout.ConversionPattern = [%d] [%F{1}:%M{1}:%L] [%p] %m%n
diff --git a/selinux/gruntmasterd.te b/selinux/gruntmasterd.te
new file mode 100644 (file)
index 0000000..bd0d99d
--- /dev/null
@@ -0,0 +1,24 @@
+policy_mdule(gruntmasterd, 1.0)
+
+type gruntmasterd_t;
+type gruntmasterd_exec_t;
+init_daemon_domain(gruntmasterd_t, gruntmasterd_exec_t);
+
+type gruntmasterd_log_t;
+logging_log_file(gruntmasterd_log_t);
+
+type gruntmaster_job_t;
+type gruntmaster_job_exec_t;
+init_daemon_domain(gruntmaster_job_t, gruntmaster_job_exec_t);
+
+allow gruntmasterd_t self : process fork;
+
+allow gruntmasterd_t gruntmasterd_job_t : dir ra_dir_perms;
+allow gruntmasterd_t gruntmasterd_job_t : file { create ra_file_perms };
+logging_log_filetrans(gruntmasterd_t, gruntmasterd_log_t, file)
+logging_search_logs(gruntmasterd_t)
+
+libs_use_ld_so(gruntmasterd_t)
+libs_use_ld_so(gruntmasterd_job_t)
+libs_use_shared_libs(gruntmasterd_t)
+libs_use_shared_libs(gruntmasterd_job_t)
\ No newline at end of file
diff --git a/t/00-compile.t b/t/00-compile.t
new file mode 100644 (file)
index 0000000..28dd755
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -w
+use v5.14;
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+BEGIN { use_ok('Gruntmaster::Daemon') };
diff --git a/t/01-jobs.t b/t/01-jobs.t
new file mode 100644 (file)
index 0000000..e573a95
--- /dev/null
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+use v5.14;
+use strict;
+use warnings;
+
+use Gruntmaster::Daemon;
+
+use Cwd qw/cwd/;
+use File::Copy qw/copy/;
+use File::Copy::Recursive qw/dircopy/;
+use File::Path qw/remove_tree/;
+use File::Temp qw/tempdir/;
+use List::Util qw/sum/;
+use Log::Log4perl;
+use Test::More;
+use YAML::Any qw/LoadFile/;
+
+##################################################
+
+my $loglevel = $ENV{TEST_LOG_LEVEL} // 'OFF';
+my $log_conf = <<CONF;
+log4perl.category.Gruntmaster.Daemon = $loglevel, stderr
+
+log4perl.appender.stderr                          = Log::Log4perl::Appender::Screen
+log4perl.appender.stderr.layout                   = Log::Log4perl::Layout::PatternLayout
+log4perl.appender.stderr.layout.ConversionPattern = [\%d] [\%F{1}:\%M{1}:\%L] [\%p] \%m\%n
+CONF
+Log::Log4perl->init(\$log_conf);
+
+sub check_job{
+  my $job = shift;
+  my $meta = LoadFile "$job/meta.yml";
+  if (exists $meta->{results}) {
+       delete $meta->{results}[$_]{time} for keys $meta->{results};
+  }
+  is $meta->{result}, $meta->{expected_result}, "Result is correct";
+  is $meta->{result_text}, $meta->{expected_result_text}, "Result text is correct";
+  is_deeply $meta->{results}, $meta->{expected_results}, "Results are correct";
+}
+
+my @problems = exists $ENV{TEST_PROBLEMS} ? map {"t/problems/$_"} split ' ', $ENV{TEST_PROBLEMS} : <t/problems/*>;
+plan tests => 3 * sum map { my @temp = <$_/tests/*>; scalar @temp } @problems;
+note "Problems to be tested: " . join ', ', @problems;
+
+my $tempdir = tempdir CLEANUP => 1;
+mkdir "$tempdir/jobs";
+dircopy 't/problems' => "$tempdir/pb";
+
+for my $problem (@problems) {
+  my $meta = LoadFile "$problem/meta.yml";
+ TODO: {
+       local $TODO = $meta->{todo} if exists $meta->{todo};
+       note "Now testing problem $meta->{name} ($meta->{description})";
+       for my $source (<$problem/tests/*>) {
+         my $meta = LoadFile "$source/meta.yml";
+         note "Running $meta->{test_name} ($meta->{test_description})...";
+         dircopy $source => "$tempdir/jobs/job";
+         my $savedcwd = cwd;
+         Gruntmaster::Daemon::process "$tempdir/jobs/job";
+         check_job "$tempdir/log/1";
+         chdir $savedcwd;
+         remove_tree "$tempdir/log", "$tempdir/jobs", {keep_root => 1};
+       }
+  }
+}
diff --git a/t/problems/aminusb/1.in b/t/problems/aminusb/1.in
new file mode 100644 (file)
index 0000000..8d04f96
--- /dev/null
@@ -0,0 +1 @@
+1 2
diff --git a/t/problems/aminusb/2.in b/t/problems/aminusb/2.in
new file mode 100644 (file)
index 0000000..2dde9d0
--- /dev/null
@@ -0,0 +1 @@
+25926 30994
diff --git a/t/problems/aminusb/3.in b/t/problems/aminusb/3.in
new file mode 100644 (file)
index 0000000..b9df610
--- /dev/null
@@ -0,0 +1 @@
+18404 28903
diff --git a/t/problems/aminusb/4.in b/t/problems/aminusb/4.in
new file mode 100644 (file)
index 0000000..d3c0e1a
--- /dev/null
@@ -0,0 +1 @@
+28523 27674
diff --git a/t/problems/aminusb/5.in b/t/problems/aminusb/5.in
new file mode 100644 (file)
index 0000000..0182f9d
--- /dev/null
@@ -0,0 +1 @@
+14479 15757
diff --git a/t/problems/aminusb/meta.yml b/t/problems/aminusb/meta.yml
new file mode 100644 (file)
index 0000000..1291dc9
--- /dev/null
@@ -0,0 +1,17 @@
+---
+name: A-B
+generator: File
+judge: Points
+runner: Verifier
+testcnt: 5
+timeout: 1
+mlimit: 20971520
+olimit: 100
+description: The A-B problem, with a verifier
+files:
+  ver:
+    format: CPP
+    name: ver.cpp
+  prog:
+    format: CPP
+    name: prog.cpp
diff --git a/t/problems/aminusb/tests/ac/meta.yml b/t/problems/aminusb/tests/ac/meta.yml
new file mode 100644 (file)
index 0000000..6b2bc2f
--- /dev/null
@@ -0,0 +1,21 @@
+test_name: Accepted
+test_description: A program which works correctly
+problem: aminusb
+expected_result: 0
+expected_result_text: Accepted
+expected_results:
+- id: 1
+  result: 0
+  result_text: 20
+- id: 2
+  result: 0
+  result_text: 20
+- id: 3
+  result: 0
+  result_text: 20
+- id: 4
+  result: 0
+  result_text: 20
+- id: 5
+  result: 0
+  result_text: 20
diff --git a/t/problems/aminusb/tests/ac/prog.cpp b/t/problems/aminusb/tests/ac/prog.cpp
new file mode 100644 (file)
index 0000000..298dd43
--- /dev/null
@@ -0,0 +1,8 @@
+#include<cstdio>
+int main()
+{
+    int a,b;
+    scanf ("%d%d",&a,&b);
+    printf ("%d",a-b);
+    return 0;
+}
diff --git a/t/problems/aminusb/tests/wa/meta.yml b/t/problems/aminusb/tests/wa/meta.yml
new file mode 100644 (file)
index 0000000..285d9e1
--- /dev/null
@@ -0,0 +1,21 @@
+test_name: Wrong answer
+test_description: A program which does nothing
+problem: aminusb
+expected_result: 10
+expected_result_text: 0 points
+expected_results:
+- id: 1
+  result: 1
+  result_text: Wrong answer
+- id: 2
+  result: 1
+  result_text: Wrong answer
+- id: 3
+  result: 1
+  result_text: Wrong answer
+- id: 4
+  result: 1
+  result_text: Wrong answer
+- id: 5
+  result: 1
+  result_text: Wrong answer
diff --git a/t/problems/aminusb/tests/wa/prog.cpp b/t/problems/aminusb/tests/wa/prog.cpp
new file mode 100644 (file)
index 0000000..76e8197
--- /dev/null
@@ -0,0 +1 @@
+int main() { return 0; }
diff --git a/t/problems/aminusb/ver.cpp b/t/problems/aminusb/ver.cpp
new file mode 100644 (file)
index 0000000..87cc931
--- /dev/null
@@ -0,0 +1,14 @@
+#include <cstdio>
+
+int main(void){
+       FILE *output = fdopen(3, "r");
+       int a, b, ret;
+       scanf("%d%d", &a, &b);
+       fscanf(output, "%d", &ret);
+       if(a-b == ret){
+               printf("20");
+               return 0;
+       } else
+               return 1;
+}
+
diff --git a/t/problems/aplusb/1.in b/t/problems/aplusb/1.in
new file mode 100644 (file)
index 0000000..8d04f96
--- /dev/null
@@ -0,0 +1 @@
+1 2
diff --git a/t/problems/aplusb/1.ok b/t/problems/aplusb/1.ok
new file mode 100644 (file)
index 0000000..00750ed
--- /dev/null
@@ -0,0 +1 @@
+3
diff --git a/t/problems/aplusb/2.in b/t/problems/aplusb/2.in
new file mode 100644 (file)
index 0000000..2dde9d0
--- /dev/null
@@ -0,0 +1 @@
+25926 30994
diff --git a/t/problems/aplusb/2.ok b/t/problems/aplusb/2.ok
new file mode 100644 (file)
index 0000000..16566a2
--- /dev/null
@@ -0,0 +1 @@
+56920
diff --git a/t/problems/aplusb/3.in b/t/problems/aplusb/3.in
new file mode 100644 (file)
index 0000000..b9df610
--- /dev/null
@@ -0,0 +1 @@
+18404 28903
diff --git a/t/problems/aplusb/3.ok b/t/problems/aplusb/3.ok
new file mode 100644 (file)
index 0000000..eb07f22
--- /dev/null
@@ -0,0 +1 @@
+47307
diff --git a/t/problems/aplusb/4.in b/t/problems/aplusb/4.in
new file mode 100644 (file)
index 0000000..d3c0e1a
--- /dev/null
@@ -0,0 +1 @@
+28523 27674
diff --git a/t/problems/aplusb/4.ok b/t/problems/aplusb/4.ok
new file mode 100644 (file)
index 0000000..6a74b56
--- /dev/null
@@ -0,0 +1 @@
+56197
diff --git a/t/problems/aplusb/5.in b/t/problems/aplusb/5.in
new file mode 100644 (file)
index 0000000..0182f9d
--- /dev/null
@@ -0,0 +1 @@
+14479 15757
diff --git a/t/problems/aplusb/5.ok b/t/problems/aplusb/5.ok
new file mode 100644 (file)
index 0000000..7436ebb
--- /dev/null
@@ -0,0 +1 @@
+30236
diff --git a/t/problems/aplusb/6.in b/t/problems/aplusb/6.in
new file mode 100644 (file)
index 0000000..86e0478
--- /dev/null
@@ -0,0 +1 @@
+2253 23718
diff --git a/t/problems/aplusb/6.ok b/t/problems/aplusb/6.ok
new file mode 100644 (file)
index 0000000..d5b0367
--- /dev/null
@@ -0,0 +1 @@
+25971
diff --git a/t/problems/aplusb/meta.yml b/t/problems/aplusb/meta.yml
new file mode 100644 (file)
index 0000000..6e20d6f
--- /dev/null
@@ -0,0 +1,21 @@
+---
+name: A+B
+generator: File
+judge: Points
+runner: File
+testcnt: 6
+timeout: 1
+mlimit: 20971520
+olimit: 100
+description: The simple A+B problem
+files:
+  prog:
+    format: CPP
+    name: prog.cpp
+tests:
+- 20
+- 20
+- 20
+- 20
+- 10
+- 10
diff --git a/t/problems/aplusb/tests/40/meta.yml b/t/problems/aplusb/tests/40/meta.yml
new file mode 100644 (file)
index 0000000..80a67ba
--- /dev/null
@@ -0,0 +1,25 @@
+test_name: 40
+test_description: A program which should get 40 points
+problem: aplusb
+expected_result: 10
+expected_result_text: 40 points
+expected_results:
+- id: 1
+  result: 0
+  result_text: 20
+- id: 2
+  result: 1
+  result_text: Wrong answer
+- id: 3
+  result: 1
+  result_text: Wrong answer
+- id: 4
+  result: 1
+  result_text: Wrong answer
+- id: 5
+  result: 0
+  result_text: 10
+- id: 6
+  result: 0
+  result_text: 10
+
diff --git a/t/problems/aplusb/tests/40/prog.cpp b/t/problems/aplusb/tests/40/prog.cpp
new file mode 100644 (file)
index 0000000..5a41733
--- /dev/null
@@ -0,0 +1,7 @@
+#include<stdio.h>
+int main(void){
+       short a,b;
+       scanf("%hd%hd", &a, &b);
+       printf("%hd", a+b);
+       return 0;
+}
diff --git a/t/problems/aplusb/tests/ac/meta.yml b/t/problems/aplusb/tests/ac/meta.yml
new file mode 100644 (file)
index 0000000..f01b97f
--- /dev/null
@@ -0,0 +1,24 @@
+test_name: Accepted
+test_description: A program which works correctly
+problem: aplusb
+expected_result: 0
+expected_result_text: Accepted
+expected_results:
+- id: 1
+  result: 0
+  result_text: 20
+- id: 2
+  result: 0
+  result_text: 20
+- id: 3
+  result: 0
+  result_text: 20
+- id: 4
+  result: 0
+  result_text: 20
+- id: 5
+  result: 0
+  result_text: 10
+- id: 6
+  result: 0
+  result_text: 10
diff --git a/t/problems/aplusb/tests/ac/prog.cpp b/t/problems/aplusb/tests/ac/prog.cpp
new file mode 100644 (file)
index 0000000..f8a683a
--- /dev/null
@@ -0,0 +1,8 @@
+#include<cstdio>
+int main()
+{
+    int a,b;
+    scanf ("%d%d",&a,&b);
+    printf ("%d",a+b);
+    return 0;
+}
diff --git a/t/problems/aplusb/tests/compile-error/meta.yml b/t/problems/aplusb/tests/compile-error/meta.yml
new file mode 100644 (file)
index 0000000..a610d14
--- /dev/null
@@ -0,0 +1,5 @@
+test_name: Compile Error
+test_description: A program which does not compile
+problem: aplusb
+expected_result: -1
+expected_result_text: Compile error
\ No newline at end of file
diff --git a/t/problems/aplusb/tests/compile-error/prog.cpp b/t/problems/aplusb/tests/compile-error/prog.cpp
new file mode 100644 (file)
index 0000000..b5287f3
--- /dev/null
@@ -0,0 +1 @@
+int
diff --git a/t/problems/aplusb/tests/mle/meta.yml b/t/problems/aplusb/tests/mle/meta.yml
new file mode 100644 (file)
index 0000000..b71c482
--- /dev/null
@@ -0,0 +1,24 @@
+test_name: Memory Limit Exceeded
+test_description: A program which uses up a lot of memory
+problem: aplusb
+expected_result: 10
+expected_result_text: 0 points
+expected_results:
+- id: 1
+  result: 5
+  result_text: Crash (SIGKILL)
+- id: 2
+  result: 5
+  result_text: Crash (SIGKILL)
+- id: 3
+  result: 5
+  result_text: Crash (SIGKILL)
+- id: 4
+  result: 5
+  result_text: Crash (SIGKILL)
+- id: 5
+  result: 5
+  result_text: Crash (SIGKILL)
+- id: 6
+  result: 5
+  result_text: Crash (SIGKILL)
diff --git a/t/problems/aplusb/tests/mle/prog.cpp b/t/problems/aplusb/tests/mle/prog.cpp
new file mode 100644 (file)
index 0000000..049ae69
--- /dev/null
@@ -0,0 +1,3 @@
+int v[1005][1005][20];
+int main(void){
+}
diff --git a/t/problems/aplusb/tests/nzx/meta.yml b/t/problems/aplusb/tests/nzx/meta.yml
new file mode 100644 (file)
index 0000000..97dfc8d
--- /dev/null
@@ -0,0 +1,24 @@
+test_name: Non-Zero Exit status
+test_description: A program which returns 42
+problem: aplusb
+expected_result: 10
+expected_result_text: 0 points
+expected_results:
+- id: 1
+  result: 2
+  result_text: 'Non-zero exit status: 42'
+- id: 2
+  result: 2
+  result_text: 'Non-zero exit status: 42'
+- id: 3
+  result: 2
+  result_text: 'Non-zero exit status: 42'
+- id: 4
+  result: 2
+  result_text: 'Non-zero exit status: 42'
+- id: 5
+  result: 2
+  result_text: 'Non-zero exit status: 42'
+- id: 6
+  result: 2
+  result_text: 'Non-zero exit status: 42'
diff --git a/t/problems/aplusb/tests/nzx/prog.cpp b/t/problems/aplusb/tests/nzx/prog.cpp
new file mode 100644 (file)
index 0000000..4a70c11
--- /dev/null
@@ -0,0 +1,3 @@
+int main(void){
+       return 42;
+}
diff --git a/t/problems/aplusb/tests/ole/meta.yml b/t/problems/aplusb/tests/ole/meta.yml
new file mode 100644 (file)
index 0000000..f5248e0
--- /dev/null
@@ -0,0 +1,24 @@
+test_name: Output Limit Exceeded
+test_description: A program which outputs a lot of nonsense
+problem: aplusb
+expected_result: 10
+expected_result_text: 0 points
+expected_results:
+- id: 1
+  result: 4
+  result_text: Output Limit Exceeded
+- id: 2
+  result: 4
+  result_text: Output Limit Exceeded
+- id: 3
+  result: 4
+  result_text: Output Limit Exceeded
+- id: 4
+  result: 4
+  result_text: Output Limit Exceeded
+- id: 5
+  result: 4
+  result_text: Output Limit Exceeded
+- id: 6
+  result: 4
+  result_text: Output Limit Exceeded
diff --git a/t/problems/aplusb/tests/ole/prog.cpp b/t/problems/aplusb/tests/ole/prog.cpp
new file mode 100644 (file)
index 0000000..92fffb1
--- /dev/null
@@ -0,0 +1,6 @@
+#include<cstdio>
+
+int main(void){
+       for(int i=0;i<100;i++)
+               puts("asdasdasd");
+}
diff --git a/t/problems/aplusb/tests/tle/meta.yml b/t/problems/aplusb/tests/tle/meta.yml
new file mode 100644 (file)
index 0000000..976ac47
--- /dev/null
@@ -0,0 +1,24 @@
+test_name: Time Limit Exceeded
+test_description: A program which loops forever
+problem: aplusb
+expected_result: 10
+expected_result_text: 0 points
+expected_results:
+- id: 1
+  result: 3
+  result_text: Time Limit Exceeded
+- id: 2
+  result: 3
+  result_text: Time Limit Exceeded
+- id: 3
+  result: 3
+  result_text: Time Limit Exceeded
+- id: 4
+  result: 3
+  result_text: Time Limit Exceeded
+- id: 5
+  result: 3
+  result_text: Time Limit Exceeded
+- id: 6
+  result: 3
+  result_text: Time Limit Exceeded
diff --git a/t/problems/aplusb/tests/tle/prog.cpp b/t/problems/aplusb/tests/tle/prog.cpp
new file mode 100644 (file)
index 0000000..a35c303
--- /dev/null
@@ -0,0 +1,3 @@
+int main(void){
+       while(1);
+}
diff --git a/t/problems/double/1.in b/t/problems/double/1.in
new file mode 100644 (file)
index 0000000..d00491f
--- /dev/null
@@ -0,0 +1 @@
+1
diff --git a/t/problems/double/1.ok b/t/problems/double/1.ok
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
diff --git a/t/problems/double/10.in b/t/problems/double/10.in
new file mode 100644 (file)
index 0000000..8502658
--- /dev/null
@@ -0,0 +1 @@
+15229
diff --git a/t/problems/double/10.ok b/t/problems/double/10.ok
new file mode 100644 (file)
index 0000000..1b698e7
--- /dev/null
@@ -0,0 +1 @@
+30458
diff --git a/t/problems/double/2.in b/t/problems/double/2.in
new file mode 100644 (file)
index 0000000..0cfbf08
--- /dev/null
@@ -0,0 +1 @@
+2
diff --git a/t/problems/double/2.ok b/t/problems/double/2.ok
new file mode 100644 (file)
index 0000000..b8626c4
--- /dev/null
@@ -0,0 +1 @@
+4
diff --git a/t/problems/double/3.in b/t/problems/double/3.in
new file mode 100644 (file)
index 0000000..00750ed
--- /dev/null
@@ -0,0 +1 @@
+3
diff --git a/t/problems/double/3.ok b/t/problems/double/3.ok
new file mode 100644 (file)
index 0000000..1e8b314
--- /dev/null
@@ -0,0 +1 @@
+6
diff --git a/t/problems/double/4.in b/t/problems/double/4.in
new file mode 100644 (file)
index 0000000..76e69c8
--- /dev/null
@@ -0,0 +1 @@
+2594
diff --git a/t/problems/double/4.ok b/t/problems/double/4.ok
new file mode 100644 (file)
index 0000000..814974a
--- /dev/null
@@ -0,0 +1 @@
+5188
diff --git a/t/problems/double/5.in b/t/problems/double/5.in
new file mode 100644 (file)
index 0000000..f7f167e
--- /dev/null
@@ -0,0 +1 @@
+22341
diff --git a/t/problems/double/5.ok b/t/problems/double/5.ok
new file mode 100644 (file)
index 0000000..5edacf0
--- /dev/null
@@ -0,0 +1 @@
+44682
diff --git a/t/problems/double/6.in b/t/problems/double/6.in
new file mode 100644 (file)
index 0000000..2638034
--- /dev/null
@@ -0,0 +1 @@
+12612
diff --git a/t/problems/double/6.ok b/t/problems/double/6.ok
new file mode 100644 (file)
index 0000000..3874ec5
--- /dev/null
@@ -0,0 +1 @@
+25224
diff --git a/t/problems/double/7.in b/t/problems/double/7.in
new file mode 100644 (file)
index 0000000..1661b24
--- /dev/null
@@ -0,0 +1 @@
+2730
diff --git a/t/problems/double/7.ok b/t/problems/double/7.ok
new file mode 100644 (file)
index 0000000..4bbe087
--- /dev/null
@@ -0,0 +1 @@
+5460
diff --git a/t/problems/double/8.in b/t/problems/double/8.in
new file mode 100644 (file)
index 0000000..bdc067b
--- /dev/null
@@ -0,0 +1 @@
+9037
diff --git a/t/problems/double/8.ok b/t/problems/double/8.ok
new file mode 100644 (file)
index 0000000..5577366
--- /dev/null
@@ -0,0 +1 @@
+18074
diff --git a/t/problems/double/9.in b/t/problems/double/9.in
new file mode 100644 (file)
index 0000000..6bec6d1
--- /dev/null
@@ -0,0 +1 @@
+7511
diff --git a/t/problems/double/9.ok b/t/problems/double/9.ok
new file mode 100644 (file)
index 0000000..2232790
--- /dev/null
@@ -0,0 +1 @@
+15022
diff --git a/t/problems/double/meta.yml b/t/problems/double/meta.yml
new file mode 100644 (file)
index 0000000..21ffc4b
--- /dev/null
@@ -0,0 +1,14 @@
+---
+name: A-B
+generator: File
+judge: Absolute
+runner: File
+testcnt: 10
+timeout: 1
+mlimit: 20971520
+olimit: 100
+description: The A * 2 problem
+files:
+  prog:
+    format: CPP
+    name: prog.cpp
diff --git a/t/problems/double/tests/wa/meta.yml b/t/problems/double/tests/wa/meta.yml
new file mode 100644 (file)
index 0000000..00f38de
--- /dev/null
@@ -0,0 +1,18 @@
+test_name: Wrong answer
+test_description: A program which fails on test 4
+problem: double
+expected_result: 1
+expected_result_text: Wrong answer
+expected_results:
+- id: 1
+  result: 0
+  result_text: 0
+- id: 2
+  result: 0
+  result_text: 0
+- id: 3
+  result: 0
+  result_text: 0
+- id: 4
+  result: 1
+  result_text: Wrong answer
diff --git a/t/problems/double/tests/wa/prog.cpp b/t/problems/double/tests/wa/prog.cpp
new file mode 100644 (file)
index 0000000..8dd19c7
--- /dev/null
@@ -0,0 +1,8 @@
+#include<cstdio>
+
+int main(void){
+       char x;
+       scanf("%d", &x);
+       printf("%d", 2*x);
+       return 0;
+}
diff --git a/t/problems/increment/int.cpp b/t/problems/increment/int.cpp
new file mode 100644 (file)
index 0000000..3b89262
--- /dev/null
@@ -0,0 +1,23 @@
+#include<cstdio>
+#include<cstdlib>
+#include<ctime>
+#include<unistd.h>
+
+int main(void){
+       srand(time(NULL));
+       for(int i=0;i<100;i++){
+               int nr = rand() % 100;
+               printf("%d\n", nr);
+               fflush(stdout);
+               int ret;
+               scanf("%d", &ret);
+               if(ret != nr + 1){
+                       fprintf(stderr, "bad ret: %d instead of %d", ret, nr + 1);
+                       return 1;
+               }
+       }
+
+       if(write(4, "20", 2) == -1)
+               perror("write");
+       return 0;
+}
diff --git a/t/problems/increment/meta.yml b/t/problems/increment/meta.yml
new file mode 100644 (file)
index 0000000..3ca70dd
--- /dev/null
@@ -0,0 +1,16 @@
+---
+name: Increment
+generator: Undef
+judge: Points
+runner: Interactive
+testcnt: 5
+timeout: 1
+mlimit: 20971520
+description: A trivial interactive problem
+files:
+  int:
+    format: CPP
+    name: int.cpp
+  prog:
+    format: CPP
+    name: prog.cpp
diff --git a/t/problems/increment/tests/ac/meta.yml b/t/problems/increment/tests/ac/meta.yml
new file mode 100644 (file)
index 0000000..9576c5c
--- /dev/null
@@ -0,0 +1,21 @@
+test_name: Accepted
+test_description: A program which works correctly
+problem: increment
+expected_result: 0
+expected_result_text: Accepted
+expected_results:
+- id: 1
+  result: 0
+  result_text: 20
+- id: 2
+  result: 0
+  result_text: 20
+- id: 3
+  result: 0
+  result_text: 20
+- id: 4
+  result: 0
+  result_text: 20
+- id: 5
+  result: 0
+  result_text: 20
diff --git a/t/problems/increment/tests/ac/prog.cpp b/t/problems/increment/tests/ac/prog.cpp
new file mode 100644 (file)
index 0000000..da549a7
--- /dev/null
@@ -0,0 +1,12 @@
+#include<cstdio>
+
+int main(void){
+       for(int i=0;i<100;i++){
+               int x;
+               scanf("%d", &x);
+               printf("%d\n", x + 1);
+               fflush(stdout);
+       }
+
+       return 0;
+}
diff --git a/t/problems/square/gen.cpp b/t/problems/square/gen.cpp
new file mode 100644 (file)
index 0000000..f5fe75b
--- /dev/null
@@ -0,0 +1,8 @@
+#include<cstdio>
+#include<cstdlib>
+
+int main(int argc, char **argv){
+       int testnum = atoi(argv[0]);
+       printf("%d", testnum);
+       return 0;
+}
diff --git a/t/problems/square/meta.yml b/t/problems/square/meta.yml
new file mode 100644 (file)
index 0000000..99ee850
--- /dev/null
@@ -0,0 +1,20 @@
+---
+name: A-B
+generator: Run
+judge: Points
+runner: Verifier
+testcnt: 10
+timeout: 1
+mlimit: 20971520
+olimit: 100
+description: The X^2 problem
+files:
+  ver:
+    format: CPP
+    name: ver.cpp
+  gen:
+    format: CPP
+    name: gen.cpp
+  prog:
+    format: CPP
+    name: prog.cpp
diff --git a/t/problems/square/tests/ac/meta.yml b/t/problems/square/tests/ac/meta.yml
new file mode 100644 (file)
index 0000000..93fd38f
--- /dev/null
@@ -0,0 +1,36 @@
+test_name: Accepted
+test_description: A program which works correctly
+problem: square
+expected_result: 0
+expected_result_text: Accepted
+expected_results:
+- id: 1
+  result: 0
+  result_text: 10
+- id: 2
+  result: 0
+  result_text: 10
+- id: 3
+  result: 0
+  result_text: 10
+- id: 4
+  result: 0
+  result_text: 10
+- id: 5
+  result: 0
+  result_text: 10
+- id: 6
+  result: 0
+  result_text: 10
+- id: 7
+  result: 0
+  result_text: 10
+- id: 8
+  result: 0
+  result_text: 10
+- id: 9
+  result: 0
+  result_text: 10
+- id: 10
+  result: 0
+  result_text: 10
diff --git a/t/problems/square/tests/ac/prog.cpp b/t/problems/square/tests/ac/prog.cpp
new file mode 100644 (file)
index 0000000..0a66015
--- /dev/null
@@ -0,0 +1,8 @@
+#include<cstdio>
+
+int main(void){
+       int x;
+       scanf("%d", &x);
+       printf("%d", x*x);
+       return 0;
+}
diff --git a/t/problems/square/ver.cpp b/t/problems/square/ver.cpp
new file mode 100644 (file)
index 0000000..cb4d031
--- /dev/null
@@ -0,0 +1,14 @@
+#include <cstdio>
+
+int main(void){
+       FILE *output = fdopen(3, "r");
+       int x, ret;
+       scanf("%d", &x);
+       fscanf(output, "%d", &ret);
+       if(x*x == ret){
+               printf("10");
+               return 0;
+       } else
+               return 1;
+}
+
This page took 0.056689 seconds and 4 git commands to generate.