bagit 0.4.2 → 0.4.3
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/.rubocop.yml +22 -0
- data/.travis.yml +1 -2
- data/Gemfile +1 -1
- data/README.md +1 -1
- data/Rakefile +8 -2
- data/bagit.gemspec +4 -3
- data/bin/bagit +30 -33
- data/lib/bagit.rb +1 -1
- data/lib/bagit/bag.rb +20 -27
- data/lib/bagit/fetch.rb +14 -20
- data/lib/bagit/file.rb +10 -15
- data/lib/bagit/info.rb +43 -57
- data/lib/bagit/manifest.rb +43 -48
- data/lib/bagit/string.rb +2 -4
- data/lib/bagit/valid.rb +67 -75
- data/lib/bagit/version.rb +1 -1
- data/spec/bagit_spec.rb +34 -30
- data/spec/fetch_spec.rb +29 -35
- data/spec/manifest_spec.rb +99 -108
- data/spec/spec_helper.rb +3 -5
- data/spec/tag_info_spec.rb +91 -99
- data/spec/tag_spec.rb +47 -50
- data/spec/util/bagit_matchers.rb +3 -14
- data/spec/validation_spec.rb +107 -110
- metadata +35 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 110811464b7bda7fe4a731155a75b09a4bfedb37
|
4
|
+
data.tar.gz: bd81624253f0d2faff9a80bc58579e18512bc577
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3754fafd47c4e53a58c7b802ac4761194577dc751ed124fd41179199b009707b169ff36bb144061a94c3494414a40ca47964257871e5d622371efd0c4f99359f
|
7
|
+
data.tar.gz: 10d1c42ed581a0f53018dbca881d9f4adb023d12e229fd6a7ed2c5a190b426e91b11b7ea417ef613b31f7fe6775dce09e71b362cc37205bf457fad91ac821929
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
inherit_gem:
|
2
|
+
bixby: bixby_default.yml
|
3
|
+
Rails/Delegate:
|
4
|
+
Enabled: false
|
5
|
+
Rails/Date:
|
6
|
+
Enabled: false
|
7
|
+
RSpec/InstanceVariable:
|
8
|
+
Enabled: false
|
9
|
+
Metrics/BlockLength:
|
10
|
+
Enabled: false
|
11
|
+
Metrics/ModuleLength:
|
12
|
+
Enabled: false
|
13
|
+
Metrics/MethodLength:
|
14
|
+
Enabled: false
|
15
|
+
RSpec/ExampleLength:
|
16
|
+
Enabled: false
|
17
|
+
Style/Semicolon:
|
18
|
+
Enabled: false
|
19
|
+
Style/ClassVars:
|
20
|
+
Enabled: false
|
21
|
+
Metrics/AbcSize:
|
22
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -5,12 +5,18 @@ Bundler.setup(:default, :development, :test)
|
|
5
5
|
require 'rake'
|
6
6
|
require 'rdoc/task'
|
7
7
|
require 'rspec/core/rake_task'
|
8
|
+
require 'rubocop/rake_task'
|
8
9
|
|
9
10
|
Bundler::GemHelper.install_tasks
|
10
11
|
|
12
|
+
desc 'Run rubocop'
|
13
|
+
task :rubocop do
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
end
|
16
|
+
|
11
17
|
RSpec::Core::RakeTask.new do |t|
|
12
18
|
t.pattern = 'spec/**/*_spec.rb'
|
13
|
-
t.rspec_opts = %w
|
19
|
+
t.rspec_opts = %w[--format documentation --color]
|
14
20
|
end
|
15
21
|
|
16
|
-
task :
|
22
|
+
task default: [:rubocop, :spec]
|
data/bagit.gemspec
CHANGED
@@ -18,14 +18,15 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.add_dependency 'validatable', '~> 1.6'
|
19
19
|
spec.add_dependency 'docopt', '~> 0.5.0'
|
20
20
|
|
21
|
+
spec.add_development_dependency 'bixby'
|
21
22
|
spec.add_development_dependency 'bundler'
|
22
|
-
spec.add_development_dependency 'rake', '~> 10.4'
|
23
|
-
spec.add_development_dependency 'rspec', '~> 3'
|
24
23
|
spec.add_development_dependency 'coveralls'
|
25
24
|
spec.add_development_dependency 'pry'
|
26
25
|
spec.add_development_dependency 'pry-byebug'
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3'
|
27
28
|
|
28
|
-
spec.files = `git ls-files`.split(
|
29
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
29
30
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
30
31
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
31
32
|
spec.require_paths = ["lib"]
|
data/bin/bagit
CHANGED
@@ -31,36 +31,34 @@ Options:
|
|
31
31
|
|
32
32
|
DOCOPT
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
# Possible commands for bag-info write
|
35
|
+
#
|
36
|
+
# bagit new [--source-organization <org>] [--organization-address <org-addr>] [--contact-name <contact>]
|
37
|
+
# [--contact-phone <phone>] [--contact-email <email>] [--external-description <ext-desc>]
|
38
|
+
# [--external-identifier <ext-id>] [--group-identifier <group-id>] [--count <count>]
|
39
|
+
# [--internal-sender-identifier <sender-id>] [--internal-sender-description <sender-desc>]
|
40
|
+
# [--bag-info-entry <label> <value>] [-f <file>...] [-t <tagfile>...] BAGPATH
|
41
41
|
|
42
42
|
begin
|
43
|
-
opts = Docopt
|
43
|
+
opts = Docopt.docopt(doc, version: BagIt::VERSION)
|
44
44
|
|
45
|
-
unless opts['validate']
|
46
|
-
bag = BagIt::Bag.new(opts['BAGPATH'])
|
47
|
-
end
|
45
|
+
bag = BagIt::Bag.new(opts['BAGPATH']) unless opts['validate']
|
48
46
|
#####################################
|
49
47
|
# commands that don't alter the bag #
|
50
48
|
#####################################
|
51
49
|
if opts['validate']
|
52
50
|
bag = BagIt::Bag.new(opts['BAGPATH'])
|
53
51
|
|
54
|
-
if opts['--oxum']
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
valid = if opts['--oxum']
|
53
|
+
bag.valid_oxum?
|
54
|
+
else
|
55
|
+
bag.valid?
|
56
|
+
end
|
59
57
|
|
60
58
|
if valid
|
61
59
|
logger.info(valid)
|
62
60
|
else
|
63
|
-
logger.error("#{valid}: #{bag.errors.full_messages.join(', ')}"
|
61
|
+
logger.error("#{valid}: #{bag.errors.full_messages.join(', ')}")
|
64
62
|
end
|
65
63
|
|
66
64
|
# validation commands MUST NOT change manifest or bag-info files
|
@@ -79,35 +77,34 @@ begin
|
|
79
77
|
exit
|
80
78
|
end
|
81
79
|
|
82
|
-
|
83
80
|
######################################
|
84
81
|
# commands that may cause data loss! #
|
85
82
|
######################################
|
86
83
|
|
87
|
-
#TODO: implement delete for data and tag files; remove for tag files.
|
84
|
+
# TODO: implement delete for data and tag files; remove for tag files.
|
88
85
|
|
89
86
|
# handle add/delete bag data files
|
90
87
|
unless opts['-f'].nil?
|
91
|
-
#TODO: add files in nested directories
|
92
|
-
opts['-f'].each
|
88
|
+
# TODO: add files in nested directories
|
89
|
+
opts['-f'].each do |datafile|
|
93
90
|
begin
|
94
|
-
if opts['add']
|
91
|
+
if opts['add'] || opts['new']
|
95
92
|
bag.add_file(File.basename(datafile), datafile)
|
96
93
|
elsif opts['delete']
|
97
94
|
bag.remove_file(File.basename(datafile))
|
98
95
|
end
|
99
|
-
rescue
|
96
|
+
rescue StandardError => e
|
100
97
|
logger.error("Failed operation on bag file: #{e.message}")
|
101
98
|
end
|
102
|
-
|
99
|
+
end
|
103
100
|
end
|
104
101
|
|
105
102
|
# handle adding tag files
|
106
103
|
unless opts['-t'].nil?
|
107
|
-
#TODO: add files in nested directories
|
108
|
-
opts['-t'].each
|
104
|
+
# TODO: add files in nested directories
|
105
|
+
opts['-t'].each do |tagfile|
|
109
106
|
begin
|
110
|
-
if opts['add']
|
107
|
+
if opts['add'] || opts['new']
|
111
108
|
# if it does, try to manifest it
|
112
109
|
if File.exist?(File.join(bag.bag_dir, File.basename(tagfile)))
|
113
110
|
bag.add_tag_file(tagfile)
|
@@ -120,20 +117,20 @@ begin
|
|
120
117
|
elsif opts['remove']
|
121
118
|
bag.remove_tag_file(File.basename(tagfile))
|
122
119
|
end
|
123
|
-
rescue
|
120
|
+
rescue StandardError => e
|
124
121
|
logger.error("Failed operation on tag file: #{e.message}".red)
|
125
122
|
end
|
126
|
-
|
123
|
+
end
|
127
124
|
end
|
128
125
|
|
129
126
|
# if we haven't quit yet, we need to re-manifest
|
130
127
|
# only do tags if tag files have been explictly added/removed or it is explictly called
|
131
|
-
bag.tagmanifest! if opts['-T']
|
128
|
+
bag.tagmanifest! if opts['-T'] || !opts['-t'].nil?
|
132
129
|
|
133
|
-
|
134
|
-
bag.manifest!(algo: opts['<algo>'])
|
135
|
-
else
|
130
|
+
if opts['-a'].nil?
|
136
131
|
bag.manifest!
|
132
|
+
else
|
133
|
+
bag.manifest!(algo: opts['<algo>'])
|
137
134
|
end
|
138
135
|
|
139
136
|
rescue Docopt::Exit => e
|
data/lib/bagit.rb
CHANGED
data/lib/bagit/bag.rb
CHANGED
@@ -16,23 +16,16 @@ module BagIt
|
|
16
16
|
include Fetch # fetch related functionality
|
17
17
|
|
18
18
|
# Make a new Bag based at path
|
19
|
-
def initialize(path, info={},
|
20
|
-
|
21
|
-
|
19
|
+
def initialize(path, info = {}, _create = false)
|
22
20
|
@bag_dir = path
|
23
21
|
# make the dir structure if it doesn't exist
|
24
|
-
FileUtils
|
25
|
-
FileUtils
|
22
|
+
FileUtils.mkdir bag_dir unless File.directory? bag_dir
|
23
|
+
FileUtils.mkdir data_dir unless File.directory? data_dir
|
26
24
|
|
27
25
|
# write some tag info if its not there
|
28
|
-
unless File.exist? bagit_txt_file
|
29
|
-
write_bagit("BagIt-Version" => SPEC_VERSION, "Tag-File-Character-Encoding" => "UTF-8")
|
30
|
-
end
|
26
|
+
write_bagit("BagIt-Version" => SPEC_VERSION, "Tag-File-Character-Encoding" => "UTF-8") unless File.exist? bagit_txt_file
|
31
27
|
|
32
|
-
unless File.exist? bag_info_txt_file
|
33
|
-
write_bag_info(info)
|
34
|
-
end
|
35
|
-
|
28
|
+
write_bag_info(info) unless File.exist? bag_info_txt_file
|
36
29
|
end
|
37
30
|
|
38
31
|
# Return the path to the data directory
|
@@ -50,32 +43,32 @@ module BagIt
|
|
50
43
|
files = []
|
51
44
|
if tagmanifest_files != []
|
52
45
|
File.open(tagmanifest_files.first) do |f|
|
53
|
-
f.each_line{|line| files << File.join(@bag_dir, line.split(' ')[1])}
|
46
|
+
f.each_line { |line| files << File.join(@bag_dir, line.split(' ')[1]) }
|
54
47
|
end
|
55
48
|
end
|
56
49
|
files
|
57
50
|
end
|
58
51
|
|
59
52
|
# Add a bag file at the given path relative to data_dir
|
60
|
-
def add_file(relative_path, src_path=nil)
|
53
|
+
def add_file(relative_path, src_path = nil)
|
61
54
|
path = File.join(data_dir, relative_path)
|
62
55
|
raise "Bag file exists: #{relative_path}" if File.exist? path
|
63
|
-
FileUtils
|
56
|
+
FileUtils.mkdir_p File.dirname(path)
|
64
57
|
|
65
|
-
if src_path.nil?
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
58
|
+
f = if src_path.nil?
|
59
|
+
File.open(path, 'w') { |io| yield io }
|
60
|
+
else
|
61
|
+
FileUtils.cp src_path, path
|
62
|
+
end
|
70
63
|
write_bag_info
|
71
|
-
|
64
|
+
f
|
72
65
|
end
|
73
66
|
|
74
67
|
# Remove a bag file at the given path relative to data_dir
|
75
68
|
def remove_file(relative_path)
|
76
69
|
path = File.join(data_dir, relative_path)
|
77
70
|
raise "Bag file does not exist: #{relative_path}" unless File.exist? path
|
78
|
-
FileUtils
|
71
|
+
FileUtils.rm path
|
79
72
|
end
|
80
73
|
|
81
74
|
# Retrieve the IO handle for a file in the bag at a given path relative to
|
@@ -88,28 +81,28 @@ module BagIt
|
|
88
81
|
|
89
82
|
# Test if this bag is empty (no files)
|
90
83
|
def empty?
|
91
|
-
|
84
|
+
bag_files.empty?
|
92
85
|
end
|
93
86
|
|
94
87
|
# Get all bag file paths relative to the data dir
|
95
88
|
def paths
|
96
|
-
|
89
|
+
bag_files.collect { |f| f.sub(data_dir + '/', '') }
|
97
90
|
end
|
98
91
|
|
99
92
|
# Get the Oxum for the payload files
|
100
93
|
def payload_oxum
|
101
94
|
bytes = 0
|
102
95
|
bag_files.each do |f|
|
103
|
-
#TODO: filesystem quirks? Are we getting the stream size or the size on disk?
|
96
|
+
# TODO: filesystem quirks? Are we getting the stream size or the size on disk?
|
104
97
|
bytes += File.size(f)
|
105
98
|
end
|
106
|
-
|
99
|
+
bytes.to_s + '.' + bag_files.count.to_s
|
107
100
|
end
|
108
101
|
|
109
102
|
# Remove all empty directory trees from the bag
|
110
103
|
def gc!
|
111
104
|
Dir.entries(data_dir).each do |f|
|
112
|
-
unless %w
|
105
|
+
unless %w[.. .].include? f
|
113
106
|
abs_path = File.join data_dir, f
|
114
107
|
File.clean abs_path
|
115
108
|
end
|
data/lib/bagit/fetch.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'open-uri'
|
2
2
|
|
3
3
|
module BagIt
|
4
|
-
|
5
4
|
module Fetch
|
6
|
-
|
7
5
|
def fetch_txt_file
|
8
6
|
File.join @bag_dir, 'fetch.txt'
|
9
7
|
end
|
@@ -16,35 +14,31 @@ module BagIt
|
|
16
14
|
|
17
15
|
# feth all remote files
|
18
16
|
def fetch!
|
19
|
-
|
20
17
|
open(fetch_txt_file) do |io|
|
21
|
-
|
22
18
|
io.readlines.each do |line|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
io.write open(url)
|
19
|
+
(url, _length, path) = line.chomp.split(/\s+/, 3)
|
20
|
+
|
21
|
+
add_file(path) do |file_io|
|
22
|
+
file_io.write open(url)
|
28
23
|
end
|
29
|
-
|
30
24
|
end
|
31
|
-
|
32
25
|
end
|
33
26
|
|
34
|
-
|
27
|
+
rename_old_fetch_txt(fetch_txt_file)
|
28
|
+
move_current_fetch_txt(fetch_txt_file)
|
29
|
+
end
|
30
|
+
|
31
|
+
def rename_old_fetch_txt(fetch_txt_file)
|
35
32
|
Dir["#{fetch_txt_file}.?*"].sort.reverse.each do |f|
|
36
|
-
|
37
33
|
if f =~ /fetch.txt.(\d+)$/
|
38
|
-
new_f = File.join File.dirname(f), "fetch.txt.#{
|
39
|
-
FileUtils
|
34
|
+
new_f = File.join File.dirname(f), "fetch.txt.#{Regexp.last_match(1).to_i + 1}"
|
35
|
+
FileUtils.mv f, new_f
|
40
36
|
end
|
41
|
-
|
42
37
|
end
|
38
|
+
end
|
43
39
|
|
44
|
-
|
45
|
-
FileUtils
|
40
|
+
def move_current_fetch_txt(fetch_txt_file)
|
41
|
+
FileUtils.mv fetch_txt_file, "#{fetch_txt_file}.0"
|
46
42
|
end
|
47
|
-
|
48
43
|
end
|
49
|
-
|
50
44
|
end
|
data/lib/bagit/file.rb
CHANGED
@@ -1,19 +1,14 @@
|
|
1
1
|
class File
|
2
|
-
|
3
2
|
# Clean out all the empty dirs
|
4
|
-
def
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Dir.delete file_name if contents.empty?
|
15
|
-
end
|
16
|
-
|
3
|
+
def self.clean(file_name)
|
4
|
+
return unless File.directory? file_name
|
5
|
+
# clean all subdirs
|
6
|
+
subdirs = Dir.entries(file_name).select { |p| File.directory?(File.join(file_name, p)) }
|
7
|
+
subdirs.reject! { |p| %w[. ..].include? p }
|
8
|
+
subdirs.each { |sd| File.clean File.join(file_name, sd) }
|
9
|
+
|
10
|
+
# if its empty then delete it
|
11
|
+
contents = Dir.entries(file_name).reject { |p| %w[. ..].include? p }
|
12
|
+
Dir.delete file_name if contents.empty?
|
17
13
|
end
|
18
|
-
|
19
14
|
end
|
data/lib/bagit/info.rb
CHANGED
@@ -1,25 +1,23 @@
|
|
1
1
|
require 'set'
|
2
2
|
|
3
3
|
module BagIt
|
4
|
-
|
5
4
|
module Info
|
6
|
-
|
7
5
|
@@bag_info_headers = {
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
6
|
+
agent: 'Bag-Software-Agent',
|
7
|
+
org: 'Source-Organization',
|
8
|
+
org_addr: 'Organization-Address',
|
9
|
+
contact_name: 'Contact-Name',
|
10
|
+
contact_phone: 'Contact-Phone',
|
11
|
+
contact_email: 'Contact-Email',
|
12
|
+
ext_desc: 'External-Description',
|
13
|
+
ext_id: 'External-Identifier',
|
14
|
+
size: 'Bag-Size',
|
15
|
+
group_id: 'Bag-Group-Identifier',
|
16
|
+
group_count: 'Bag-Count',
|
17
|
+
sender_id: 'Internal-Sender-Identifier',
|
18
|
+
int_desc: 'Internal-Sender-Description',
|
19
|
+
date: 'Bagging-Date',
|
20
|
+
oxum: 'Payload-Oxum'
|
23
21
|
}
|
24
22
|
|
25
23
|
def bag_info_txt_file
|
@@ -27,16 +25,14 @@ module BagIt
|
|
27
25
|
end
|
28
26
|
|
29
27
|
def bag_info
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
{}
|
34
|
-
end
|
28
|
+
read_info_file bag_info_txt_file
|
29
|
+
rescue
|
30
|
+
{}
|
35
31
|
end
|
36
32
|
|
37
|
-
def write_bag_info(hash={})
|
33
|
+
def write_bag_info(hash = {})
|
38
34
|
hash = bag_info.merge(hash)
|
39
|
-
hash[@@bag_info_headers[:agent]] = "BagIt Ruby Gem (
|
35
|
+
hash[@@bag_info_headers[:agent]] = "BagIt Ruby Gem (https://github.com/tipr/bagit)" if hash[@@bag_info_headers[:agent]].nil?
|
40
36
|
hash[@@bag_info_headers[:date]] = Date.today.strftime('%Y-%m-%d') if hash[@@bag_info_headers[:date]].nil?
|
41
37
|
hash[@@bag_info_headers[:oxum]] = payload_oxum
|
42
38
|
write_info_file bag_info_txt_file, hash
|
@@ -61,48 +57,38 @@ module BagIt
|
|
61
57
|
|
62
58
|
protected
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
entries = io.read.split /\n(?=[^\s])/
|
60
|
+
def read_info_file(file)
|
61
|
+
File.open(file) do |io|
|
62
|
+
entries = io.read.split(/\n(?=[^\s])/)
|
69
63
|
|
70
|
-
|
71
|
-
|
72
|
-
|
64
|
+
entries.inject({}) do |hash, line|
|
65
|
+
name, value = line.chomp.split(/\s*:\s*/, 2)
|
66
|
+
hash.merge(name => value)
|
67
|
+
end
|
73
68
|
end
|
74
|
-
|
75
69
|
end
|
76
70
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
a = hash.keys.grep(/#{key}/i)
|
83
|
-
acc + (a.size > 1 ? a : [])
|
84
|
-
end
|
85
|
-
|
86
|
-
raise "Multiple labels (#{dups.to_a.join ', '}) in #{file}" unless dups.empty?
|
71
|
+
def write_info_file(file, hash)
|
72
|
+
dups = hash.keys.inject(Set.new) do |acc, key|
|
73
|
+
a = hash.keys.grep(/#{key}/i)
|
74
|
+
acc + (a.size > 1 ? a : [])
|
75
|
+
end
|
87
76
|
|
88
|
-
|
77
|
+
raise "Multiple labels (#{dups.to_a.join ', '}) in #{file}" unless dups.empty?
|
89
78
|
|
90
|
-
|
91
|
-
|
79
|
+
File.open(file, 'w') do |io|
|
80
|
+
hash.each do |name, value|
|
81
|
+
simple_entry = "#{name}: #{value.gsub(/\s+/, ' ')}"
|
92
82
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
83
|
+
entry = if simple_entry.length > 79
|
84
|
+
simple_entry.wrap(77).indent(2)
|
85
|
+
else
|
86
|
+
simple_entry
|
87
|
+
end
|
98
88
|
|
99
|
-
|
89
|
+
io.puts entry
|
90
|
+
end
|
100
91
|
end
|
101
|
-
|
102
92
|
end
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
93
|
end
|
107
|
-
|
108
94
|
end
|