resync-client 0.1.2 → 0.2.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 +4 -4
- data/.gitignore +2 -0
- data/CHANGES.md +10 -0
- data/lib/resync/client.rb +63 -0
- data/lib/resync/client/http_helper.rb +90 -90
- data/lib/resync/client/mixins.rb +1 -0
- data/lib/resync/client/mixins/bitstream_resource.rb +26 -0
- data/lib/resync/client/mixins/bitstream_resource_list.rb +29 -0
- data/lib/resync/client/mixins/client_delegator.rb +38 -0
- data/lib/resync/client/mixins/downloadable.rb +36 -0
- data/lib/resync/client/mixins/link_client_delegate.rb +19 -0
- data/lib/resync/client/mixins/resource_client_delegate.rb +19 -0
- data/lib/resync/client/mixins/zipped_resource.rb +20 -0
- data/lib/resync/client/mixins/zipped_resource_list.rb +26 -0
- data/lib/resync/client/version.rb +1 -1
- data/lib/resync/client/zip.rb +1 -0
- data/lib/resync/client/zip/bitstream.rb +85 -0
- data/lib/resync/client/zip/zip_package.rb +78 -0
- data/lib/resync/client/zip/zip_packages.rb +59 -0
- data/lib/resync/extensions.rb +36 -0
- data/resync-client.gemspec +1 -1
- data/spec/acceptance/example_spec.rb +46 -0
- data/spec/data/resourcedump/changedump.xml +16 -0
- data/spec/data/simulator/capability-list.xml +2 -0
- data/spec/data/simulator/change-list.xml +2 -0
- data/spec/data/simulator/source-description.xml +2 -0
- data/spec/data/simulator/update.txt +1 -0
- data/spec/unit/resync/client/bitstream_spec.rb +84 -80
- data/spec/unit/resync/client/client_spec.rb +64 -3
- data/spec/unit/resync/client/{resync_extensions_spec.rb → extensions_spec.rb} +1 -6
- data/spec/unit/resync/client/http_helper_spec.rb +187 -185
- data/spec/unit/resync/client/zip_package_spec.rb +47 -32
- data/spec/unit/resync/client/zip_packages_spec.rb +42 -38
- data/spec/unit/resync/client/zipped_resource_list_spec.rb +61 -0
- metadata +35 -16
- data/lib/resync/client/bitstream.rb +0 -79
- data/lib/resync/client/client.rb +0 -58
- data/lib/resync/client/downloadable.rb +0 -35
- data/lib/resync/client/dump.rb +0 -26
- data/lib/resync/client/resync_extensions.rb +0 -85
- data/lib/resync/client/zip_package.rb +0 -66
- data/lib/resync/client/zip_packages.rb +0 -51
- data/spec/unit/resync/client/dump_spec.rb +0 -26
@@ -1,43 +1,58 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'resync/client/zip_package'
|
3
2
|
|
4
3
|
module Resync
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
class Client
|
5
|
+
module Zip
|
6
|
+
describe ZipPackage do
|
7
|
+
describe '#new' do
|
8
|
+
it 'accepts a path to a ZIP file' do
|
9
|
+
path = 'spec/data/resourcedump/resourcedump.zip'
|
10
|
+
pkg = ZipPackage.new(path)
|
11
|
+
zipfile = pkg.zipfile
|
12
|
+
expect(zipfile).to be_a(::Zip::File)
|
13
|
+
expect(zipfile.name).to eq(path)
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
it 'accepts a Zip::File object' do
|
17
|
+
zipfile = ::Zip::File.open('spec/data/resourcedump/resourcedump.zip')
|
18
|
+
pkg = ZipPackage.new(zipfile)
|
19
|
+
expect(pkg.zipfile).to eq(zipfile)
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
it 'extracts a manifest' do
|
23
|
+
pkg = ZipPackage.new('spec/data/resourcedump/resourcedump.zip')
|
24
|
+
manifest = pkg.manifest
|
25
|
+
expect(manifest).to be_a(Resync::ResourceDumpManifest)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'extracts entries' do
|
29
|
+
pkg = ZipPackage.new('spec/data/resourcedump/resourcedump.zip')
|
30
|
+
bitstreams = pkg.bitstreams
|
31
|
+
expect(bitstreams.size).to eq(2)
|
32
|
+
|
33
|
+
bs0 = bitstreams[0]
|
34
|
+
expect(bs0.path).to eq('resources/res1')
|
35
|
+
expect(bs0.size).to eq(446)
|
36
|
+
expect(bs0.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
|
37
|
+
|
38
|
+
bs1 = bitstreams[1]
|
39
|
+
expect(bs1.path).to eq('resources/res2')
|
40
|
+
expect(bs1.size).to eq(447)
|
41
|
+
expect(bs1.content).to eq(File.read('spec/data/resourcedump/resources/res2'))
|
42
|
+
end
|
26
43
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
expect(bitstreams.size).to eq(2)
|
44
|
+
it 'provides direct access to bitstreams for each resource in the manifest' do
|
45
|
+
pkg = ZipPackage.new('spec/data/resourcedump/resourcedump.zip')
|
46
|
+
bitstreams = pkg.bitstreams
|
31
47
|
|
32
|
-
|
33
|
-
|
34
|
-
expect(bs0.size).to eq(446)
|
35
|
-
expect(bs0.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
|
48
|
+
manifest = pkg.manifest
|
49
|
+
resources = manifest.resources
|
36
50
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
51
|
+
resources.each_with_index do |r, i|
|
52
|
+
expect(r.bitstream).to be(bitstreams[i])
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
41
56
|
end
|
42
57
|
end
|
43
58
|
end
|
@@ -1,53 +1,57 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
module Resync
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class Client
|
5
|
+
module Zip
|
6
|
+
describe ZipPackages do
|
7
|
+
it 'is lazy' do
|
8
|
+
resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
|
7
9
|
|
8
|
-
|
10
|
+
zip_packages = ZipPackages.new(resources)
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
zip_package = instance_double(ZipPackage)
|
13
|
+
expect(resources[0]).not_to receive(:zip_package)
|
14
|
+
expect(resources[1]).not_to receive(:zip_package)
|
15
|
+
expect(resources[2]).to receive(:zip_package).and_return(zip_package)
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
it 'caches zip packages' do
|
19
|
-
resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
|
17
|
+
expect(zip_packages[2]).to be(zip_package)
|
18
|
+
end
|
20
19
|
|
21
|
-
|
20
|
+
it 'caches zip packages' do
|
21
|
+
resources = Array.new(3) { |i| Resource.new(uri: "http://example.org/res#{i}") }
|
22
22
|
|
23
|
-
|
24
|
-
expect(resources[1]).to receive(:zip_package).once.and_return(zip_package)
|
23
|
+
zip_packages = ZipPackages.new(resources)
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
end
|
25
|
+
zip_package = instance_double(ZipPackage)
|
26
|
+
expect(resources[1]).to receive(:zip_package).once.and_return(zip_package)
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
all_packages = Array.new(3) do |index|
|
33
|
-
zip_package = instance_double(ZipPackage)
|
34
|
-
allow(zip_package).to receive(:manifest).and_return(manifests[index])
|
35
|
-
zip_package
|
36
|
-
end
|
37
|
-
resources = Array.new(3) do |index|
|
38
|
-
resource = Resource.new(uri: "http://example.org/res#{index}")
|
39
|
-
if index > 1
|
40
|
-
expect(resource).not_to receive(:zip_package)
|
41
|
-
else
|
42
|
-
expect(resource).to receive(:zip_package).and_return(all_packages[index])
|
28
|
+
expect(zip_packages[1]).to be(zip_package)
|
29
|
+
expect(zip_packages[1]).to be(zip_package)
|
43
30
|
end
|
44
|
-
resource
|
45
|
-
end
|
46
31
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
32
|
+
it 'supports lazy iteration' do
|
33
|
+
manifests = Array.new(3) { instance_double(ChangeDumpManifest) }
|
34
|
+
all_packages = Array.new(3) do |index|
|
35
|
+
zip_package = instance_double(ZipPackage)
|
36
|
+
allow(zip_package).to receive(:manifest).and_return(manifests[index])
|
37
|
+
zip_package
|
38
|
+
end
|
39
|
+
resources = Array.new(3) do |index|
|
40
|
+
resource = Resource.new(uri: "http://example.org/res#{index}")
|
41
|
+
if index > 1
|
42
|
+
expect(resource).not_to receive(:zip_package)
|
43
|
+
else
|
44
|
+
expect(resource).to receive(:zip_package).and_return(all_packages[index])
|
45
|
+
end
|
46
|
+
resource
|
47
|
+
end
|
48
|
+
|
49
|
+
zip_packages = ZipPackages.new(resources)
|
50
|
+
zip_packages.each_with_index do |zip_package, index|
|
51
|
+
expect(zip_package.manifest).to be(manifests[index])
|
52
|
+
break if index >= 1
|
53
|
+
end
|
54
|
+
end
|
51
55
|
end
|
52
56
|
end
|
53
57
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Resync
|
4
|
+
class Client
|
5
|
+
module Mixins
|
6
|
+
describe ZippedResourceList do
|
7
|
+
it "works for #{ResourceDump}" do
|
8
|
+
path = 'spec/data/resourcedump/resourcedump.xml'
|
9
|
+
package_uri = URI('http://example.com/resourcedump.zip')
|
10
|
+
|
11
|
+
client = instance_double(Client)
|
12
|
+
expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
|
13
|
+
|
14
|
+
dump = XMLParser.parse(File.read(path))
|
15
|
+
dump.client = client
|
16
|
+
|
17
|
+
zip_packages = dump.zip_packages
|
18
|
+
expect(zip_packages.size).to eq(1)
|
19
|
+
|
20
|
+
zip_package = zip_packages[0]
|
21
|
+
expect(zip_package).to be_a(Resync::Client::Zip::ZipPackage)
|
22
|
+
|
23
|
+
bitstreams = zip_package.bitstreams
|
24
|
+
expect(bitstreams.size).to eq(2)
|
25
|
+
|
26
|
+
stream1 = bitstreams[0]
|
27
|
+
expect(stream1.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
|
28
|
+
|
29
|
+
stream2 = bitstreams[1]
|
30
|
+
expect(stream2.content).to eq(File.read('spec/data/resourcedump/resources/res2'))
|
31
|
+
end
|
32
|
+
|
33
|
+
it "works for #{ChangeDump}" do
|
34
|
+
path = 'spec/data/resourcedump/changedump.xml'
|
35
|
+
package_uri = URI('http://example.com/changedump.zip')
|
36
|
+
|
37
|
+
client = instance_double(Client)
|
38
|
+
expect(client).to receive(:download_to_temp_file).once.with(package_uri).and_return('spec/data/resourcedump/resourcedump.zip')
|
39
|
+
|
40
|
+
dump = XMLParser.parse(File.read(path))
|
41
|
+
dump.client = client
|
42
|
+
|
43
|
+
zip_packages = dump.zip_packages
|
44
|
+
expect(zip_packages.size).to eq(1)
|
45
|
+
|
46
|
+
zip_package = zip_packages[0]
|
47
|
+
expect(zip_package).to be_a(Resync::Client::Zip::ZipPackage)
|
48
|
+
|
49
|
+
bitstreams = zip_package.bitstreams
|
50
|
+
expect(bitstreams.size).to eq(2)
|
51
|
+
|
52
|
+
stream1 = bitstreams[0]
|
53
|
+
expect(stream1.content).to eq(File.read('spec/data/resourcedump/resources/res1'))
|
54
|
+
|
55
|
+
stream2 = bitstreams[1]
|
56
|
+
expect(stream2.content).to eq(File.read('spec/data/resourcedump/resources/res2'))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resync-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Moles
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-06-
|
11
|
+
date: 2015-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: resync
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '0.1'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.1.
|
22
|
+
version: 0.1.3
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '0.1'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.1.
|
32
|
+
version: 0.1.3
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rubyzip
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -160,16 +160,24 @@ files:
|
|
160
160
|
- Rakefile
|
161
161
|
- example.rb
|
162
162
|
- lib/resync/client.rb
|
163
|
-
- lib/resync/client/bitstream.rb
|
164
|
-
- lib/resync/client/client.rb
|
165
|
-
- lib/resync/client/downloadable.rb
|
166
|
-
- lib/resync/client/dump.rb
|
167
163
|
- lib/resync/client/http_helper.rb
|
168
|
-
- lib/resync/client/
|
164
|
+
- lib/resync/client/mixins.rb
|
165
|
+
- lib/resync/client/mixins/bitstream_resource.rb
|
166
|
+
- lib/resync/client/mixins/bitstream_resource_list.rb
|
167
|
+
- lib/resync/client/mixins/client_delegator.rb
|
168
|
+
- lib/resync/client/mixins/downloadable.rb
|
169
|
+
- lib/resync/client/mixins/link_client_delegate.rb
|
170
|
+
- lib/resync/client/mixins/resource_client_delegate.rb
|
171
|
+
- lib/resync/client/mixins/zipped_resource.rb
|
172
|
+
- lib/resync/client/mixins/zipped_resource_list.rb
|
169
173
|
- lib/resync/client/version.rb
|
170
|
-
- lib/resync/client/
|
171
|
-
- lib/resync/client/
|
174
|
+
- lib/resync/client/zip.rb
|
175
|
+
- lib/resync/client/zip/bitstream.rb
|
176
|
+
- lib/resync/client/zip/zip_package.rb
|
177
|
+
- lib/resync/client/zip/zip_packages.rb
|
178
|
+
- lib/resync/extensions.rb
|
172
179
|
- resync-client.gemspec
|
180
|
+
- spec/acceptance/example_spec.rb
|
173
181
|
- spec/data/examples/capability-list.xml
|
174
182
|
- spec/data/examples/change-dump-manifest.xml
|
175
183
|
- spec/data/examples/change-dump.xml
|
@@ -180,21 +188,26 @@ files:
|
|
180
188
|
- spec/data/examples/resource-list-index.xml
|
181
189
|
- spec/data/examples/resource-list.xml
|
182
190
|
- spec/data/examples/source-description.xml
|
191
|
+
- spec/data/resourcedump/changedump.xml
|
183
192
|
- spec/data/resourcedump/manifest.xml
|
184
193
|
- spec/data/resourcedump/resourcedump.xml
|
185
194
|
- spec/data/resourcedump/resourcedump.zip
|
186
195
|
- spec/data/resourcedump/resources/res1
|
187
196
|
- spec/data/resourcedump/resources/res2
|
197
|
+
- spec/data/simulator/capability-list.xml
|
198
|
+
- spec/data/simulator/change-list.xml
|
199
|
+
- spec/data/simulator/source-description.xml
|
200
|
+
- spec/data/simulator/update.txt
|
188
201
|
- spec/rspec_custom_matchers.rb
|
189
202
|
- spec/spec_helper.rb
|
190
203
|
- spec/todo.rb
|
191
204
|
- spec/unit/resync/client/bitstream_spec.rb
|
192
205
|
- spec/unit/resync/client/client_spec.rb
|
193
|
-
- spec/unit/resync/client/
|
206
|
+
- spec/unit/resync/client/extensions_spec.rb
|
194
207
|
- spec/unit/resync/client/http_helper_spec.rb
|
195
|
-
- spec/unit/resync/client/resync_extensions_spec.rb
|
196
208
|
- spec/unit/resync/client/zip_package_spec.rb
|
197
209
|
- spec/unit/resync/client/zip_packages_spec.rb
|
210
|
+
- spec/unit/resync/client/zipped_resource_list_spec.rb
|
198
211
|
homepage: http://github.com/dmolesUC3/resync-client
|
199
212
|
licenses:
|
200
213
|
- MIT
|
@@ -215,11 +228,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
215
228
|
version: '0'
|
216
229
|
requirements: []
|
217
230
|
rubyforge_project:
|
218
|
-
rubygems_version: 2.4.
|
231
|
+
rubygems_version: 2.4.6
|
219
232
|
signing_key:
|
220
233
|
specification_version: 4
|
221
234
|
summary: Client library for ResourceSync
|
222
235
|
test_files:
|
236
|
+
- spec/acceptance/example_spec.rb
|
223
237
|
- spec/data/examples/capability-list.xml
|
224
238
|
- spec/data/examples/change-dump-manifest.xml
|
225
239
|
- spec/data/examples/change-dump.xml
|
@@ -230,19 +244,24 @@ test_files:
|
|
230
244
|
- spec/data/examples/resource-list-index.xml
|
231
245
|
- spec/data/examples/resource-list.xml
|
232
246
|
- spec/data/examples/source-description.xml
|
247
|
+
- spec/data/resourcedump/changedump.xml
|
233
248
|
- spec/data/resourcedump/manifest.xml
|
234
249
|
- spec/data/resourcedump/resourcedump.xml
|
235
250
|
- spec/data/resourcedump/resourcedump.zip
|
236
251
|
- spec/data/resourcedump/resources/res1
|
237
252
|
- spec/data/resourcedump/resources/res2
|
253
|
+
- spec/data/simulator/capability-list.xml
|
254
|
+
- spec/data/simulator/change-list.xml
|
255
|
+
- spec/data/simulator/source-description.xml
|
256
|
+
- spec/data/simulator/update.txt
|
238
257
|
- spec/rspec_custom_matchers.rb
|
239
258
|
- spec/spec_helper.rb
|
240
259
|
- spec/todo.rb
|
241
260
|
- spec/unit/resync/client/bitstream_spec.rb
|
242
261
|
- spec/unit/resync/client/client_spec.rb
|
243
|
-
- spec/unit/resync/client/
|
262
|
+
- spec/unit/resync/client/extensions_spec.rb
|
244
263
|
- spec/unit/resync/client/http_helper_spec.rb
|
245
|
-
- spec/unit/resync/client/resync_extensions_spec.rb
|
246
264
|
- spec/unit/resync/client/zip_package_spec.rb
|
247
265
|
- spec/unit/resync/client/zip_packages_spec.rb
|
266
|
+
- spec/unit/resync/client/zipped_resource_list_spec.rb
|
248
267
|
has_rdoc:
|
@@ -1,79 +0,0 @@
|
|
1
|
-
module Resync
|
2
|
-
|
3
|
-
# A single entry in a ZIP package.
|
4
|
-
class Bitstream
|
5
|
-
|
6
|
-
# ------------------------------------------------------------
|
7
|
-
# Attributes
|
8
|
-
|
9
|
-
# @return [String] the path to the entry within the ZIP file
|
10
|
-
attr_reader :path
|
11
|
-
|
12
|
-
# @return [Resource] the resource describing this bitstream
|
13
|
-
attr_reader :resource
|
14
|
-
|
15
|
-
# @return [Metadata] the metadata for this bitstream
|
16
|
-
attr_reader :metadata
|
17
|
-
|
18
|
-
# ------------------------------------------------------------
|
19
|
-
# Initializer
|
20
|
-
|
21
|
-
# Creates a new bitstream for the specified resource.
|
22
|
-
#
|
23
|
-
# @param zipfile [Zip::File] The zipfile to read the bitstream from.
|
24
|
-
# @param resource [Resource] The resource describing the bitstream.
|
25
|
-
def initialize(zipfile:, resource:)
|
26
|
-
self.resource = resource
|
27
|
-
@zip_entry = zipfile.find_entry(@path)
|
28
|
-
end
|
29
|
-
|
30
|
-
# ------------------------------------------------------------
|
31
|
-
# Convenience accessors
|
32
|
-
|
33
|
-
# The (uncompressed) size of the bitstream.
|
34
|
-
def size
|
35
|
-
@size ||= @zip_entry.size
|
36
|
-
end
|
37
|
-
|
38
|
-
# The bitstream, as an +IO+-like object. Subsequent
|
39
|
-
# calls will return the same stream.
|
40
|
-
def stream
|
41
|
-
@stream ||= @zip_entry.get_input_stream
|
42
|
-
end
|
43
|
-
|
44
|
-
# The content of the bitstream. The content will be
|
45
|
-
# read only once.
|
46
|
-
def content
|
47
|
-
@content ||= stream.read
|
48
|
-
end
|
49
|
-
|
50
|
-
# The content type of the bitstream, as per {#metadata}.
|
51
|
-
def mime_type
|
52
|
-
@mime_type ||= metadata.mime_type
|
53
|
-
end
|
54
|
-
|
55
|
-
# ------------------------------------------------------------
|
56
|
-
# Private methods
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def resource=(value)
|
61
|
-
fail ArgumentError, 'nil is not a resource' unless value
|
62
|
-
self.metadata = value.metadata
|
63
|
-
@resource = value
|
64
|
-
end
|
65
|
-
|
66
|
-
def metadata=(value)
|
67
|
-
fail 'no metadata found' unless value
|
68
|
-
self.path = value.path
|
69
|
-
@metadata = value
|
70
|
-
end
|
71
|
-
|
72
|
-
def path=(value)
|
73
|
-
fail 'no path found in metadata' unless value
|
74
|
-
@path = value.start_with?('/') ? value.slice(1..-1) : value
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|