uva-tools 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +1 -0
- data/lib/uva-tools/problem.rb +124 -0
- data/lib/uva-tools/user.rb +80 -0
- data/lib/uva-tools/uva-tools.rb +108 -0
- data/lib/uva-tools/version.rb +3 -0
- data/lib/uva-tools.rb +7 -0
- data/uva-tools.gemspec +19 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 600ae5264d13d0c083a5ad143e01f6cd5cd3b180
|
4
|
+
data.tar.gz: c13486119816dc8ad210072915efac90142d6256
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5d565deb6a25120c1f19a66d640f7e060055b28ba31a6abc1ee01457ff0c5da25bf08b9678e51f309ca0c9be57fb05a7329f296e3b125638b4853711c63c9e86
|
7
|
+
data.tar.gz: 55be55d88c394e2570361d3508dcc506a626308f55fdc0136968ca98beed12bc8a2efa1c52cda3d9af0055b876a84a299194eb627eae2f9468d4d33657dd1d20
|
data/.gitignore
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Henning Koch
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# UVa Tools
|
@@ -0,0 +1,124 @@
|
|
1
|
+
=begin
|
2
|
+
0: Problem ID
|
3
|
+
1: Problem Number
|
4
|
+
2: Problem Title
|
5
|
+
3: Number of Distinct Accepted User (DACU)
|
6
|
+
4: Best Runtime of an Accepted Submission
|
7
|
+
5: Best Memory used of an Accepted Submission
|
8
|
+
6: Number of No Verdict Given (can be ignored)
|
9
|
+
7: Number of Submission Error
|
10
|
+
8: Number of Can't be Judged
|
11
|
+
9: Number of In Queue
|
12
|
+
10: Number of Compilation Error
|
13
|
+
11: Number of Restricted Function
|
14
|
+
12: Number of Runtime Error
|
15
|
+
13: Number of Output Limit Exceeded
|
16
|
+
14: Number of Time Limit Exceeded
|
17
|
+
15: Number of Memory Limit Exceeded
|
18
|
+
16: Number of Wrong Answer
|
19
|
+
17: Number of Presentation Error
|
20
|
+
18: Number of Accepted
|
21
|
+
19: Problem Run-Time Limit (milliseconds)
|
22
|
+
20: Problem Status (0 = unavailable, 1 = normal, 2 = special judge)
|
23
|
+
=end
|
24
|
+
|
25
|
+
module UVaTools
|
26
|
+
class Problem
|
27
|
+
def initialize(array)
|
28
|
+
@info = array
|
29
|
+
end
|
30
|
+
|
31
|
+
def id
|
32
|
+
@info[0]
|
33
|
+
end
|
34
|
+
|
35
|
+
def number
|
36
|
+
@info[1]
|
37
|
+
end
|
38
|
+
|
39
|
+
def title
|
40
|
+
@info[2]
|
41
|
+
end
|
42
|
+
|
43
|
+
def info
|
44
|
+
{
|
45
|
+
id: id,
|
46
|
+
number: number,
|
47
|
+
title: title,
|
48
|
+
run_time: @info[19]
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def submitted
|
53
|
+
@info[6..18].inject(:+)
|
54
|
+
end
|
55
|
+
|
56
|
+
def accepted
|
57
|
+
@info[18]
|
58
|
+
end
|
59
|
+
|
60
|
+
def dacu
|
61
|
+
@info[3]
|
62
|
+
end
|
63
|
+
|
64
|
+
def submission_info
|
65
|
+
{
|
66
|
+
submitted: submitted,
|
67
|
+
accepted: accepted,
|
68
|
+
dacu: dacu
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
def download
|
73
|
+
unless downloaded?
|
74
|
+
FileUtils::mkdir_p dir_name
|
75
|
+
Dir.chdir(dir_name) do
|
76
|
+
uri = URI("https://uva.onlinejudge.org/external/#{number/100}/#{number}.html")
|
77
|
+
source = Net::HTTP.get(uri)
|
78
|
+
if source.include? "URL=p#{number}.pdf"
|
79
|
+
File.open("#{number.to_s}.pdf", 'w') do |pdf|
|
80
|
+
pdf.write open("https://uva.onlinejudge.org/external/#{number/100}/p#{number}.pdf").read
|
81
|
+
end
|
82
|
+
else
|
83
|
+
File.open("#{number.to_s}.html", 'w') { |f| f.write source }
|
84
|
+
|
85
|
+
source.scan(/#{number}img\d{1,3}\.[a-zA-Z]+/).uniq.each do |picture|
|
86
|
+
File.open(picture, 'wb') do |pic_file|
|
87
|
+
pic_file.write open("https://uva.onlinejudge.org/external/#{number/100}/#{picture}").read
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
puts "downloaded: #{number}"
|
93
|
+
true
|
94
|
+
else
|
95
|
+
puts "#{number} was already downloaded"
|
96
|
+
false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def remove
|
101
|
+
if downloaded?
|
102
|
+
Dir.chdir(dir_name) do
|
103
|
+
Dir.entries('.').each do |file_name|
|
104
|
+
if file_name =~ /^#{number}.*/ && !File.directory?(file_name)
|
105
|
+
File.delete(file_name)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
puts "removed #{number}"
|
110
|
+
else
|
111
|
+
puts "#{number} wasn't downloaded"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def downloaded?
|
116
|
+
File.directory?(dir_name) && (File.exists?("#{dir_name}/#{number}.html") || File.exists?("#{dir_name}/#{number}.pdf"))
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def dir_name
|
121
|
+
"#{ENV['HOME']}/uva-tools/#{number/100}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module UVaTools
|
2
|
+
class User
|
3
|
+
def initialize(username)
|
4
|
+
@username = username
|
5
|
+
end
|
6
|
+
|
7
|
+
def solved
|
8
|
+
solved_hash.values
|
9
|
+
end
|
10
|
+
|
11
|
+
def solved_by_number
|
12
|
+
solved_hash
|
13
|
+
end
|
14
|
+
|
15
|
+
def unsolved
|
16
|
+
@unsolved ||= begin
|
17
|
+
prob_by_id = UVaTools.problems_by_id
|
18
|
+
unsolved_pids.map do |pid|
|
19
|
+
prob_by_id[pid]
|
20
|
+
end.sort{ |a, b| b.dacu <=> a.dacu }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_solved?(prob_nums)
|
25
|
+
res = Array(prob_nums).map do |prob_num|
|
26
|
+
solved_by_number.has_key? prob_num
|
27
|
+
end
|
28
|
+
res.length < 2 ? res[0] : res
|
29
|
+
end
|
30
|
+
|
31
|
+
def reload
|
32
|
+
@solved_pids = nil
|
33
|
+
@solved = nil
|
34
|
+
@unsolved = nil
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def uid
|
40
|
+
@uid ||= begin
|
41
|
+
uri = URI("http://uhunt.felix-halim.net/api/uname2uid/#{@username}")
|
42
|
+
Net::HTTP.get(uri)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def solved_pids
|
47
|
+
@solved_pids ||= get_solved_pids
|
48
|
+
end
|
49
|
+
|
50
|
+
def solved_hash
|
51
|
+
@solved ||= begin
|
52
|
+
prob_by_id = UVaTools.problems_by_id
|
53
|
+
h = {}
|
54
|
+
solved_pids.each do |pid|
|
55
|
+
problem = prob_by_id[pid]
|
56
|
+
h[problem.number] = problem
|
57
|
+
end
|
58
|
+
h
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def reload_solved_pids
|
63
|
+
@solved_pids = get_solved_pids
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_solved_pids
|
67
|
+
uri = URI("http://uhunt.felix-halim.net/api/solved-bits/#{uid}")
|
68
|
+
res = JSON.parse(Net::HTTP.get(uri))[0]['solved']
|
69
|
+
res.each_with_index.map do |num, j|
|
70
|
+
num.to_s(2).reverse.scan(/./).each_with_index.map do |c, i|
|
71
|
+
j*32 + i if c == '1'
|
72
|
+
end.compact
|
73
|
+
end.flatten.sort
|
74
|
+
end
|
75
|
+
|
76
|
+
def unsolved_pids
|
77
|
+
UVaTools.problems.map(&:id) - solved_pids
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module UVaTools
|
2
|
+
class << self
|
3
|
+
def problems
|
4
|
+
problem_hash.values
|
5
|
+
end
|
6
|
+
|
7
|
+
def problems_by_number
|
8
|
+
problem_hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def problems_by_id
|
12
|
+
h = {}
|
13
|
+
problem_hash.values.each{ |p| h[p.id] = p }
|
14
|
+
h
|
15
|
+
end
|
16
|
+
|
17
|
+
def download_multiple(prob_nums, worker_count = 4)
|
18
|
+
to_download = Array(prob_nums).map do |prob_num|
|
19
|
+
problems_by_number[prob_num]
|
20
|
+
end
|
21
|
+
|
22
|
+
if to_download.length > 0
|
23
|
+
worker_count = [worker_count, to_download.length].min
|
24
|
+
workers = []
|
25
|
+
|
26
|
+
worker_count.times do
|
27
|
+
workers << worker(to_download)
|
28
|
+
end
|
29
|
+
|
30
|
+
reads = workers.map{|worker| worker[:read]}
|
31
|
+
writes = workers.map{|worker| worker[:write]}
|
32
|
+
|
33
|
+
index = 0
|
34
|
+
finished = 0
|
35
|
+
|
36
|
+
loop do
|
37
|
+
break if finished >= to_download.size
|
38
|
+
|
39
|
+
ready = IO.select(reads, writes)
|
40
|
+
|
41
|
+
ready[0].each do |readable|
|
42
|
+
data = Marshal.load(readable)
|
43
|
+
# assets.merge! data["assets"]
|
44
|
+
# files.merge! data["files"]
|
45
|
+
# paths_with_errors.merge! data["errors"]
|
46
|
+
finished += 1
|
47
|
+
end
|
48
|
+
|
49
|
+
ready[1].each do |write|
|
50
|
+
break if index >= to_download.size
|
51
|
+
|
52
|
+
Marshal.dump(index, write)
|
53
|
+
index += 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
workers.each do |worker|
|
58
|
+
worker[:read].close
|
59
|
+
worker[:write].close
|
60
|
+
end
|
61
|
+
|
62
|
+
workers.each do |worker|
|
63
|
+
Process.wait worker[:pid]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def worker(problems)
|
72
|
+
child_read, parent_write = IO.pipe
|
73
|
+
parent_read, child_write = IO.pipe
|
74
|
+
|
75
|
+
pid = fork do
|
76
|
+
begin
|
77
|
+
parent_write.close
|
78
|
+
parent_read.close
|
79
|
+
|
80
|
+
while !child_read.eof?
|
81
|
+
problem = problems[Marshal.load(child_read)]
|
82
|
+
problem.download
|
83
|
+
Marshal.dump(problem.number, child_write)
|
84
|
+
end
|
85
|
+
ensure
|
86
|
+
child_read.close
|
87
|
+
child_write.close
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
child_read.close
|
92
|
+
child_write.close
|
93
|
+
|
94
|
+
{:read => parent_read, :write => parent_write, :pid => pid}
|
95
|
+
end
|
96
|
+
|
97
|
+
def problem_hash
|
98
|
+
@@problems ||= begin
|
99
|
+
uri = URI("http://uhunt.felix-halim.net/api/p")
|
100
|
+
res = JSON.parse(Net::HTTP.get(uri))
|
101
|
+
|
102
|
+
h = {}
|
103
|
+
res.each{ |row| h[row[1]] = UVaTools::Problem.new(row) }
|
104
|
+
h
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/lib/uva-tools.rb
ADDED
data/uva-tools.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$: << File.expand_path('../lib', __FILE__)
|
3
|
+
require 'uva-tools/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.authors = "Dave Allie"
|
7
|
+
gem.email = "dave@daveallie.com"
|
8
|
+
gem.description = "Set of UVa Online tools"
|
9
|
+
gem.summary = gem.description
|
10
|
+
gem.homepage = "https://github.com/daveallie/uva-tools"
|
11
|
+
gem.license = 'MIT'
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.name = "uva-tools"
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
gem.version = UVaTools::VERSION
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: uva-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dave Allie
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-05 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Set of UVa Online tools
|
14
|
+
email: dave@daveallie.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- ".gitignore"
|
20
|
+
- MIT-LICENSE
|
21
|
+
- README.md
|
22
|
+
- lib/uva-tools.rb
|
23
|
+
- lib/uva-tools/problem.rb
|
24
|
+
- lib/uva-tools/user.rb
|
25
|
+
- lib/uva-tools/uva-tools.rb
|
26
|
+
- lib/uva-tools/version.rb
|
27
|
+
- uva-tools.gemspec
|
28
|
+
homepage: https://github.com/daveallie/uva-tools
|
29
|
+
licenses:
|
30
|
+
- MIT
|
31
|
+
metadata: {}
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements: []
|
47
|
+
rubyforge_project:
|
48
|
+
rubygems_version: 2.4.5.1
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: Set of UVa Online tools
|
52
|
+
test_files: []
|