codeforces-viewer 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f84c5a69101037d7e82b4e19d1f70859bc1a7faa
4
+ data.tar.gz: 2982dccf14455c2c16c26bd109bcdd27c4a351e5
5
+ SHA512:
6
+ metadata.gz: 6e678360a4b164df4d2b49be5f552afacd187068489f3f85e9d5baa776953e57127794fe09645d7ba4039a2f47096a2883263c27ac3dc3ebc9aaf30da63759f8
7
+ data.tar.gz: 85cba4d0d3462c23f6d2985371c3ac822b9e397fdea288f9dc50c5a2bcf5154740c579809dbebe0164e4f441f1a40cc9fe671b5bb4432ef6dc49672277ea2103
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .cache
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in codeforces-viewer.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Hiroyuki Sano
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Codeforces::Viewer
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'codeforces-viewer'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install codeforces-viewer
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/codeforces-viewer/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/codeforces/viewer/application'
4
+
5
+ app = Codeforces::Viewer::Application.new
6
+ app.parse_options ARGV
7
+ app.show
8
+
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'codeforces/viewer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "codeforces-viewer"
8
+ spec.version = Codeforces::Viewer::VERSION
9
+ spec.authors = ["Hiroyuki Sano"]
10
+ spec.email = ["sh19910711@gmail.com"]
11
+ spec.summary = %q{A simple command-line viewer for Codeforces}
12
+ spec.description = %q{A simple command-line viewer for Codeforces}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "nokogiri"
22
+ spec.add_dependency "colorize"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.5"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "webmock"
28
+ spec.add_development_dependency "fakefs"
29
+ end
@@ -0,0 +1,67 @@
1
+ require_relative 'version'
2
+ require_relative 'viewer'
3
+ require 'optparse'
4
+
5
+ module Codeforces
6
+ module Viewer
7
+ class Application
8
+ attr_accessor :option
9
+
10
+ def initialize
11
+ @option = {
12
+ :contest_id => nil,
13
+ :problem_id => nil,
14
+ :input_only => false,
15
+ :output_only => false,
16
+ :cache => true,
17
+ }
18
+ end
19
+
20
+ def parse_options(argv)
21
+ OptionParser.new do |option_parser|
22
+ option_parser.banner = "Usage: codeforces_viewer -c {contest-id} -p {problem-id} [options]"
23
+ option_parser.separator ""
24
+ option_parser.version = Codeforces::Viewer::VERSION
25
+
26
+ # contest id
27
+ option_parser.on('-c contest-id', '--contest-id contest-id', 'specify codeforces contest id (e.g. 100, 99)', String) {|contest_id| @option[:contest_id] = contest_id }
28
+
29
+ # problem_id
30
+ option_parser.on('-p problem-id', '--problem-id problem-id', 'specify codeforces problem id (e.g. A, B)', String) {|problem_id| @option[:problem_id] = problem_id }
31
+
32
+ option_parser.separator ""
33
+
34
+ # show input only
35
+ option_parser.on('-i input-no', '--input input-no', 'specify sample input id (0 is all)', Integer) {|flag| @option[:input_only] = flag }
36
+
37
+ # show output only
38
+ option_parser.on('-o input-no', '--output input-no', 'specify sample output id (0 is all)', Integer) {|flag| @option[:output_only] = flag }
39
+
40
+ option_parser.separator ""
41
+
42
+ # no cache
43
+ option_parser.on('--no-cache', 'no cache html files') {|flag| @option[:cache] = flag }
44
+
45
+ option_parser.separator ""
46
+
47
+ # parse
48
+ option_parser.parse! argv
49
+ end
50
+
51
+ # check
52
+ if @option[:contest_id].nil? || @option[:contest_id] == ""
53
+ abort "Error: contest id must be specified"
54
+ end
55
+ if @option[:problem_id].nil? || @option[:problem_id] == ""
56
+ abort "Error: problem id must be specified"
57
+ end
58
+ end
59
+
60
+ def show
61
+ viewer = Codeforces::Viewer::Viewer.new @option
62
+ viewer.show
63
+ end
64
+ end
65
+ end
66
+ end
67
+
@@ -0,0 +1,38 @@
1
+ require_relative 'constants'
2
+
3
+ require 'digest/md5'
4
+ require 'fileutils'
5
+ require 'net/http'
6
+ require 'uri'
7
+
8
+ module Codeforces
9
+ module Viewer
10
+ class Cacher
11
+ attr_accessor :option
12
+
13
+ def initialize(enabled = true, cache_dir = DEFAULT_CACHE_DIR)
14
+ @option = {}
15
+ @option[:enabled] = enabled
16
+ if @option[:enabled]
17
+ @option[:cache_dir] = File.expand_path cache_dir
18
+ FileUtils.mkdir_p @option[:cache_dir]
19
+ end
20
+ end
21
+
22
+ def get_url(url)
23
+ file_path = "#{@option[:cache_dir]}/#{Digest::MD5.hexdigest url}"
24
+ if @option[:enabled] && File.exists?(file_path)
25
+ File.read file_path
26
+ else
27
+ body = Net::HTTP.get URI.parse url
28
+ if @option[:enabled]
29
+ FileUtils.touch file_path
30
+ File.write file_path, body
31
+ end
32
+ body
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
@@ -0,0 +1,6 @@
1
+ module Codeforces
2
+ module Viewer
3
+ DEFAULT_CACHE_DIR="~/.codeforces-viewer/cache"
4
+ end
5
+ end
6
+
@@ -0,0 +1,110 @@
1
+ require 'colorize'
2
+ require 'nokogiri'
3
+
4
+ module Codeforces
5
+ module Viewer
6
+ class Render
7
+ def render_list_item(depth, doc, number = false)
8
+ cnt = 0
9
+ doc.children.each do |item|
10
+ case item.name
11
+ when "ol", "ul"
12
+ item = render_list(depth, item)
13
+ when "li"
14
+ if number
15
+ cnt += 1
16
+ item.content = "#{" " * depth}#{cnt}. #{item.text}\n"
17
+ else
18
+ item.content = "#{" " * depth}* #{item.text}\n"
19
+ end
20
+ end
21
+ end
22
+ doc
23
+ end
24
+
25
+ def render_list(depth, doc)
26
+ case doc.name
27
+ when "ol"
28
+ doc = render_list_item(depth + 2, doc, true)
29
+ when "ul"
30
+ doc = render_list_item(depth + 2, doc)
31
+ end
32
+ doc.content = "#{doc.text}\n"
33
+ doc
34
+ end
35
+
36
+ def render_normal_tag(doc)
37
+ case doc.name
38
+ when "div", "pre"
39
+ doc.content = "\n#{doc.content}\n"
40
+ when "p"
41
+ doc.content = "\n\n#{doc.content}\n\n"
42
+ when "ol"
43
+ doc = render_list(0, doc)
44
+ when "br"
45
+ doc.content = "\n"
46
+ when "sup"
47
+ doc.content = "^#{doc.content}"
48
+ when "sub"
49
+ doc.content = "[#{doc.content}]"
50
+ when "img"
51
+ doc.content = "\n!! Image File: #{doc["src"]}\n\n"
52
+ end
53
+ doc
54
+ end
55
+
56
+ def render_header_class(doc)
57
+ case doc["class"]
58
+ when "title", "section-title"
59
+ doc.content = "# #{doc.text.strip}".colorize(:mode => :bold)
60
+ when "tex-span", "tex-font-style-tt"
61
+ doc.content = doc.text.strip.colorize(:mode => :bold)
62
+ when "property-title"
63
+ doc.content = doc.text.strip.colorize(:mode => :underline)
64
+ end
65
+ doc
66
+ end
67
+
68
+ def render_header(doc)
69
+ doc = render_header_class(doc)
70
+ if doc.children.length > 0
71
+ doc.children.map {|item| render_header item }
72
+ end
73
+ doc = render_normal_tag(doc)
74
+ doc
75
+ end
76
+
77
+ def render(doc)
78
+ if doc.children.length > 0
79
+ doc.children.map {|item| render item }
80
+ end
81
+ doc = render_normal_tag(doc)
82
+ doc = render_header_class(doc)
83
+ doc
84
+ end
85
+
86
+ def render_html(html)
87
+ render(Nokogiri::HTML.fragment(html)).text
88
+ end
89
+
90
+ def render_input(input_id, doc)
91
+ input_id = input_id.to_i
92
+ if input_id == 0
93
+ doc.xpath('./div[@class="input"]/pre').map {|item| render item }
94
+ else
95
+ [render(doc.xpath('./div[@class="input"]/pre')[input_id - 1])]
96
+ end
97
+ end
98
+
99
+ def render_output(output_id, doc)
100
+ output_id = output_id.to_i
101
+ if output_id == 0
102
+ doc.xpath('./div[@class="output"]/pre').map {|item| render item }
103
+ else
104
+ [render(doc.xpath('./div[@class="output"]/pre')[output_id - 1])]
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
@@ -0,0 +1,9 @@
1
+ module Codeforces
2
+ module Viewer
3
+ module Utils
4
+ def self.get_problem_url contest_id, problem_id
5
+ "http://codeforces.com/contest/#{contest_id}/problem/#{problem_id}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Codeforces
2
+ module Viewer
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,112 @@
1
+ require_relative 'version'
2
+ require_relative 'render'
3
+ require_relative 'cacher'
4
+ require_relative 'utils'
5
+
6
+ require 'nokogiri'
7
+
8
+ module Codeforces
9
+ module Viewer
10
+ class Viewer
11
+ def initialize(option = {})
12
+ @option = option
13
+ @render = Codeforces::Viewer::Render.new
14
+ @cacher = Codeforces::Viewer::Cacher.new @option[:cache]
15
+ end
16
+
17
+ # fetch problem text
18
+ def fetch_problem_text(contest_id, problem_id)
19
+ url = Codeforces::Viewer::Utils.get_problem_url(contest_id, problem_id)
20
+ body = @cacher.get_url url
21
+ doc = Nokogiri::HTML(body)
22
+ problem_statement = doc.xpath('//div[@class="problem-statement"]')
23
+
24
+ div_list = problem_statement.xpath('./div')
25
+
26
+ res = {}
27
+ res[:round] = get_round_info(contest_id, doc)
28
+ res[:info] = get_problem_info(div_list[0])
29
+ res[:body] = @render.render(div_list[1]).text
30
+ res[:input] = @render.render(div_list[2]).text
31
+ res[:output] = @render.render(div_list[3]).text
32
+ res[:sample_test] = @render.render(div_list[4]).text
33
+ if div_list.length >= 6
34
+ res[:note] = @render.render(div_list[5]).text
35
+ else
36
+ res[:note] = ""
37
+ end
38
+ res
39
+ end
40
+
41
+ def fetch_input(input_id, contest_id, problem_id)
42
+ url = Codeforces::Viewer::Utils.get_problem_url(contest_id, problem_id)
43
+ body = @cacher.get_url url
44
+ doc = Nokogiri::HTML(body)
45
+ @render.render_input(input_id, doc.xpath('//div[@class="sample-test"]')).map {|item| item.text.strip + "\n" }.join
46
+ end
47
+
48
+ def fetch_output(output_id, contest_id, problem_id)
49
+ url = Codeforces::Viewer::Utils.get_problem_url(contest_id, problem_id)
50
+ body = @cacher.get_url url
51
+ doc = Nokogiri::HTML(body)
52
+ @render.render_output(output_id, doc.xpath('//div[@class="sample-test"]')).map {|item| item.text.strip + "\n" }.join
53
+ end
54
+
55
+ def get_round_info(contest_id, doc)
56
+ doc.xpath("//table//a[@href='/contest/#{contest_id}']").text.strip
57
+ end
58
+
59
+ # get title and other info
60
+ def get_problem_info(doc)
61
+ res = {
62
+ :title => @render.render_header(doc.xpath('//div[@class="title"]')[0]).text,
63
+ :time_limit => @render.render_header(doc.xpath('//div[@class="time-limit"]')[0]).text,
64
+ :memory_limit => @render.render_header(doc.xpath('//div[@class="memory-limit"]')[0]).text,
65
+ :input_file => @render.render_header(doc.xpath('//div[@class="input-file"]')[0]).text,
66
+ :output_file => @render.render_header(doc.xpath('//div[@class="output-file"]')[0]).text,
67
+ }
68
+ res
69
+ end
70
+
71
+ def show()
72
+ contest_id = @option[:contest_id]
73
+ problem_id = @option[:problem_id]
74
+
75
+
76
+ if @option[:input_only]
77
+ puts fetch_input(@option[:input_only], contest_id, problem_id)
78
+ elsif @option[:output_only]
79
+ puts fetch_output(@option[:output_only], contest_id, problem_id)
80
+ else
81
+ ret = fetch_problem_text contest_id, problem_id
82
+ puts "# #{ret[:round]}"
83
+ puts "URL: #{Codeforces::Viewer::Utils.get_problem_url(contest_id, problem_id)}"
84
+ print ret[:info][:title]
85
+ print ret[:info][:time_limit]
86
+ print ret[:info][:memory_limit]
87
+ print ret[:info][:input_file]
88
+ print ret[:info][:output_file]
89
+ puts ""
90
+ puts ""
91
+ puts " * * * * *"
92
+ puts ""
93
+ puts ret[:body]
94
+ puts ""
95
+ puts " * * * * *"
96
+ puts ""
97
+ puts ret[:input]
98
+ puts ret[:output]
99
+ puts ""
100
+ puts " * * * * *"
101
+ puts ""
102
+ puts ret[:sample_test]
103
+ puts ""
104
+ puts " * * * * *"
105
+ puts ""
106
+ puts ret[:note]
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
@@ -0,0 +1,5 @@
1
+ require_relative 'viewer/application'
2
+ require_relative 'viewer/viewer'
3
+ require_relative 'viewer/cacher'
4
+ require_relative 'viewer/render'
5
+ require_relative 'viewer/version'
@@ -0,0 +1,37 @@
1
+ <html>
2
+ <body>
3
+ <table class="rtable ">
4
+ <tr>
5
+ <td>
6
+ <a style="color: black" href="/contest/350">Codeforces Round #203 (Div. 2)</a>
7
+ </td>
8
+ </tr>
9
+ </table>
10
+ <div class="ttypography">
11
+ <div class="problem-statement">
12
+ <div class="header">
13
+ <div class="title">A. TL</div>
14
+ <div class="time-limit"><div class="property-title">time limit per test</div>2 seconds</div>
15
+ <div class="memory-limit"><div class="property-title">memory limit per test</div>256 megabytes</div>
16
+ <div class="input-file"><div class="property-title">input</div>standard input</div>
17
+ <div class="output-file"><div class="property-title">output</div>standard output</div>
18
+ </div>
19
+ <div>
20
+ <p>Valera wanted to prepare a Codesecrof round. He's already got one problem and he wants to set a time limit (TL) on it.</p><p>Valera has written <span class="tex-span"><i>n</i></span> correct solutions. For each correct solution, he knows its running time (in seconds). Valera has also wrote <span class="tex-span"><i>m</i></span> wrong solutions and for each wrong solution he knows its running time (in seconds).</p><p>Let's suppose that Valera will set <span class="tex-span"><i>v</i></span> seconds TL in the problem. Then we can say that a solution passes the system testing if its running time is at most <span class="tex-span"><i>v</i></span> seconds. We can also say that a solution passes the system testing with some &quot;extra&quot; time if for its running time, <span class="tex-span"><i>a</i></span> seconds, an inequality <span class="tex-span">2<i>a</i> ≤ <i>v</i></span> holds.</p><p>As a result, Valera decided to set <span class="tex-span"><i>v</i></span> seconds TL, that the following conditions are met:</p><ol> <li> <span class="tex-span"><i>v</i></span> is a positive integer; </li><li> all correct solutions pass the system testing; </li><li> at least one correct solution passes the system testing with some &quot;extra&quot; time; </li><li> all wrong solutions do not pass the system testing; </li><li> value <span class="tex-span"><i>v</i></span> is minimum among all TLs, for which points <span class="tex-span">1</span>, <span class="tex-span">2</span>, <span class="tex-span">3</span>, <span class="tex-span">4</span> hold. </li></ol><p>Help Valera and find the most suitable TL or else state that such TL doesn't exist.</p></div>
21
+ <div class="input-specification">
22
+ <div class="section-title">Input</div><p>The first line contains two integers <span class="tex-span"><i>n</i></span>, <span class="tex-span"><i>m</i></span> (<span class="tex-span">1 ≤ <i>n</i>, <i>m</i> ≤ 100</span>). The second line contains <span class="tex-span"><i>n</i></span> space-separated positive integers <span class="tex-span"><i>a</i><sub class="lower-index">1</sub>, <i>a</i><sub class="lower-index">2</sub>, ..., <i>a</i><sub class="lower-index"><i>n</i></sub></span> (<span class="tex-span">1 ≤ <i>a</i><sub class="lower-index"><i>i</i></sub> ≤ 100</span>) — the running time of each of the <span class="tex-span"><i>n</i></span> correct solutions in seconds. The third line contains <span class="tex-span"><i>m</i></span> space-separated positive integers <span class="tex-span"><i>b</i><sub class="lower-index">1</sub>, <i>b</i><sub class="lower-index">2</sub>, ..., <i>b</i><sub class="lower-index"><i>m</i></sub></span> (<span class="tex-span">1 ≤ <i>b</i><sub class="lower-index"><i>i</i></sub> ≤ 100</span>) — the running time of each of <span class="tex-span"><i>m</i></span> wrong solutions in seconds. </p></div>
23
+ <div class="output-specification">
24
+ <div class="section-title">Output</div><p>If there is a valid TL value, print it. Otherwise, print -1.</p></div>
25
+ <div class="sample-tests">
26
+ <div class="section-title">Sample test(s)</div>
27
+ <div class="sample-test">
28
+ <div class="input"><div class="title">Input</div><pre>3 6<br />4 5 2<br />8 9 6 10 7 11<br /></pre></div>
29
+ <div class="output"><div class="title">Output</div><pre>5</pre></div>
30
+ <div class="input"><div class="title">Input</div><pre>3 1<br />3 4 5<br />6<br /></pre>
31
+ </div>
32
+ <div class="output"><div class="title">Output</div><pre>-1<br /></pre></div></div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ </body>
37
+ </html>
@@ -0,0 +1,59 @@
1
+ <html>
2
+ <body>
3
+ <table class="rtable ">
4
+ <tr>
5
+ <td>
6
+ <div><a style="color: black" href="/contest/365">Codeforces Round #213 (Div. 2)</a></div>
7
+ </td>
8
+ </tr>
9
+ </table>
10
+ <div class="ttypography">
11
+ <div class="problem-statement">
12
+ <div class="header">
13
+ <div class="title">
14
+ A. Good Number
15
+ </div>
16
+ <div class="time-limit"><div class="property-title">time limit per test</div>1 second</div>
17
+ <div class="memory-limit"><div class="property-title">memory limit per test</div>256 megabytes</div>
18
+ <div class="input-file"><div class="property-title">input</div>standard input</div>
19
+ <div class="output-file"><div class="property-title">output</div>standard output</div>
20
+ </div>
21
+
22
+ <div><p>Let's call a number <span class="tex-span"><i>k</i></span>-good if it contains all digits not exceeding <span class="tex-span"><i>k</i></span> (<span class="tex-span">0, ..., <i>k</i></span>). You've got a number <span class="tex-span"><i>k</i></span> and an array <span class="tex-span"><i>a</i></span> containing <span class="tex-span"><i>n</i></span> numbers. Find out how many <span class="tex-span"><i>k</i></span>-good numbers are in <span class="tex-span"><i>a</i></span> (count each number every time it occurs in array <span class="tex-span"><i>a</i></span>).</p></div>
23
+ <div class="input-specification">
24
+ <div class="section-title">Input</div>
25
+ <p>The first line contains integers <span class="tex-span"><i>n</i></span> and <span class="tex-span"><i>k</i></span> (<span class="tex-span">1 ≤ <i>n</i> ≤ 100</span>, <span class="tex-span">0 ≤ <i>k</i> ≤ 9</span>). The <span class="tex-span"><i>i</i></span>-th of the following <span class="tex-span"><i>n</i></span> lines contains integer <span class="tex-span"><i>a</i><sub class="lower-index"><i>i</i></sub></span> without leading zeroes (<span class="tex-span">1 ≤ <i>a</i><sub class="lower-index"><i>i</i></sub> ≤ 10<sup class="upper-index">9</sup></span>).</p>
26
+ </div>
27
+ <div class="output-specification">
28
+ <div class="section-title">Output</div>
29
+ <p>Print a single integer — the number of <span class="tex-span"><i>k</i></span>-good numbers in <span class="tex-span"><i>a</i></span>.</p>
30
+ </div>
31
+
32
+ <div class="sample-tests">
33
+ <div class="section-title">Sample test(s)
34
+ </div>
35
+ <div class="sample-test">
36
+ <div class="input">
37
+ <div class="title">Input</div><pre>10 6<br />1234560<br />1234560<br />1234560<br />1234560<br />1234560<br />1234560<br />1234560<br />1234560<br />1234560<br />1234560<br /></pre>
38
+ </div>
39
+
40
+ <div class="output">
41
+ <div class="title">Output</div>
42
+ <pre>10<br /></pre>
43
+ </div>
44
+
45
+ <div class="input">
46
+ <div class="title">Input</div>
47
+ <pre>2 1<br />1<br />10<br /></pre>
48
+ </div>
49
+
50
+ <div class="output">
51
+ <div class="title">Output</div>
52
+ <pre>1<br /></pre>
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </body>
59
+ </html>
@@ -0,0 +1,22 @@
1
+ require 'codeforces/viewer'
2
+
3
+ require 'fakefs/safe'
4
+ require 'fakefs/spec_helpers'
5
+
6
+ RSpec.configure do |config|
7
+ config.include FakeFS::SpecHelpers
8
+ end
9
+
10
+ require 'webmock'
11
+ WebMock.disable_net_connect!
12
+
13
+ module SpecHelpers
14
+ def self.read_file array_of_path
15
+ File.read get_path(array_of_path)
16
+ end
17
+
18
+ def self.get_path array_of_path
19
+ File.expand_path(File.join(File.dirname(__FILE__), File.join(array_of_path)))
20
+ end
21
+ end
22
+
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe Codeforces::Viewer::Render do
4
+ before do
5
+ @render = Codeforces::Viewer::Render.new
6
+ end
7
+
8
+ context :render_html do
9
+ context :sup do
10
+ it "<sup>" do
11
+ expect(@render.render_html("x<sup>y</sup>")).to eq "x^y"
12
+ end
13
+ it "<sup class>" do
14
+ expect(@render.render_html("x<sup class>y</sup>")).to eq "x^y"
15
+ end
16
+ it "<sup><sup>" do
17
+ expect(@render.render_html("x<sup>y</sup><sup>z</sup>")).to eq "x^y^z"
18
+ end
19
+ end
20
+
21
+ context :sub do
22
+ it "<sub>" do
23
+ expect(@render.render_html("A<sub>i</sub>")).to eq "A[i]"
24
+ end
25
+ it "<sub class>" do
26
+ expect(@render.render_html("A<sub class>i</sub>")).to eq "A[i]"
27
+ end
28
+ it "span sub" do
29
+ html = '<span class="tex-span">1 ≤ <i>a</i><sub class="lower-index"><i>i</i></sub> ≤ 100</span>'
30
+ expect(@render.render_html(html)).to include "1 ≤ a[i] ≤ 100"
31
+ end
32
+ end
33
+
34
+ context :div do
35
+ it "<div>" do
36
+ expect(@render.render_html("A<div>B</div>C")).to eq "A\nB\nC"
37
+ end
38
+ it "<div class>" do
39
+ expect(@render.render_html("A<div>B</div>C")).to eq "A\nB\nC"
40
+ end
41
+ end
42
+
43
+ context :p do
44
+ it "<p>" do
45
+ expect(@render.render_html("A<p>B</p>C")).to eq "A\n\nB\n\nC"
46
+ end
47
+ it "<p class>" do
48
+ expect(@render.render_html("A<p class>B</p>C")).to eq "A\n\nB\n\nC"
49
+ end
50
+ end
51
+
52
+ context :list do
53
+ it "<ol>" do
54
+ expect(@render.render_html("<ol><li>1</li><li>2</li><li>3</li></ol>")).to eq " 1. 1\n 2. 2\n 3. 3\n\n"
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Codeforces::Viewer::Viewer do
4
+ before do
5
+ @viewer = Codeforces::Viewer::Viewer.new
6
+ end
7
+
8
+ before do
9
+ FakeFS.deactivate!
10
+ dummy_response_365A = SpecHelpers.read_file ['mock', 'problem_text_365A.html']
11
+ dummy_response_350A = SpecHelpers.read_file ['mock', 'problem_text_350A.html']
12
+ FakeFS.activate!
13
+ WebMock.stub_request(:get, /http:\/\/codeforces\.com\/contest\/[0-9]*?\/problem/).to_return(
14
+ :body => dummy_response_365A,
15
+ )
16
+ WebMock.stub_request(:get, /http:\/\/codeforces\.com\/contest\/350\/problem\/A/).to_return(
17
+ :body => dummy_response_350A,
18
+ )
19
+ end
20
+
21
+ context :fetch_problem_text do
22
+ subject(:ret) { @viewer.fetch_problem_text '350', 'A' }
23
+ it { ret[:round].should eq "Codeforces Round #203 (Div. 2)" }
24
+ it { ret[:body].should include "Valera" }
25
+ end
26
+
27
+ context :get_round_info do
28
+ it do
29
+ url = Codeforces::Viewer::Utils.get_problem_url '350', 'A'
30
+ body = Net::HTTP.get URI.parse url
31
+ doc = Nokogiri::HTML(body)
32
+ expect(@viewer.get_round_info('350', doc)).to eq 'Codeforces Round #203 (Div. 2)'
33
+ end
34
+ it do
35
+ url = Codeforces::Viewer::Utils.get_problem_url '365', 'A'
36
+ body = Net::HTTP.get URI.parse url
37
+ doc = Nokogiri::HTML(body)
38
+ expect(@viewer.get_round_info('365', doc)).to eq 'Codeforces Round #213 (Div. 2)'
39
+ end
40
+ end
41
+ end
42
+
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Codeforces::Viewer::Cacher do
4
+ before do
5
+ @cacher = Codeforces::Viewer::Cacher.new true, ".cache"
6
+ end
7
+
8
+ context :cache do
9
+ before do
10
+ WebMock.stub_request(:get, /^http:\/\/foo\/bar$/).to_return(
11
+ :body => 'this is test',
12
+ )
13
+ end
14
+
15
+ it "enable cache: http://foo/bar" do
16
+ url = "http://foo/bar"
17
+ ret = @cacher.get_url url
18
+ expect(ret).to eq File.read ".cache/#{Digest::MD5.hexdigest(url)}"
19
+ end
20
+
21
+ it "disable cache: http://foo/bar" do
22
+ @cacher = Codeforces::Viewer::Cacher.new false
23
+ url = "http://foo/bar"
24
+ ret = @cacher.get_url url
25
+ expect { File.read(".cache/#{Digest::MD5.hexdigest(url)}") }.to raise_error
26
+ end
27
+ end
28
+ end
29
+
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: codeforces-viewer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Hiroyuki Sano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: fakefs
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: A simple command-line viewer for Codeforces
112
+ email:
113
+ - sh19910711@gmail.com
114
+ executables:
115
+ - codeforces-viewer
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - bin/codeforces-viewer
125
+ - codeforces-viewer.gemspec
126
+ - lib/codeforces/viewer.rb
127
+ - lib/codeforces/viewer/application.rb
128
+ - lib/codeforces/viewer/cacher.rb
129
+ - lib/codeforces/viewer/constants.rb
130
+ - lib/codeforces/viewer/render.rb
131
+ - lib/codeforces/viewer/utils.rb
132
+ - lib/codeforces/viewer/version.rb
133
+ - lib/codeforces/viewer/viewer.rb
134
+ - spec/mock/problem_text_350A.html
135
+ - spec/mock/problem_text_365A.html
136
+ - spec/spec_helper.rb
137
+ - spec/test/t2u9hw5_render_spec.rb
138
+ - spec/test/tirgu7u_viewer_spec.rb
139
+ - spec/test/tukgi3p_cacher_spec.rb
140
+ homepage: ''
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.2.0
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: A simple command-line viewer for Codeforces
164
+ test_files:
165
+ - spec/mock/problem_text_350A.html
166
+ - spec/mock/problem_text_365A.html
167
+ - spec/spec_helper.rb
168
+ - spec/test/t2u9hw5_render_spec.rb
169
+ - spec/test/tirgu7u_viewer_spec.rb
170
+ - spec/test/tukgi3p_cacher_spec.rb