ojagent 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/quicksubmit CHANGED
@@ -11,10 +11,13 @@ require 'highline'
11
11
 
12
12
  ME = 'quicksubmit'
13
13
 
14
- Agents = {
15
- :livearchive => OJAgent::LiveArchiveAgent,
16
- :timus => OJAgent::TimusAgent
17
- }
14
+ Agents = {}
15
+ OJAgent.all.each do |agent|
16
+ name = agent.name.downcase
17
+ name.sub!(/.*::/, '')
18
+ name.sub!(/agent$/, '')
19
+ Agents[name.to_sym] = agent
20
+ end
18
21
 
19
22
  Ext2Lang = {
20
23
  '.pas' => :pascal,
@@ -138,7 +141,8 @@ $*.uniq.each do |path|
138
141
  path.sub!(/#{ext}$/, ".#{Time.now.to_i}#{ext}") if File.exists? path
139
142
  IO.write(path, code)
140
143
 
141
- LOG.add status[:status] =~ /accepted/i ? Logger::INFO : Logger::WARN, status
144
+ level = status[:status] =~ /correct|accepted/i ? Logger::INFO : Logger::WARN
145
+ LOG.add level, status
142
146
  rescue Exception => ex
143
147
  LOG.error ex
144
148
  end
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'ojagent'
4
+
5
+ # Change these two lines
6
+ USER = ENV['OJ_USERNAME'] || 'ojagent'
7
+ PASS = ENV['OJ_PASSWORD'] || 'ppnn13%dkstFeb.1st'
8
+
9
+ HDOJ = OJAgent::HDOJAgent.new
10
+ HDOJ.login USER, PASS
11
+
12
+ def code(off)
13
+ return <<-CODE
14
+ #include <time.h>
15
+ #include <stdio.h>
16
+ #include <stdlib.h>
17
+ #include <string.h>
18
+
19
+ int main(void) {
20
+ int n = #{off};
21
+ clock_t cpu;
22
+ size_t mem;
23
+ char* p = NULL;
24
+
25
+ while (n-- > 0) {
26
+ getchar();
27
+ }
28
+ n = getchar();
29
+ if (n == EOF) {
30
+ n = 0;
31
+ }
32
+
33
+ cpu = ((n >> 4) * 100 + 10) * (CLOCKS_PER_SEC / 1000);
34
+ mem = ((n & 0xF) * 1000 + 10) * 1024;
35
+ p = malloc(mem);
36
+ memset(p, 0xff, mem);
37
+ while (clock() < cpu) {
38
+ p[rand() % mem] = (char)cpu;
39
+ }
40
+ putchar(p[0]);
41
+ free(p);
42
+
43
+ return 0;
44
+ }
45
+ CODE
46
+ end
47
+
48
+ input = ''
49
+ 50.times do
50
+ id = HDOJ.submit! '3337', code(input.size), :c
51
+ status = HDOJ.status! id
52
+ ascii = (status[:time].to_i / 100) * 16 + (status[:mem].to_i / 1000)
53
+ break if ascii.zero?
54
+ input << ascii.chr
55
+ puts input
56
+ end
57
+ p input
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/ruby
2
+
3
+ BEGIN {
4
+ require 'ojagent'
5
+
6
+ $filename = 'rosalind.cookie'
7
+ $rosalind = OJAgent::RosalindAgent.new
8
+ $rosalind.agent.cookie_jar.load $filename if File.readable? $filename
9
+ }
10
+
11
+ END {
12
+ $rosalind.agent.cookie_jar.save_as $filename
13
+ FileUtils.chmod 0600, $filename
14
+ }
15
+
16
+ require 'highline'
17
+
18
+ begin
19
+ require 'wirble'
20
+ def pp(status)
21
+ puts Wirble::Colorize.colorize(status.inspect)
22
+ end
23
+ rescue LoadError
24
+ alias :pp :p
25
+ end
26
+
27
+ def usage
28
+ print <<-USAGE
29
+ Usage:
30
+ rosalind.rb login
31
+ rosalind.rb $pid.pl dl
32
+ rosalind.rb $pid.pl up
33
+ USAGE
34
+ exit 1
35
+ end
36
+
37
+ $pl, $op = *$*
38
+
39
+ if $pl =~ /login/i
40
+ hl = HighLine.new
41
+ user = hl.ask("Username: ")
42
+ pass = hl.ask("Password: "){|q| q.echo = false}
43
+ $rosalind.login user, pass
44
+ elsif $pl =~ /[a-z]*/
45
+ id = $&
46
+ if $op =~ /dl|download|open/i
47
+ input = $rosalind.open! id
48
+ IO.write input.filename, input.content
49
+ system %{perl #{$pl} #{input.filename} | tee output}
50
+ elsif $op =~ /up|upload|submit/i
51
+ output = IO.read('output')
52
+ source = IO.read($pl)
53
+ status = $rosalind.judge! id, [output, 'output'], [source, $pl]
54
+ pp status
55
+ if status && status[:status] == 'Correct'
56
+ FileUtils.mv $pl, 'pl/', :verbose => true
57
+ FileUtils.mv "rosalind_#{id}.txt", 'txt/', :verbose => true
58
+ FileUtils.rm "rosalind_#{id}.txt.index", :force => true
59
+ end
60
+ else
61
+ usage
62
+ end
63
+ else
64
+ usage
65
+ end
66
+
data/lib/ojagent.rb CHANGED
@@ -1,8 +1,17 @@
1
1
  require 'ojagent/version'
2
2
  require 'ojagent/ojagent.rb'
3
- require 'ojagent/timus_agent.rb'
4
- require 'ojagent/livearchive_agent.rb'
3
+
4
+ libdir = File.join(File.expand_path(File.dirname(__FILE__)), 'ojagent')
5
+ Dir.entries(libdir).each do |filename|
6
+ require File.join(libdir, filename) if filename.end_with? '_agent.rb'
7
+ end
5
8
 
6
9
  module OJAgent
7
- # Your code goes here...
10
+ # Return all avialbe agents.
11
+ def self.all
12
+ ObjectSpace.each_object(Class).select{|agent| agent < OJAgent}
13
+ end
14
+
15
+ # All avialbe agents at initial time.
16
+ StandardAgents = all
8
17
  end
@@ -0,0 +1,41 @@
1
+ module OJAgent
2
+ class HDOJAgent < OJAgent
3
+ def initialize
4
+ super 'http://acm.hdu.edu.cn',
5
+ :cpp => 0,
6
+ :c => 1,
7
+ :mscpp => 2,
8
+ :msc => 3,
9
+ :pascal => 4,
10
+ :java => 5
11
+ end
12
+
13
+ def login(user, pass)
14
+ @user = user
15
+ page = get '/'
16
+ login_form = page.form_with :action => '/userloginex.php?action=login'
17
+ login_form.set_fields :username => user,
18
+ :userpass => pass
19
+ login_form.submit
20
+ end
21
+
22
+ def submit(pid, code, lang)
23
+ page = get '/submit.php'
24
+ submit_form = page.form_with :action => './submit.php?action=submit'
25
+ submit_form.set_fields :problemid => pid,
26
+ :language => languages[lang],
27
+ :usercode => code
28
+ submit_form.submit
29
+ pid.to_s
30
+ end
31
+
32
+ @@selector = '#fixed_table table.table_text tr'
33
+ @@thead = [:id, :date, :status, :pid, :time, :mem, :length, :lang, :user]
34
+
35
+ def status(pid)
36
+ parse_status '/status.php?user=' + user, @@selector, @@thead do |tr|
37
+ tr[3] && tr[3].inner_text == pid
38
+ end
39
+ end
40
+ end
41
+ end
@@ -9,6 +9,7 @@ module OJAgent
9
9
  end
10
10
 
11
11
  def login(user, pass)
12
+ @user = user
12
13
  page = get '/'
13
14
  login_form = page.form_with :id => 'mod_loginform'
14
15
  login_form.set_fields :username => user,
@@ -17,9 +18,6 @@ module OJAgent
17
18
  result = login_form.submit
18
19
  end
19
20
 
20
- def logout
21
- end
22
-
23
21
  def submit(pid, code, lang)
24
22
  page = get '/index.php?option=com_onlinejudge&Itemid=25'
25
23
  action = 'index.php?option=com_onlinejudge&Itemid=25&page=save_submission'
@@ -38,25 +36,14 @@ module OJAgent
38
36
  end
39
37
  end
40
38
 
41
- def status(id)
42
- page = get '/index.php?option=com_onlinejudge&Itemid=9'
43
- status = (page / '.maincontent table tr').
44
- map{|tr| tr / 'td'}.
45
- find{|td| !td.empty? && td[0].inner_text == id}
39
+ @@selector = '.maincontent table tr'
40
+ @@thead = [:id, :pid, :pname, :status, :lang, :time, :data]
46
41
 
47
- return nil unless status
48
- ret = {
49
- :id => status[0].inner_text,
50
- :pid => status[1].inner_text,
51
- :pname => status[2].inner_text,
52
- :status => status[3].inner_text.strip,
53
- :lang => status[4].inner_text,
54
- :time => status[5].inner_text,
55
- :date => status[6].inner_text
56
- }
57
- url = status[3] / 'a[href]'
58
- ret[:url] = url.map{|a| a['href']} unless url.empty?
59
- ret
42
+ def status(id)
43
+ url = '/index.php?option=com_onlinejudge&Itemid=9'
44
+ parse_status url, @@selector, @@thead do |tr|
45
+ !tr.empty? && tr[0].inner_text == id
46
+ end
60
47
  end
61
48
  end
62
49
  end
@@ -2,6 +2,14 @@ require 'forwardable'
2
2
  require 'mechanize'
3
3
  require 'nokogiri'
4
4
 
5
+ class Mechanize::Form::FileUpload
6
+ def file=(file, default_name = 'noname')
7
+ data, name = *file
8
+ self.file_data = data
9
+ self.file_name = name || default_name
10
+ end
11
+ end
12
+
5
13
  module OJAgent
6
14
  class LoginFailureError < RuntimeError
7
15
  end
@@ -16,9 +24,9 @@ module OJAgent
16
24
 
17
25
  attr_accessor :retries, :duration
18
26
 
19
- attr_reader :agent, :base_uri, :languages
27
+ attr_reader :agent, :base_uri, :languages, :user
20
28
 
21
- def initialize(base_uri, languages)
29
+ def initialize(base_uri = nil, languages = {})
22
30
  @agent = Mechanize.new
23
31
  @agent.open_timeout = 20
24
32
  @agent.read_timeout = 60
@@ -44,6 +52,10 @@ module OJAgent
44
52
  raise NotImplementedError
45
53
  end
46
54
 
55
+ def open(pid)
56
+ # noop
57
+ end
58
+
47
59
  def submit(pid, code, lang)
48
60
  raise NotImplementedError
49
61
  end
@@ -52,6 +64,43 @@ module OJAgent
52
64
  raise NotImplementedError
53
65
  end
54
66
 
67
+ def parse_status(url, selector, thead, &block)
68
+ tbody = get(url) / selector
69
+ tr = tbody.map{|tr| tr / 'td'}.find{|tr| yield tr}
70
+ return nil unless tr
71
+
72
+ ret = {}
73
+ thead.zip(tr) do |th, td|
74
+ next unless th && td
75
+ ret[th] = td.inner_text.strip.gsub(/\s+/, ' ')
76
+ if th == :status
77
+ url = td / 'a[href]'
78
+ if url.size > 0
79
+ ret[:url] = (ret[:url] || []) + url.map{|a| a['href']}
80
+ end
81
+ end
82
+ end
83
+ ret
84
+ end
85
+
86
+ # Open the problem or download the input. For online judges that ask
87
+ # users to download the input and upload the output in time limit,
88
+ # user must open (download the input) before submit (upload the output).
89
+ # For other online judges, it does nothing.
90
+ def open!(pid, retries = 1)
91
+ retries ||= self.retries
92
+ retries.times do
93
+ begin
94
+ ret = open pid
95
+ return ret if ret
96
+ rescue
97
+ end
98
+ end
99
+ raise OperationFailureError, "Fail to open"
100
+ end
101
+
102
+ # Submit solution and retry on failure. The return value is a hint for
103
+ # getting status and varys at different online judges.
55
104
  def submit!(pid, code, lang, retries = nil)
56
105
  retries ||= self.retries
57
106
  retries.times do
@@ -64,6 +113,7 @@ module OJAgent
64
113
  raise OperationFailureError, "Fail to submit"
65
114
  end
66
115
 
116
+ # Get status and retry on failure.
67
117
  def status!(id, retries = nil, duration = nil)
68
118
  retries ||= self.retries
69
119
  duration ||= self.duration
@@ -84,5 +134,11 @@ module OJAgent
84
134
  return ret if ret
85
135
  raise OperationFailureError, "Fail to get status"
86
136
  end
137
+
138
+ # Submit solution and get the corresponding status.
139
+ def judge!(pid, code, lang, retries = nil, duration = nil)
140
+ id = submit!(pid, code, lang, retries)
141
+ status!(id, retries, duration)
142
+ end
87
143
  end
88
144
  end
@@ -0,0 +1,44 @@
1
+ module OJAgent
2
+ class RosalindAgent < OJAgent
3
+ def initialize
4
+ super 'http://rosalind.info'
5
+ end
6
+
7
+ def login(user, pass)
8
+ @user = user
9
+ page = get '/accounts/login/'
10
+ login_form = page.form_with :id => 'id_form_login'
11
+ login_form.set_fields :username => user,
12
+ :password => pass
13
+ login_form.submit
14
+ end
15
+
16
+ def open(pid)
17
+ get "/problems/#{pid}/dataset/"
18
+ end
19
+
20
+ def submit(pid, ans, src = nil)
21
+ page = get "/problems/#{pid}/"
22
+ submit_form = page.form_with :id => 'id_form_submission'
23
+ submit_form.file_upload_with(:name => 'output_file').file = ans
24
+ submit_form.file_upload_with(:name => 'code').file = src if src
25
+ submit_form.submit
26
+ end
27
+
28
+ @@close = "\xc3\x97".force_encoding('utf-8')
29
+
30
+ def status(page)
31
+ status = {}
32
+ [:error, :warning, :info, :success].each do |type|
33
+ messages = []
34
+ (page / "div.main div.alert-#{type}.flash-message").each do |alert|
35
+ message = alert.inner_text.strip.gsub(@@close, '').gsub(/\s+/, ' ')
36
+ messages << message unless message.empty?
37
+ end
38
+ status[type] = messages unless messages.empty?
39
+ end
40
+ status[:status] = status[:success] && !status[:error] ? 'Correct' : 'Wrong'
41
+ status
42
+ end
43
+ end
44
+ end
@@ -1,7 +1,5 @@
1
1
  module OJAgent
2
2
  class TimusAgent < OJAgent
3
- attr_accessor :user, :pass
4
-
5
3
  def initialize
6
4
  super 'http://acm.timus.ru',
7
5
  :pascal => '3',
@@ -12,43 +10,33 @@ module OJAgent
12
10
  end
13
11
 
14
12
  def login(user, pass)
15
- self.user = user
16
- self.pass = pass
17
- end
18
-
19
- def logout
13
+ @user = user
14
+ @pass = pass
20
15
  end
21
16
 
22
17
  def submit(pid, code, lang)
23
18
  page = get '/submit.aspx'
24
19
  submit_form = page.form_with :action => 'submit.aspx?space=1'
25
- submit_form.set_fields :JudgeID => user + pass,
20
+ submit_form.set_fields :JudgeID => user + @pass,
26
21
  :Language => languages[lang],
27
22
  :ProblemNum => pid,
28
23
  :Source => code
29
24
  submit_form.submit
30
- pid
25
+ pid.to_s
31
26
  end
32
27
 
33
- def status(pid)
34
- page = get '/status.aspx?author=' + user
35
- status = (page / 'table.status tr').
36
- map{|tr| tr / 'td'}.
37
- find{|td| td[3] && td[3].inner_text.start_with?(pid)}
28
+ @@selector = 'table.status tr'
29
+ @@thead = [:id, :date, :user, :pname, :lang, :status, :testid, :time, :mem]
38
30
 
39
- return nil unless status
40
- ret = {}
41
- ths = [:id, :date, :user, :pname, :lang, :status, :testid, :time, :mem]
42
- ths.each_with_index do |k, i|
43
- ret[k] = status[i].inner_text.strip.gsub('\s+', ' ')
31
+ def status(pid)
32
+ url = '/status.aspx?author=' + user
33
+ status = parse_status url, @@selector, @@thead do |tr|
34
+ tr[3] && tr[3].inner_text.start_with?(pid)
44
35
  end
45
- if ret[:pname] =~ /^(\d+).\s*(.*)$/
46
- ret[:pid] = $1
47
- ret[:pname] = $2
36
+ if status[:pname] =~ /^(\d+).\s*(.*)$/
37
+ status[:pid], status[:pname] = $1, $2
48
38
  end
49
- url = status[5] / 'a[href]'
50
- ret[:url] = url.map{|a| a['href']} unless url.empty?
51
- ret
39
+ status
52
40
  end
53
41
  end
54
42
  end
@@ -1,3 +1,3 @@
1
1
  module OJAgent
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.4'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ojagent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-06 00:00:00.000000000 Z
12
+ date: 2013-01-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mechanize
@@ -94,9 +94,13 @@ files:
94
94
  - README.md
95
95
  - Rakefile
96
96
  - bin/quicksubmit
97
+ - examples/hdoj3337.rb
98
+ - examples/rosalind.rb
97
99
  - lib/ojagent.rb
100
+ - lib/ojagent/hdoj_agent.rb
98
101
  - lib/ojagent/livearchive_agent.rb
99
102
  - lib/ojagent/ojagent.rb
103
+ - lib/ojagent/rosalind_agent.rb
100
104
  - lib/ojagent/timus_agent.rb
101
105
  - lib/ojagent/version.rb
102
106
  - ojagent.gemspec