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

NAME

OnlineJudge::Progra - (Just Another) Programming Tasks Grading System

VERSION

Version 0.021

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's home
 $judge->set_timeinterval(30);          # 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'. Once 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)

The time interval defines the amount of time (in seconds) progra waits to check again for new requests to process. Default to 60 seconds.

set_background(true/false)

Defines if progra runs on background or not. In case background is set, the output and errors will be redirected to the output.log and error.log files found in progra's home directory. True by default.

set_logging(true/false)

Defines if progra log risky situations or not (badwords and time limits). Anything different than zero is considered true. 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 will 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.

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: 'biw'. The -b argument ignores extra white spaces, 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!

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 uniquely.

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: $word. The forbidden word $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 processing it, 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.

TODO

There are lots of things to do:

Implement some kind of sandbox for safely test and compile.
Try with distributed processing.
Create working modules that use progra.

AVAILABILITY

 The latest version of progra is available from CPAN:

 http://search.cpan.org/dist/OnlineJudge-Progra/

 You can also browse the git repository at:

 https://github.com/ileiva/onlinejudge-progra.git
       

AUTHOR

 israel leiva <ilv AT cpan DOT org>

COPYRIGHT

 Copyright (c) 2011-2014 israel leiva

 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/