label 0.1.6 → 0.2.0
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 +4 -4
- data/label.gemspec +0 -2
- data/lib/label.rb +29 -39
- data/lib/label/version.rb +1 -1
- data/spec/label/description_formatter_spec.rb +1 -0
- data/spec/label_spec.rb +31 -15
- data/spec/spec_helper.rb +0 -7
- metadata +3 -23
- data/lib/label/gemspec_info.rb +0 -76
- data/lib/label/summary_extractor.rb +0 -23
- data/spec/label/gemspec_info_spec.rb +0 -25
- data/spec/label/summary_extractor_spec.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69b062d913786723a28cb0fcf27ba5e2a614a4ea
|
4
|
+
data.tar.gz: 5c4e954723b928ac583a463bc956b05c28d7ea88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05fb43e1d46f8bb542eea2059efc4f3a3cadbeaee5c5a989bfd2c170048758b5816bd661540359dd17c711c3f6d0a3118843d6e6e975d8934f9cc47318b905b8
|
7
|
+
data.tar.gz: 798b20fc30a6211c587c8b13a824952686259ce6c8f0881a6fbc1df678958c56c1722647f344bb11f4d82cf8de0458b163dded6e36b45e7b40ce4129d877f44c
|
data/label.gemspec
CHANGED
@@ -18,8 +18,6 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "gems", "~> 0.8"
|
22
|
-
|
23
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
22
|
spec.add_development_dependency "rake"
|
25
23
|
spec.add_development_dependency "rspec"
|
data/lib/label.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
require "label/version"
|
2
|
-
require "label/gemspec_info"
|
3
2
|
require "label/description_formatter"
|
3
|
+
|
4
|
+
require "bundler"
|
4
5
|
require "optparse"
|
5
6
|
require "ostruct"
|
6
|
-
require "gems"
|
7
7
|
|
8
8
|
module Label
|
9
9
|
|
10
10
|
class << self
|
11
11
|
|
12
|
+
GEM_REGEXP = /^(?<whitespace> *)gem ['"](?<name>.+?)['"](:?, ['"](?<version>.+?)['"])?/
|
13
|
+
|
12
14
|
def label gemfile = "Gemfile"
|
13
|
-
describing = lambda { |
|
15
|
+
describing = lambda { |name| STDOUT.write "#{name}: " }
|
14
16
|
described = lambda { |description| STDOUT.puts description }
|
15
17
|
|
16
18
|
output = process gemfile, describing, described
|
@@ -33,21 +35,21 @@ module Label
|
|
33
35
|
processed_lines = []
|
34
36
|
|
35
37
|
lines.each_with_index do |line, i|
|
36
|
-
|
38
|
+
match = line.match GEM_REGEXP
|
37
39
|
|
38
|
-
if
|
40
|
+
if match
|
39
41
|
previous_line = lines[i - 1]
|
40
42
|
|
41
|
-
whitespace =
|
42
|
-
|
43
|
-
|
43
|
+
whitespace = match[:whitespace]
|
44
|
+
name = match[:name]
|
45
|
+
version = match[:version]
|
44
46
|
|
45
47
|
unless previous_line =~ /^ *#/
|
46
|
-
describing.call
|
48
|
+
describing.call(name) if describing
|
47
49
|
|
48
|
-
description = describe
|
50
|
+
description = describe(name, version)
|
49
51
|
|
50
|
-
described.call
|
52
|
+
described.call(description) if described
|
51
53
|
|
52
54
|
processed_lines << format(description, "#{whitespace}#")
|
53
55
|
end
|
@@ -78,43 +80,31 @@ module Label
|
|
78
80
|
|
79
81
|
# Describe the given gem.
|
80
82
|
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
# - rubygems
|
84
|
-
# - github
|
85
|
-
# - path
|
86
|
-
# - git
|
83
|
+
# name - A String with the name of a gem.
|
84
|
+
# version - A String describing the version of a gem.
|
87
85
|
#
|
88
86
|
# Returns a String.
|
89
|
-
def describe
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
info.summary
|
87
|
+
def describe name, version = nil
|
88
|
+
requirement = Gem::Requirement.new(version)
|
89
|
+
|
90
|
+
or_raise = -> do
|
91
|
+
raise Gem::LoadError.new("Could not find '#{name}' (#{requirement})")
|
95
92
|
end
|
93
|
+
|
94
|
+
specs.find or_raise do |spec|
|
95
|
+
spec.name == name &&
|
96
|
+
requirement.satisfied_by?(spec.version)
|
97
|
+
end.summary
|
96
98
|
end
|
97
99
|
|
98
100
|
private
|
99
101
|
|
100
|
-
def
|
101
|
-
|
102
|
+
def specs
|
103
|
+
@specs ||= Bundler.load.specs
|
102
104
|
end
|
103
105
|
|
104
|
-
|
105
|
-
|
106
|
-
# :rubygems is the default
|
107
|
-
def extract_source_and_options line
|
108
|
-
source = {}
|
109
|
-
options = line.split ","
|
110
|
-
options[1, options.length - 1].each do |option|
|
111
|
-
if option.match(/:/)
|
112
|
-
args = option.split(":").map {|arg| arg.strip.gsub(/('|\")/, '') }
|
113
|
-
source[args.first.to_sym] = args.last
|
114
|
-
end
|
115
|
-
end
|
116
|
-
source[:rubygems] = true if source.empty?
|
117
|
-
source
|
106
|
+
def format description, prepend_string
|
107
|
+
DescriptionFormatter.format description, prepend_string
|
118
108
|
end
|
119
109
|
|
120
110
|
end
|
data/lib/label/version.rb
CHANGED
data/spec/label_spec.rb
CHANGED
@@ -1,23 +1,24 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
2
3
|
require "spec_helper"
|
3
4
|
|
4
5
|
describe Label do
|
5
6
|
describe "#process" do
|
6
|
-
it "
|
7
|
+
it "labels unlabelled gems" do
|
7
8
|
allow(File).to receive(:open).with("Gemfile").and_return(StringIO.new fixture("stock_gemfile"))
|
8
9
|
|
9
|
-
allow(subject).to receive(:describe).with("rspec",
|
10
|
+
allow(subject).to receive(:describe).with("rspec", nil).and_return("BDD for Ruby")
|
10
11
|
|
11
|
-
allow(subject).to receive(:describe).with("carrierwave",
|
12
|
+
allow(subject).to receive(:describe).with("carrierwave", nil).and_return(
|
12
13
|
"Upload files in your Ruby applications, map them to a range of ORMs, " +
|
13
14
|
"store them on different backends."
|
14
15
|
)
|
15
16
|
|
16
|
-
allow(subject).to receive(:describe).with("label",
|
17
|
+
allow(subject).to receive(:describe).with("label", nil).and_return(
|
17
18
|
"Label labels the gems in your Gemfile"
|
18
19
|
)
|
19
20
|
|
20
|
-
allow(subject).to receive(:describe).with("pg",
|
21
|
+
allow(subject).to receive(:describe).with("pg", nil).and_return(
|
21
22
|
"Pg is the Ruby interface to the {PostgreSQL RDBMS}[http://www.postgresql.org/].\n\n"+
|
22
23
|
"It works with {PostgreSQL 8.4 and later}[http://www.postgresql.org/support/versioning/]."+
|
23
24
|
"\n\nA small example usage:\n\n #!/usr/bin/env ruby\n\n require 'pg'\n\n"+
|
@@ -28,7 +29,7 @@ describe Label do
|
|
28
29
|
"row.values_at('procpid', 'usename', 'current_query')\n end\n end"
|
29
30
|
)
|
30
31
|
|
31
|
-
allow(subject).to receive(:describe).with("nokogiri",
|
32
|
+
allow(subject).to receive(:describe).with("nokogiri", nil).and_return(
|
32
33
|
"Nokogiri (é\u008B¸) is an HTML, XML, SAX, and Reader "+
|
33
34
|
"parser. Among Nokogiri's\nmany features is the "+
|
34
35
|
"ability to search documents via XPath or CSS3 "+
|
@@ -37,7 +38,7 @@ describe Label do
|
|
37
38
|
"using\nenough of it."
|
38
39
|
)
|
39
40
|
|
40
|
-
allow(subject).to receive(:describe).with("unicorn",
|
41
|
+
allow(subject).to receive(:describe).with("unicorn", nil).and_return(
|
41
42
|
"\\Unicorn is an HTTP server for Rack applications "+
|
42
43
|
"designed to only serve\nfast clients on low-latency, high-bandwidth "+
|
43
44
|
"connections and take\nadvantage of features in Unix/Unix-like kernels."+
|
@@ -46,10 +47,10 @@ describe Label do
|
|
46
47
|
"\\Unicorn and slow clients."
|
47
48
|
)
|
48
49
|
|
49
|
-
allow(subject).to receive(:describe).with("pry",
|
50
|
+
allow(subject).to receive(:describe).with("pry", nil)
|
50
51
|
.and_return("An IRB alternative and runtime developer console")
|
51
52
|
|
52
|
-
allow(subject).to receive(:describe).with("rspec-rails",
|
53
|
+
allow(subject).to receive(:describe).with("rspec-rails", '~> 3.0.0.beta2').and_return(
|
53
54
|
"Rspec for Rails"
|
54
55
|
)
|
55
56
|
|
@@ -58,15 +59,30 @@ describe Label do
|
|
58
59
|
end
|
59
60
|
|
60
61
|
describe "#describe" do
|
61
|
-
it "
|
62
|
-
expect(
|
62
|
+
it "describes a given gem" do
|
63
|
+
expect(subject.describe("rake")).to eq "Rake is a Make-like program implemented in Ruby"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "describes requested version of a given gem" do
|
67
|
+
expect(subject.describe("bundler", "~> 1.3")).to eq "The best way to manage your application's dependencies"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "raises when a given gem could not be found" do
|
71
|
+
expect do
|
72
|
+
subject.describe("missing")
|
73
|
+
end.to raise_error Gem::LoadError, "Could not find 'missing' (>= 0)"
|
74
|
+
end
|
63
75
|
|
64
|
-
|
76
|
+
it "raises when requested version of a given gem could not be found" do
|
77
|
+
expect do
|
78
|
+
subject.describe("bundler", "~> 1000.0")
|
79
|
+
end.to raise_error Gem::LoadError, "Could not find 'bundler' (~> 1000.0)"
|
65
80
|
end
|
66
81
|
|
67
|
-
it "
|
68
|
-
|
69
|
-
|
82
|
+
it "raises when given version requirement is malformed" do
|
83
|
+
expect do
|
84
|
+
subject.describe("bundler", "fweep")
|
85
|
+
end.to raise_error Gem::Requirement::BadRequirementError
|
70
86
|
end
|
71
87
|
end
|
72
88
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,10 +6,3 @@ Coveralls.wear!
|
|
6
6
|
def fixture file
|
7
7
|
File.read "spec/fixtures/#{file}"
|
8
8
|
end
|
9
|
-
|
10
|
-
def mock_github_response!
|
11
|
-
gemspec_contents = File.readlines("./label.gemspec").join("\n")
|
12
|
-
response_double = double :response_double, body: gemspec_contents
|
13
|
-
expect(Net::HTTP).to receive(:get_response).with(anything())
|
14
|
-
.and_return(response_double)
|
15
|
-
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: label
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johannes Gorset
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: gems
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0.8'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0.8'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: bundler
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,14 +71,10 @@ files:
|
|
85
71
|
- label.gemspec
|
86
72
|
- lib/label.rb
|
87
73
|
- lib/label/description_formatter.rb
|
88
|
-
- lib/label/gemspec_info.rb
|
89
|
-
- lib/label/summary_extractor.rb
|
90
74
|
- lib/label/version.rb
|
91
75
|
- spec/fixtures/processed_gemfile
|
92
76
|
- spec/fixtures/stock_gemfile
|
93
77
|
- spec/label/description_formatter_spec.rb
|
94
|
-
- spec/label/gemspec_info_spec.rb
|
95
|
-
- spec/label/summary_extractor_spec.rb
|
96
78
|
- spec/label_spec.rb
|
97
79
|
- spec/spec_helper.rb
|
98
80
|
homepage: https://github.com/jgorset/label
|
@@ -115,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
97
|
version: '0'
|
116
98
|
requirements: []
|
117
99
|
rubyforge_project:
|
118
|
-
rubygems_version: 2.2.
|
100
|
+
rubygems_version: 2.2.2
|
119
101
|
signing_key:
|
120
102
|
specification_version: 4
|
121
103
|
summary: Label labels the gems in your Gemfile
|
@@ -123,7 +105,5 @@ test_files:
|
|
123
105
|
- spec/fixtures/processed_gemfile
|
124
106
|
- spec/fixtures/stock_gemfile
|
125
107
|
- spec/label/description_formatter_spec.rb
|
126
|
-
- spec/label/gemspec_info_spec.rb
|
127
|
-
- spec/label/summary_extractor_spec.rb
|
128
108
|
- spec/label_spec.rb
|
129
109
|
- spec/spec_helper.rb
|
data/lib/label/gemspec_info.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
require 'label/summary_extractor'
|
2
|
-
require 'net/http'
|
3
|
-
|
4
|
-
module Label
|
5
|
-
# A class to represent a gemspec file in order
|
6
|
-
# to extract info from it
|
7
|
-
class GemspecInfo
|
8
|
-
attr_reader :gem_name, :source
|
9
|
-
|
10
|
-
GITHUB_RAW_URL = "https://raw.githubusercontent.com"
|
11
|
-
|
12
|
-
def initialize gem_name, source
|
13
|
-
@gem_name = gem_name
|
14
|
-
@source = source
|
15
|
-
end
|
16
|
-
|
17
|
-
# Extracts the gemspec summary string
|
18
|
-
def summary
|
19
|
-
SummaryExtractor.new(content).extract_summary
|
20
|
-
end
|
21
|
-
|
22
|
-
# Raw contents of the gemspec file
|
23
|
-
def content
|
24
|
-
@content ||= fetch_gemspec_content!
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
# Fetch the content from a gemspec file that could be remote or
|
30
|
-
# that could be a file in the developer computer
|
31
|
-
#
|
32
|
-
# Returns a string with the gemspec file content
|
33
|
-
def fetch_gemspec_content!
|
34
|
-
case source_name
|
35
|
-
when :git
|
36
|
-
fetch_gemspec_content_from_git!
|
37
|
-
when :github
|
38
|
-
fetch_gemspec_content_from_github!
|
39
|
-
when :path
|
40
|
-
fetch_gemspec_content_from_path!
|
41
|
-
else
|
42
|
-
""
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# returns a symbol of the defined source
|
47
|
-
# it could be :git, :github, :path, etc
|
48
|
-
def source_name
|
49
|
-
[:git, :github, :path].each do |source_name|
|
50
|
-
return source_name if source[source_name]
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# for simplicity git protocol calls that match with a github repo
|
55
|
-
# will be converted to a github url
|
56
|
-
def fetch_gemspec_content_from_git!
|
57
|
-
if md = source[:git].match(/git:\/\/github\.com:(?<repo>.*)/)
|
58
|
-
source[:github] = md[:repo]
|
59
|
-
source.delete :git
|
60
|
-
fetch_gemspec_content_from_github!
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def fetch_gemspec_content_from_github!
|
65
|
-
repo = source[:github]
|
66
|
-
branch = source[:branch] || "master"
|
67
|
-
file_url = "#{GITHUB_RAW_URL}/#{repo}/#{branch}/#{gem_name}.gemspec"
|
68
|
-
Net::HTTP.get_response(URI(file_url)).body
|
69
|
-
end
|
70
|
-
|
71
|
-
def fetch_gemspec_content_from_path!
|
72
|
-
File.readlines("#{source[:path]}/#{gem_name}.gemspec").join "\n"
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Label
|
2
|
-
# A class to extract the summary from the contents of a gemspec file
|
3
|
-
class SummaryExtractor
|
4
|
-
attr_reader :content
|
5
|
-
|
6
|
-
STRING_REGEXPS = [
|
7
|
-
/\"(?<content>[^"]*)\"/,
|
8
|
-
/'(?<content>[^']*)'/,
|
9
|
-
/%q\{(?<content>[^}]*)\}/i
|
10
|
-
]
|
11
|
-
|
12
|
-
def initialize content
|
13
|
-
@content = content
|
14
|
-
end
|
15
|
-
|
16
|
-
def extract_summary
|
17
|
-
STRING_REGEXPS.find do |regexp|
|
18
|
-
md = content.match(/\w+\.summary\s+=\s+#{regexp}/)
|
19
|
-
return md[:content] if md
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "label/gemspec_info"
|
3
|
-
|
4
|
-
describe Label::GemspecInfo do
|
5
|
-
|
6
|
-
describe "#summary" do
|
7
|
-
it "should extract the summary from a gem from a github repo" do
|
8
|
-
mock_github_response!
|
9
|
-
info = Label::GemspecInfo.new "label", github: "jgorset/label"
|
10
|
-
expect(info.summary).to eq "Label labels the gems in your Gemfile"
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should extract the summary from a gem from a git repo" do
|
14
|
-
mock_github_response!
|
15
|
-
info = Label::GemspecInfo.new "label", git: "git://github.com:jgorset/label"
|
16
|
-
expect(info.summary).to eq "Label labels the gems in your Gemfile"
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should extract the summary from a gem from a path" do
|
20
|
-
info = Label::GemspecInfo.new "label", path: "./"
|
21
|
-
expect(info.summary).to eq "Label labels the gems in your Gemfile"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require "label/summary_extractor"
|
2
|
-
|
3
|
-
shared_examples "extracts summary" do |expected_summary|
|
4
|
-
it "should extract summary" do
|
5
|
-
extractor = Label::SummaryExtractor.new(content)
|
6
|
-
expect(extractor.extract_summary).to eq expected_summary
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe Label::SummaryExtractor do
|
11
|
-
|
12
|
-
describe "#extract_summary" do
|
13
|
-
context "for double quoted strings containing single quoted strings" do
|
14
|
-
let(:content) { "s.email = [\"fespinozacast@gmail.com\"]\n s.homepage = \"fespinoza.github.io\"\n s.summary = \"A series of generators an other rails 'defaults' for my projects\"\n s.description = \"TODO.\"\n s.license = \"MIT\"\n\n" }
|
15
|
-
|
16
|
-
include_examples "extracts summary", "A series of generators an other rails 'defaults' for my projects"
|
17
|
-
end
|
18
|
-
|
19
|
-
context "for single quoted strings containing double quoted strings" do
|
20
|
-
let(:content) { "s.email = [\"fespinozacast@gmail.com\"]\n s.homepage = \"fespinoza.github.io\"\n s.summary = 'A series of generators an other rails \"defaults\" for my projects'\n s.description = \"TODO.\"\n s.license = \"MIT\"\n\n" }
|
21
|
-
|
22
|
-
include_examples "extracts summary", "A series of generators an other rails \"defaults\" for my projects"
|
23
|
-
end
|
24
|
-
|
25
|
-
context "for strings defined with %q{}" do
|
26
|
-
let(:content) { "s.email = [\"fespinozacast@gmail.com\"]\n s.homepage = \"fespinoza.github.io\"\n s.summary = %q{A series of generators an other rails \"defaults\" for my 'projects'}\n s.description = \"TODO.\"\n s.license = \"MIT\"\n\n" }
|
27
|
-
|
28
|
-
include_examples "extracts summary", "A series of generators an other rails \"defaults\" for my 'projects'"
|
29
|
-
end
|
30
|
-
|
31
|
-
context "for strings defined with %Q{}" do
|
32
|
-
let(:content) { "s.email = [\"fespinozacast@gmail.com\"]\n s.homepage = \"fespinoza.github.io\"\n s.summary = %Q{A series of generators an other rails \"defaults\" for my 'projects'}\n s.description = \"TODO.\"\n s.license = \"MIT\"\n\n" }
|
33
|
-
|
34
|
-
include_examples "extracts summary", "A series of generators an other rails \"defaults\" for my 'projects'"
|
35
|
-
end
|
36
|
-
|
37
|
-
context "for different gem configuration variable names" do
|
38
|
-
let(:content) { "g.email = [\"fespinozacast@gmail.com\"]\n g.homepage = \"fespinoza.github.io\"\n g.summary = %q{A series of generators an other rails \"defaults\" for my 'projects'}\n g.description = \"TODO.\"\n g.license = \"MIT\"\n\n" }
|
39
|
-
|
40
|
-
include_examples "extracts summary", "A series of generators an other rails \"defaults\" for my 'projects'"
|
41
|
-
end
|
42
|
-
|
43
|
-
context "for summaries that don't exist at all" do
|
44
|
-
let(:content) { "s.email = [\"fespinozacast@gmail.com\"]\n s.homepage = \"fespinoza.github.io\"\n s.description = \"TODO.\"\n s.license = \"MIT\"\n\n" }
|
45
|
-
|
46
|
-
include_examples "extracts summary", nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|