active-fedora 13.1.2 → 13.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/.github_changelog_generator +2 -0
  3. data/CHANGELOG.md +3362 -0
  4. data/CONTRIBUTING.md +23 -1
  5. data/README.md +4 -0
  6. data/active-fedora.gemspec +14 -13
  7. data/lib/active_fedora/version.rb +1 -1
  8. metadata +104 -206
  9. data/spec/config_helper.rb +0 -17
  10. data/spec/fixtures/dino.jpg +0 -0
  11. data/spec/fixtures/dino_jpg_no_file_ext +0 -0
  12. data/spec/fixtures/minivan.jpg +0 -0
  13. data/spec/fixtures/rails_root/config/fake_fedora.yml +0 -7
  14. data/spec/fixtures/rails_root/config/fedora.yml +0 -12
  15. data/spec/fixtures/rails_root/config/solr.yml +0 -15
  16. data/spec/fixtures/rails_root/config/solr_mappings.yml +0 -16
  17. data/spec/fixtures/rails_root/config/solr_mappings_af_0.1.yml +0 -9
  18. data/spec/fixtures/rails_root/config/solr_mappings_bl_2.4.yml +0 -17
  19. data/spec/integration/associations/rdf_spec.rb +0 -61
  20. data/spec/integration/associations_spec.rb +0 -680
  21. data/spec/integration/attached_files_spec.rb +0 -146
  22. data/spec/integration/attributes_spec.rb +0 -73
  23. data/spec/integration/autosave_association_spec.rb +0 -24
  24. data/spec/integration/base_spec.rb +0 -184
  25. data/spec/integration/basic_contains_association_spec.rb +0 -121
  26. data/spec/integration/belongs_to_association_spec.rb +0 -260
  27. data/spec/integration/caching_spec.rb +0 -59
  28. data/spec/integration/clean_connection_spec.rb +0 -21
  29. data/spec/integration/collection_association_spec.rb +0 -166
  30. data/spec/integration/date_time_properties_spec.rb +0 -41
  31. data/spec/integration/delete_all_spec.rb +0 -64
  32. data/spec/integration/direct_container_spec.rb +0 -250
  33. data/spec/integration/directly_contains_one_association_spec.rb +0 -96
  34. data/spec/integration/eradicate_spec.rb +0 -52
  35. data/spec/integration/fedora_solr_sync_spec.rb +0 -30
  36. data/spec/integration/file_fixity_spec.rb +0 -36
  37. data/spec/integration/file_spec.rb +0 -221
  38. data/spec/integration/generators/fedora_generator_spec.rb +0 -26
  39. data/spec/integration/generators/solr_generator_spec.rb +0 -23
  40. data/spec/integration/gone_spec.rb +0 -41
  41. data/spec/integration/has_and_belongs_to_many_associations_spec.rb +0 -414
  42. data/spec/integration/has_many_associations_spec.rb +0 -436
  43. data/spec/integration/has_subresource_spec.rb +0 -34
  44. data/spec/integration/indexing/descendant_fetcher_spec.rb +0 -64
  45. data/spec/integration/indexing_spec.rb +0 -110
  46. data/spec/integration/indirect_container_spec.rb +0 -290
  47. data/spec/integration/json_serialization_spec.rb +0 -32
  48. data/spec/integration/marshal_spec.rb +0 -39
  49. data/spec/integration/nested_attribute_spec.rb +0 -177
  50. data/spec/integration/nested_hash_resources_spec.rb +0 -43
  51. data/spec/integration/persistence_spec.rb +0 -37
  52. data/spec/integration/query_result_builder_spec.rb +0 -37
  53. data/spec/integration/rdf_nested_attributes_spec.rb +0 -85
  54. data/spec/integration/relation_delegation_spec.rb +0 -52
  55. data/spec/integration/relation_spec.rb +0 -117
  56. data/spec/integration/scoped_query_spec.rb +0 -134
  57. data/spec/integration/scoping_spec.rb +0 -48
  58. data/spec/integration/solr_hit_spec.rb +0 -32
  59. data/spec/integration/versionable_spec.rb +0 -256
  60. data/spec/integration/with_metadata_spec.rb +0 -111
  61. data/spec/lib/active_fedora/null_logger_spec.rb +0 -10
  62. data/spec/rcov.opts +0 -2
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_helper.rb +0 -106
  65. data/spec/support/an_active_model.rb +0 -29
  66. data/spec/unit/active_fedora/indexing/inserter_spec.rb +0 -35
  67. data/spec/unit/active_fedora_spec.rb +0 -118
  68. data/spec/unit/aggregation/list_source_spec.rb +0 -134
  69. data/spec/unit/aggregation/ordered_reader_spec.rb +0 -43
  70. data/spec/unit/association_hash_spec.rb +0 -64
  71. data/spec/unit/attached_files_spec.rb +0 -218
  72. data/spec/unit/attributes_spec.rb +0 -146
  73. data/spec/unit/base_active_model_spec.rb +0 -28
  74. data/spec/unit/base_cma_spec.rb +0 -15
  75. data/spec/unit/base_extra_spec.rb +0 -33
  76. data/spec/unit/base_spec.rb +0 -328
  77. data/spec/unit/builder/has_and_belongs_to_many_spec.rb +0 -8
  78. data/spec/unit/callback_spec.rb +0 -65
  79. data/spec/unit/change_set_spec.rb +0 -60
  80. data/spec/unit/checksum_spec.rb +0 -25
  81. data/spec/unit/code_configurator_spec.rb +0 -41
  82. data/spec/unit/collection_proxy_spec.rb +0 -25
  83. data/spec/unit/config_spec.rb +0 -18
  84. data/spec/unit/core/fedora_id_translator_spec.rb +0 -29
  85. data/spec/unit/core/fedora_uri_translator_spec.rb +0 -19
  86. data/spec/unit/core/logger_spec.rb +0 -18
  87. data/spec/unit/core_spec.rb +0 -242
  88. data/spec/unit/default_model_mapper_spec.rb +0 -39
  89. data/spec/unit/fedora_spec.rb +0 -31
  90. data/spec/unit/file/streaming_spec.rb +0 -33
  91. data/spec/unit/file_configurator_spec.rb +0 -295
  92. data/spec/unit/file_io_spec.rb +0 -137
  93. data/spec/unit/file_path_builder_spec.rb +0 -18
  94. data/spec/unit/file_spec.rb +0 -489
  95. data/spec/unit/files_hash_spec.rb +0 -52
  96. data/spec/unit/filter_spec.rb +0 -133
  97. data/spec/unit/finder_methods_spec.rb +0 -154
  98. data/spec/unit/fixity_service_spec.rb +0 -128
  99. data/spec/unit/forbidden_attributes_protection_spec.rb +0 -50
  100. data/spec/unit/has_and_belongs_to_many_association_spec.rb +0 -125
  101. data/spec/unit/has_many_association_spec.rb +0 -131
  102. data/spec/unit/indexers/global_indexer_spec.rb +0 -41
  103. data/spec/unit/indexing/map/index_object_spec.rb +0 -25
  104. data/spec/unit/indexing/map_spec.rb +0 -27
  105. data/spec/unit/indexing_service_spec.rb +0 -28
  106. data/spec/unit/indexing_spec.rb +0 -86
  107. data/spec/unit/inheritance_spec.rb +0 -60
  108. data/spec/unit/ldp_resource_spec.rb +0 -15
  109. data/spec/unit/loadable_from_json_spec.rb +0 -40
  110. data/spec/unit/logger_spec.rb +0 -19
  111. data/spec/unit/model_classifier_spec.rb +0 -49
  112. data/spec/unit/ordered_spec.rb +0 -367
  113. data/spec/unit/orders/list_node_spec.rb +0 -151
  114. data/spec/unit/orders/ordered_list_spec.rb +0 -335
  115. data/spec/unit/orders/reflection_spec.rb +0 -22
  116. data/spec/unit/pathing_spec.rb +0 -35
  117. data/spec/unit/persistence_spec.rb +0 -115
  118. data/spec/unit/property_predicate_spec.rb +0 -35
  119. data/spec/unit/property_spec.rb +0 -25
  120. data/spec/unit/query_result_builder_spec.rb +0 -31
  121. data/spec/unit/query_spec.rb +0 -307
  122. data/spec/unit/querying_spec.rb +0 -24
  123. data/spec/unit/rdf/indexing_service_spec.rb +0 -114
  124. data/spec/unit/rdf_vocab_spec.rb +0 -30
  125. data/spec/unit/readonly_spec.rb +0 -24
  126. data/spec/unit/reflection_spec.rb +0 -42
  127. data/spec/unit/rspec_matchers/belong_to_associated_active_fedora_object_matcher_spec.rb +0 -37
  128. data/spec/unit/rspec_matchers/have_many_associated_active_fedora_objects_matcher_spec.rb +0 -38
  129. data/spec/unit/rspec_matchers/have_predicate_matcher_spec.rb +0 -38
  130. data/spec/unit/schema_indexing_strategy_spec.rb +0 -68
  131. data/spec/unit/scoping_spec.rb +0 -67
  132. data/spec/unit/serializers_spec.rb +0 -19
  133. data/spec/unit/solr_config_options_spec.rb +0 -57
  134. data/spec/unit/solr_hit_spec.rb +0 -57
  135. data/spec/unit/solr_query_builder_spec.rb +0 -18
  136. data/spec/unit/solr_service_spec.rb +0 -165
  137. data/spec/unit/sparql_insert_spec.rb +0 -31
  138. data/spec/unit/validations_spec.rb +0 -92
  139. data/spec/unit/with_metadata/default_metadata_class_factory_spec.rb +0 -29
  140. data/spec/unit/with_metadata/metadata_node_spec.rb +0 -69
@@ -1,41 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveFedora::Base do
4
- before do
5
- class Foo < ActiveFedora::Base
6
- # Date attributes are recognized by having index.type :Date or class_name: 'DateTime'
7
- property :date, predicate: ::RDF::Vocab::DC.date do |index|
8
- index.type :date
9
- end
10
- property :integer, predicate: ::RDF::URI.new('http://www.example.com/integer'), multiple: false do |index|
11
- index.type :integer
12
- end
13
- property :single_date, multiple: false, class_name: 'DateTime', predicate: ::RDF::URI.new('http://www.example.com/single_date')
14
- property :missing_date, multiple: false, class_name: 'DateTime', predicate: ::RDF::URI.new('http://www.example.com/missing_date')
15
- property :empty_date, multiple: false, class_name: 'DateTime', predicate: ::RDF::URI.new('http://www.example.com/empty_date')
16
- end
17
- end
18
-
19
- after do
20
- Object.send(:remove_const, :Foo)
21
- end
22
-
23
- let(:date) { DateTime.parse("2015-10-22T10:20:03.653+01:00") }
24
- let(:date2) { DateTime.parse("2015-10-22T15:34:20.323-11:00") }
25
-
26
- describe "saving and loading in Fedora" do
27
- let(:object) { Foo.create!(date: [date], single_date: date2, empty_date: '', integer: 1).reload }
28
- it "loads the correct time" do
29
- expect(object.date.first).to eql date
30
- expect(object.single_date).to eql date2
31
- end
32
- end
33
-
34
- describe 'serializing' do
35
- let(:object) { Foo.new(date: [date]) }
36
- let(:triple) { object.resource.query(predicate: ::RDF::Vocab::DC.date).to_a.first }
37
- it 'time zone must have semicolin to be a cannonical XMLSchema#dateTime' do
38
- expect(triple.to_s).to match(/\+01:00/)
39
- end
40
- end
41
- end
@@ -1,64 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveFedora::Base do
4
- before(:all) do
5
- module SpecModel
6
- class Basic < ActiveFedora::Base
7
- class_attribute :callback_counter
8
-
9
- before_destroy :inc_counter
10
-
11
- def inc_counter
12
- self.class.callback_counter += 1
13
- end
14
- end
15
- end
16
- end
17
-
18
- after(:all) do
19
- Object.send(:remove_const, :SpecModel)
20
- end
21
-
22
- let!(:model1) { SpecModel::Basic.create! }
23
- let!(:model2) { SpecModel::Basic.create! }
24
-
25
- before do
26
- SpecModel::Basic.callback_counter = 0
27
- end
28
-
29
- describe ".destroy_all" do
30
- it "removes both and run callbacks" do
31
- SpecModel::Basic.destroy_all
32
- expect(SpecModel::Basic.count).to eq 0
33
- expect(SpecModel::Basic.callback_counter).to eq 2
34
- end
35
-
36
- describe "when a model is missing" do
37
- let(:model3) { SpecModel::Basic.create! }
38
- let!(:id) { model3.id }
39
-
40
- before { Ldp::Resource::RdfSource.new(ActiveFedora.fedora.connection, model3.uri).delete }
41
-
42
- after do
43
- ActiveFedora::SolrService.instance.conn.tap do |conn|
44
- conn.delete_by_query "id:\"#{id}\""
45
- conn.commit
46
- end
47
- end
48
-
49
- it "is able to skip a missing model" do
50
- expect(described_class.logger).to receive(:error).with("Although #{id} was found in Solr, it doesn't seem to exist in Fedora. The index is out of synch.")
51
- SpecModel::Basic.destroy_all
52
- expect(SpecModel::Basic.count).to eq 1
53
- end
54
- end
55
- end
56
-
57
- describe ".delete_all" do
58
- it "removes both and not run callbacks" do
59
- SpecModel::Basic.delete_all
60
- expect(SpecModel::Basic.count).to eq 0
61
- expect(SpecModel::Basic.callback_counter).to eq 0
62
- end
63
- end
64
- end
@@ -1,250 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe "Direct containers" do
4
- describe "#directly_contains" do
5
- context "when the class is ActiveFedora::File" do
6
- before do
7
- class FooHistory < ActiveFedora::Base
8
- directly_contains :files, has_member_relation: ::RDF::URI.new("http://example.com/hasFiles")
9
- end
10
- end
11
- after do
12
- Object.send(:remove_const, :FooHistory)
13
- end
14
-
15
- let(:file) { o.files.build }
16
- let(:reloaded) { FooHistory.find(o.id) }
17
-
18
- context "with no files" do
19
- subject { o.files }
20
- let(:o) { FooHistory.new }
21
-
22
- it { is_expected.to be_empty }
23
- it { is_expected.to eq [] }
24
- end
25
-
26
- context "when the object exists" do
27
- let(:o) { FooHistory.create }
28
-
29
- before do
30
- file.content = "HMMM"
31
- o.save
32
- end
33
-
34
- describe "#first" do
35
- subject(:first_file) { reloaded.files.first }
36
- it "has the content" do
37
- expect(first_file.content).to eq 'HMMM'
38
- end
39
- end
40
-
41
- describe "#to_a" do
42
- subject(:files) { reloaded.files }
43
- it "has the content" do
44
- expect(files.to_a).to eq [file]
45
- end
46
- end
47
-
48
- describe "#append" do
49
- let(:file2) { o.files.build }
50
- it "has two files" do
51
- expect(o.files).to contain_exactly file, file2
52
- end
53
-
54
- context "and then saved/reloaded" do
55
- before do
56
- file2.content = "Derp"
57
- o.save!
58
- end
59
- it "has two files" do
60
- expect(reloaded.files).to contain_exactly file, file2
61
- end
62
- end
63
- end
64
- end
65
-
66
- context "when the object is new" do
67
- let(:o) { FooHistory.new }
68
- let(:file) { o.files.build }
69
-
70
- it "fails" do
71
- # This is the expected behavior right now. In the future make the uri get assigned by autosave.
72
- expect { o.files.build }.to raise_error "Can't get uri. Owner isn't saved"
73
- end
74
- end
75
- end
76
-
77
- context "when the class is a subclass of ActiveFedora::File" do
78
- before do
79
- class SubFile < ActiveFedora::File; end
80
- class FooHistory < ActiveFedora::Base
81
- directly_contains :files, has_member_relation: ::RDF::URI.new("http://example.com/hasFiles"), class_name: 'SubFile'
82
- end
83
- end
84
- after do
85
- Object.send(:remove_const, :FooHistory)
86
- Object.send(:remove_const, :SubFile)
87
- end
88
-
89
- let(:o) { FooHistory.create }
90
- let(:file) { o.files.build }
91
- let(:reloaded) { FooHistory.find(o.id) }
92
-
93
- describe "#build" do
94
- subject { file }
95
- it { is_expected.to be_kind_of SubFile }
96
- end
97
-
98
- context "when the object exists" do
99
- before do
100
- file.content = "HMMM"
101
- o.save
102
- end
103
-
104
- describe "#first" do
105
- subject(:first_file) { reloaded.files.first }
106
- it "has the content" do
107
- expect(first_file.content).to eq 'HMMM'
108
- end
109
- end
110
- end
111
- end
112
-
113
- context "when using is_member_of_relation" do
114
- before do
115
- class FooHistory < ActiveFedora::Base
116
- directly_contains :files, is_member_of_relation: ::RDF::URI.new("http://example.com/isWithin")
117
- end
118
- end
119
- after do
120
- Object.send(:remove_const, :FooHistory)
121
- end
122
-
123
- let(:file) { o.files.build }
124
- let(:reloaded) { FooHistory.find(o.id) }
125
-
126
- context "with no files" do
127
- subject { o.files }
128
- let(:o) { FooHistory.new }
129
-
130
- it { is_expected.to be_empty }
131
- it { is_expected.to eq [] }
132
- end
133
-
134
- context "when the object exists" do
135
- let(:o) { FooHistory.create }
136
-
137
- before do
138
- file.content = "HMMM"
139
- o.save
140
- end
141
-
142
- describe "#first" do
143
- subject(:first_file) { reloaded.files.first }
144
- it "has the content" do
145
- expect(first_file.content).to eq 'HMMM'
146
- end
147
- end
148
- end
149
- end
150
-
151
- context "deleting members" do
152
- before do
153
- class FooHistory < ActiveFedora::Base
154
- directly_contains :files, is_member_of_relation: ::RDF::URI.new("http://example.com/isWithin")
155
- end
156
- end
157
- after do
158
- Object.send(:remove_const, :FooHistory)
159
- end
160
-
161
- describe "#delete the contained object directly" do
162
- let(:history) { FooHistory.create }
163
- let(:file1) { history.files.build }
164
- let(:file2) { history.files.build }
165
-
166
- before do
167
- file1.content = "hello"
168
- file2.content = "hola"
169
- history.save
170
- history.reload
171
- end
172
-
173
- it "deletes the contained resource directly" do
174
- expect(history.files).to contain_exactly file1, file2
175
- file1.delete
176
- history.reload
177
- expect(history.files).to eq [file2]
178
- end
179
- end
180
-
181
- describe "#delete via the collection proxy" do
182
- let(:history) { FooHistory.create }
183
- let(:file1) { history.files.build }
184
- let(:file2) { history.files.build }
185
-
186
- before do
187
- file1.content = "hello"
188
- file2.content = "hola"
189
- history.save
190
- history.reload
191
- end
192
-
193
- it "deletes the contained resource via the collection proxy" do
194
- expect(history.reload.files).to contain_exactly file1, file2
195
- history.files.delete(file1)
196
- expect(history.reload.files).to eq [file2]
197
- end
198
- end
199
- end
200
- end
201
-
202
- describe "#include?" do
203
- before do
204
- class FooHistory < ActiveFedora::Base
205
- directly_contains :files, has_member_relation: ::RDF::URI.new('http://example.com/hasFiles')
206
- end
207
- end
208
-
209
- after do
210
- Object.send(:remove_const, :FooHistory)
211
- end
212
-
213
- let(:foo) { FooHistory.create }
214
-
215
- let!(:file1) { foo.files.build }
216
-
217
- before do
218
- file1.content = 'hmm'
219
- foo.save
220
- end
221
-
222
- context "when it is not loaded" do
223
- context "and it contains the file" do
224
- subject { foo.reload.files.include? file1 }
225
- it { is_expected.to be true }
226
- end
227
-
228
- context "and it doesn't contain the file" do
229
- let!(:file2) { ActiveFedora::File.new { |f| f.content = 'hmm'; f.save } }
230
- subject { foo.reload.files.include? file2 }
231
- it { is_expected.to be false }
232
- end
233
- end
234
-
235
- context "when it is loaded" do
236
- before { foo.files.to_a } # initial load of the association
237
-
238
- context "and it contains the file" do
239
- subject { foo.files.include? file1 }
240
- it { is_expected.to be true }
241
- end
242
-
243
- context "and it doesn't contain the file" do
244
- let!(:file2) { ActiveFedora::File.new { |f| f.content = 'hmm'; f.save } }
245
- subject { foo.files.include? file2 }
246
- it { is_expected.to be false }
247
- end
248
- end
249
- end
250
- end
@@ -1,96 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiveFedora::Base do
4
- before do
5
- class PageImage < ActiveFedora::Base
6
- directly_contains :files, has_member_relation: ::RDF::URI.new("http://example.com/hasFiles"), class_name: "FileWithMetadata"
7
- directly_contains_one :primary_file, through: :files, type: ::RDF::URI.new("http://example.com/primaryFile"), class_name: "FileWithMetadata"
8
- directly_contains_one :alternative_file, through: :files, type: ::RDF::URI.new("http://example.com/featuredFile"), class_name: 'AlternativeFileWithMetadata'
9
- end
10
-
11
- class FileWithMetadata < ActiveFedora::File
12
- include ActiveFedora::WithMetadata
13
- end
14
- class AlternativeFileWithMetadata < ActiveFedora::File
15
- include ActiveFedora::WithMetadata
16
- end
17
- end
18
-
19
- after do
20
- Object.send(:remove_const, :PageImage)
21
- Object.send(:remove_const, :FileWithMetadata)
22
- Object.send(:remove_const, :AlternativeFileWithMetadata)
23
- end
24
-
25
- let(:page_image) { PageImage.create }
26
- let(:reloaded_page_image) { PageImage.find(page_image.id) }
27
-
28
- let(:a_file) { page_image.files.build }
29
- let(:primary_file) { page_image.build_primary_file }
30
- let(:alternative_file) { page_image.build_alternative_file }
31
- let(:primary_sub_image) { page_image.build_primary_sub_image }
32
-
33
- context "#build" do
34
- context "when container element is a type of ActiveFedora::File" do
35
- before do
36
- primary_file.content = "I'm in a container all alone!"
37
- page_image.save!
38
- end
39
- subject(:reloaded_file) { reloaded_page_image.primary_file }
40
- it "initializes an object within the container" do
41
- expect(reloaded_file.content).to eq("I'm in a container all alone!")
42
- expect(reloaded_file.metadata_node.type).to include(::RDF::URI.new("http://example.com/primaryFile"))
43
- end
44
- it "relies on info from the :through association, including class_name" do
45
- expect(page_image.files).to include(primary_file)
46
- expect(primary_file.uri.to_s).to include("/files/")
47
- expect(reloaded_file.class).to eq FileWithMetadata
48
- end
49
- end
50
- end
51
-
52
- context "finder" do
53
- subject { reloaded_page_image.primary_file }
54
- context "when no matching child is set" do
55
- before { page_image.files.build }
56
- it { is_expected.to be_nil }
57
- end
58
- context "when a matching object is directly contained" do
59
- before do
60
- a_file.content = "I'm a file"
61
- primary_file.content = "I am too"
62
- page_image.save!
63
- end
64
- it { is_expected.to eq primary_file }
65
- end
66
- context "if class_name is set" do
67
- before do
68
- a_file.content = "I'm a file"
69
- alternative_file.content = "I am too"
70
- page_image.save!
71
- end
72
- subject(:reloaded_file) { reloaded_page_image.alternative_file }
73
- it "uses the specified class to load objects" do
74
- expect(reloaded_file).to eq alternative_file
75
- expect(reloaded_file).to be_instance_of AlternativeFileWithMetadata
76
- end
77
- end
78
- end
79
-
80
- describe "setter" do
81
- before do
82
- a_file.content = "I'm a file"
83
- primary_file.content = "I am too"
84
- page_image.save!
85
- end
86
- subject(:reloaded_file) { reloaded_page_image.files }
87
- it "replaces existing record without disturbing the other contents of the container" do
88
- replacement_file = page_image.primary_file = FileWithMetadata.new
89
- replacement_file.content = "I'm a replacement"
90
- page_image.save
91
- expect(reloaded_file).to_not include(primary_file)
92
- expect(reloaded_file).to contain_exactly(a_file, replacement_file)
93
- expect(reloaded_page_image.primary_file).to eq(replacement_file)
94
- end
95
- end
96
- end