uva-tools 0.0.1
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.
- 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: []
|