The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

OnlineJudge::Progra - Programming Tasks Grading System

VERSION

Version 0.01

SYNOPSIS

 use OnlineJudge::Progra;
 
 # Create your soubroutine to obtain new requests to process.
 # Returns requests to be processed.
 sub get {
         #...
         return @requests;
 }

 # Create your subroutine to update requests wherever you store them.
 # Receives a processed request.
 sub update {
         my $request = shift;
         # ...
 }

 my $judge = OnlineJudge::Progra->new();
 
 $judge->set_home('/home/progra/'); # Progra home directory
 $judge->set_timeinterval(30);          # time in seconds
 
 $judge->run(
        get_sub => sub { &get },
        update_sub => sub { &update }
 );     

DESCRIPTION

Progra is an Online Judge capable of compile and test programs written to solve a programming task.

METHODS

set_home(/home/foo/bar)

Sets the home directory for Progra files (logs, pid file, etc). If not specified is set to '/tmp'. When Progra starts, it creates a .pid file in its home directory. You should remove the .pid file created in this directory in order to stop Progra.

set_timeinterval(n)

Time interval (in seconds) it waits to check again for new requests to be processed. Default to 60 seconds.

set_background(true/false)

Defines whether Progra runs on background or not. In case background is set, then output and errors will be redirected to specific files found in Progra home directory (output.log and error.log). True by default.

set_compiler('ext', '/path/to/compiler _SOURCECODE_ -options _BINARY_')

Defines how source codes of a given language must be compiled. The _SOURCECODE_ and _BINARY_ strings must be present (yes, with both underscores) and they would be internally replaced by the corresponding filenames. Example:

 # how a .c file should be compiled
 $judge->set_compiler('c', '/usr/bin/gcc _SOURCECODE_ -o _BINARY_')
 

There are some compiler strings by default:

 c: /usr/bin/gcc _SOURCECODE_ -o _BINARY_
 cpp: /usr/bin/g++ _SOURCECODE_ -o _BINARY_
 

If you want to avoid the output generated by compilation errors, you should add '> /dev/null 2>&1' at the end of the string, otherwise it would be redireced to standard output.

$judge->set_exec('ext', 'string to execute _FILE_')

Defines how programs of a given language must be executed. The _FILE_ string must be present and it would be internally replaced by the corresponding filename. Example:

 # how a .pl file should be 'executed'
 $judge->set_exec('pl', '/usr/bin/perl _FILE_')
 
 # how a .c file should be executed
 $judge->set_exec('c', './_FILE_');

There are some execution strings by default:

 pl: /usr/bin/perl _FILE_
 c: ./_FILE_
 cpp: ./_FILE_
 py: /usr/bin/python _FILE_

diff_options(string)

Replace options for diff command. By default are: 'biwBE'. The -b argument ignores extra white spaces, the -B ignores white lines, the -E ignores tab expansion, the -w ignores all white spaces, the -i ignores case differences.

load_badwords(/path/to/file.txt)

Open the specified file and load the badwords into memory. They must be separated by commas. This is quite basic and should be enhanced with stronger security policies.

Example: system, exec, popen, etc.

Be aware that system and system() are different words!. This method is mandatory.

verbose(true/false)

Defines if Progra runs in verbose. If true, it prints out every processed request to standard output. False by default.

run(get_sub => &get, update_sub => &update)

Runs the judge. It has two mandatory parameters, get_sub and update_sub. Both define the subroutines used to obtain new requests and to update processed requests.

Subroutines to obtain new requests must return an array of hash references:

 (
         {
                 'rid'  => 1,
                 'sourcecode' => '/home/progra/users/1/task1.pl'
                 'lang' => 'pl',
                 'compile' => 0,
                 'userpath' => '/home/progra/users/1/',
                 'taskpath' => '/home/progra/tasks/1/',
                 'timelimit' => 1,
                 'testcases' => 10,
                 'maxscore'     => 100,
         },
         {
                 'rid'  => 2,
                 'sourcecode' => '/home/progra/users/2/task1.c',
                 'lang' => 'c',
                 'compile' => 1,
                 'userpath' => '/home/progra/users/2/'
                 'taskpath' => '/home/progra/tasks/1/',
                 'timelimit' => 1,
                 'testcases' => 20,
                 'maxscore' => 100,
         }
 )
  

You MUST specify a rid, it identifies the processed request uniquelly.

You MUST specify a language. It cannot compile and/or execute a source code/program if it does not know its language. The format used is according to its source code extension: Perl => pl, C => c, C++ => cpp and so on. The extension used must be consistent with the ones used in compile and exec strings.

You MUST specify a testcases number. It has to be consistent with the test cases you made. If you made ten test cases, they need to be named from 0 to 9 with input. and output. prefix, depending on if they are input or output files.

If you do not specify a maxscore, it will be 100 by default. This way the score obtained for every test case passed will be 100 divided by the number of test cases.

If you do not specify a timelimit, it will be 1 second by default.

The compile field specifies if the source code must be compiled or not. False if not specified.

You MUST specify a sourcecode, userpath and taskpath. Test cases files MUST be inside taskpath. Example:

 -- /home/progra/tasks/1/
 --------------- input.0
 --------------- output.0
 --------------- input.1
 --------------- output.1
 

This represents a directory with 2 test cases.

Subroutines to update processed requests must receive a hash structure like this:

 {
         'rid' => 1,
         'grade' => 100,
         'timemarked' => 1233455,
         'executiontime' => 0.001,
         'comment' => 'AC'
 }

The timemarked field is an Unix time stamp, it records the time when the request was processed. The execution time field is the average execution time of all test cases. The comment field is a string that represents the state of the request. The possible values are:

 AC - Accepted: the program passed all test cases.
 WA - Wrong Answer: the program didn't pass all test cases.
 PC - Processing: the source code is in the queue waiting to be processed.
 TL - Time Limit Exceeded: the program ran out of time.
 CE - Compilation Error: there was an error while trying to compile the source code.
 BW - Bad Word found: a forbidden word was found in the source code.
 IE - Internal Error: something went wrong in Progra, check the error.log file.

Note: When a bad/forbidden word is found in the source code or a time limit happens when executing it, a directory named "logged" will be created and the source code that caused the security breach will be saved with the format "requestid_hourmin.ext"

Progra will return the result of a request inmediately after is processed, so the update subroutine must receive only one request at a time. Progra will call this subroutine for each request processed.

BUGS

No bugs found so far.

AUTHOR

Israel Leiva A. - <ileiva AT csrg DOT cl>

COPYRIGHT

Copyright (C) 2011-2012 Israel Leiva A.

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

http://www.gnu.org/licenses/

SEE ALSO

Time::HiRes, File::Spec::Functions, Proc::Killall, File::Copy