lib/contest/driver/kattis_driver.rb
#
# kattis_driver.rb
#
# Copyright (c) 2013-2014 Hiroyuki Sano <sh19910711 at gmail.com>
# Copyright (c) 2014 Oskar Sundström <oskar.sundstrom at gmail.com>
# Licensed under the MIT-License.
#
# An official Python submission script can be found at
# https://open.kattis.com/help/submit
#
# Using the Python script you would write:
# $ python3 submit3.py -p aaah Main.java
#
# To do the same thing using git-contest you instead write:
# $ git contest submit kattis -p aaah -s Main.java
#
require 'contest/driver/common'
module Contest
module Driver
class KattisDriver < DriverBase
def initialize_ext
@client = Mechanize.new {|agent|
agent.user_agent_alias = 'Windows IE 7'
}
end
def get_opts_ext
define_options do
opt(
:contest_id,
"Contest ID (Ex: open, kth, liu, etc...)",
:type => :string,
:required => false,
)
opt(
:problem_id,
"Problem ID (Ex: aaah, listgame2, etc...)",
:type => :string,
:required => true,
)
end
end
def get_site_name
"Kattis"
end
def get_desc
"Kattis (URL: https://open.kattis.com/)"
end
def get_problem_id(options)
"#{options[:problem_id]}"
end
def resolve_language(label)
case label
when 'cpp'
return '1'
when 'c'
return '2'
when 'java'
return '3'
when 'python2'
return '6'
when 'python3'
return '8'
when 'cs'
return '9'
when 'golang'
return '10'
when 'objc'
return '11'
when 'haskell'
return '12'
when 'prolog'
return '13'
when 'javascript'
return '14'
when 'php'
return '15'
else
abort 'unknown language'
end
end
def submit_ext
trigger 'start'
problem_id = @options[:problem_id]
if (@options[:contest_id])
subdomain = @options[:contest_id]
else
subdomain = 'open'
end
# Login
trigger 'before_login'
login_page = @client.get "https://#{subdomain}.kattis.com/login?email_login=true"
login_page.form_with(:action => '/login/email') do |form|
form.user = @config["user"]
form.password = @config["password"]
end.submit
trigger 'after_login'
# Submit
trigger 'before_submit', @options
submit_page = @client.get "https://#{subdomain}.kattis.com/submit"
res_page = submit_page.form_with(:name => 'upload') do |form|
form.problem = problem_id
form['lang'] = @options[:language]
form.sub_code = File.read(@options[:source])
# Use file name as main class for Java
if (@options[:language] == resolve_language('java'))
form['mainclass'] = @options[:source].rpartition('.')[0]
end
form.submit(form.button_with(:name => 'submit'))
end.submit
trigger 'after_submit'
# Result
trigger 'before_wait'
user = @config['user']
doc = Nokogiri::HTML(res_page.body)
# Check for error messages
error = doc.xpath('//p[@class="error"]')[0];
if ((/Problem ID not found in database./ =~ error) ||
(/Problem-id inte funnet i databasen./ =~ error))
abort "Problem ID not found in database."
end
sleep 2
submissions_page = @client.get "https://#{subdomain}.kattis.com/users/#{user}"
submission_id = get_submission_id(submissions_page.body)
status = get_status_wait(submission_id, subdomain)
trigger(
'after_wait',
{
:submission_id => submission_id,
:status => status,
:result => get_commit_message(status),
}
)
trigger 'finish'
get_commit_message(status)
end
def is_wait_status(status)
case status
when "Running", "Compiling", ""
true
else
false
end
end
def get_status_wait(submission_id, subdomain)
submission_id = submission_id.to_s
# Wait for result
12.times do
sleep 10
submission_page = @client.get "https://#{subdomain}.kattis.com/submissions/#{submission_id}"
status = get_submission_status(submission_id, submission_page.body)
return status unless is_wait_status status
trigger 'retry'
end
trigger 'timeout'
return 'timeout'
end
def get_submission_id(body)
doc = Nokogiri::HTML(body)
return doc.xpath('//*[@id="wrapper"]/div/div[2]/section/table/tbody/tr[1]/td[1]/a')[0].inner_text().strip
end
def get_submission_status(submission_id, body)
doc = Nokogiri::HTML(body)
return doc.xpath('//*[@id="judge_table"]/tbody/tr[1]/td[4]/span').inner_text().strip
end
end
end
end