Module: CollectionObject::DwcExtensions
- Extended by:
- ActiveSupport::Concern
- Included in:
- BiologicalCollectionObject
- Defined in:
- app/models/collection_object/dwc_extensions.rb
Instance Method Summary collapse
-
#api_image_link(image) ⇒ Object
TODO: likeley a helper.
- #dwc_associated_media ⇒ Object
- #dwc_catalog_number ⇒ Object
- #dwc_class ⇒ Object
- #dwc_collection_code ⇒ Object
-
#dwc_coordinate_uncertainty_in_meters ⇒ Object
TODO: extend to Georeferences when we understand how to describe spatial uncertainty.
- #dwc_country ⇒ Object
- #dwc_county ⇒ Object
-
#dwc_date_identified ⇒ Object
ISO 8601:2004(E).
- #dwc_day ⇒ Object
- #dwc_decimal_latitude ⇒ Object
- #dwc_decimal_longitude ⇒ Object
- #dwc_end_day_of_year ⇒ Object
- #dwc_event_date ⇒ Object
- #dwc_event_time ⇒ Object
- #dwc_family ⇒ Object
- #dwc_field_number ⇒ Object
- #dwc_footprint_wkt ⇒ Object
- #dwc_genus ⇒ Object
- #dwc_geodetic_datum ⇒ Object
- #dwc_georeference_protocol ⇒ Object
- #dwc_georeference_remarks ⇒ Object
- #dwc_georeference_sources ⇒ Object
- #dwc_georeferenced_by ⇒ Object
-
#dwc_georeferenced_date ⇒ Object
georeferenceDate technically could look at papertrail to see when geographic_area_id appeared.
- #dwc_higher_classification ⇒ Object
- #dwc_identified_by ⇒ Object
- #dwc_identified_by_id ⇒ Object
-
#dwc_individual_count ⇒ Object
TODO: handle ranged lots.
- #dwc_infraspecific_epithet ⇒ Object
-
#dwc_institution_code ⇒ Object
we assert custody, NOT ownership.
-
#dwc_institution_id ⇒ Object
we assert custody, NOT ownership.
- #dwc_internal_attribute_for(target = :collection_object, dwc_term_name) ⇒ Object
- #dwc_kingdom ⇒ Object
-
#dwc_life_stage ⇒ Object
TODO: consider CVT attributes with Predicates linked to URIs.
- #dwc_locality ⇒ Object
- #dwc_maximum_depth_in_meters ⇒ Object
- #dwc_maximum_elevation_in_meters ⇒ Object
- #dwc_minimum_depth_in_meters ⇒ Object
- #dwc_minimum_elevation_in_meters ⇒ Object
- #dwc_month ⇒ Object
- #dwc_nomenclatural_code ⇒ Object
- #dwc_occurrence_remarks ⇒ Object
- #dwc_occurrence_status ⇒ Object
- #dwc_order ⇒ Object
- #dwc_other_catalog_numbers ⇒ Object
- #dwc_phylum ⇒ Object
- #dwc_preparations ⇒ Object
- #dwc_previous_identifications ⇒ Object
-
#dwc_recorded_by ⇒ Object
Definition: A list (concatenated and separated) of names of people, groups, or organizations responsible for recording the original Occurrence.
-
#dwc_recorded_by_id ⇒ Object
See dwc_recorded_by.
-
#dwc_sampling_protocol ⇒ Object
TODO: Reconcile with Protocol (capital P) assignments.
- #dwc_scientific_name ⇒ Object
-
#dwc_sex ⇒ Object
TODO: consider CVT attributes with Predicates linked to URIs.
- #dwc_specific_epithet ⇒ Object
- #dwc_start_day_of_year ⇒ Object
- #dwc_state_province ⇒ Object
- #dwc_taxon_name_authorship ⇒ Object
- #dwc_taxon_rank ⇒ Object
-
#dwc_type_status ⇒ Object
holotype of Ctenomys sociabilis.
- #dwc_verbatim_coordinates ⇒ Object
- #dwc_verbatim_depth ⇒ Object
- #dwc_verbatim_elevation ⇒ Object
- #dwc_verbatim_event_date ⇒ Object
- #dwc_verbatim_habitat ⇒ Object
- #dwc_verbatim_latitude ⇒ Object
- #dwc_verbatim_locality ⇒ Object
- #dwc_verbatim_longitude ⇒ Object
- #dwc_verbatim_srs ⇒ Object
- #dwc_water_body ⇒ Object
- #dwc_year ⇒ Object
- #is_fossil? ⇒ Boolean
- #set_georeference_attributes ⇒ Hash
Instance Method Details
#api_image_link(image) ⇒ Object
TODO: likeley a helper
167 168 169 170 171 172 173 174 175 176 |
# File 'app/models/collection_object/dwc_extensions.rb', line 167 def api_image_link(image) s = ENV['SERVER_NAME'] if s.nil? s ||= 'http://127.0.0.1:3000' else s = 'https://' + s end s = s + '/api/v1/images/' + image.image_file_fingerprint # An experiment, use md5 as a proxy for id (also unique id) end |
#dwc_associated_media ⇒ Object
162 163 164 |
# File 'app/models/collection_object/dwc_extensions.rb', line 162 def dwc_associated_media images.collect{|i| api_image_link(i) }.join(CollectionObject::DWC_DELIMITER).presence end |
#dwc_catalog_number ⇒ Object
438 439 440 |
# File 'app/models/collection_object/dwc_extensions.rb', line 438 def dwc_catalog_number catalog_number_cached # via delegation end |
#dwc_class ⇒ Object
359 360 361 |
# File 'app/models/collection_object/dwc_extensions.rb', line 359 def dwc_class taxonomy['class'] end |
#dwc_collection_code ⇒ Object
434 435 436 |
# File 'app/models/collection_object/dwc_extensions.rb', line 434 def dwc_collection_code catalog_number_namespace&.verbatim_short_name || catalog_number_namespace&.short_name end |
#dwc_coordinate_uncertainty_in_meters ⇒ Object
TODO: extend to Georeferences when we understand how to describe spatial uncertainty
213 214 215 216 217 218 219 |
# File 'app/models/collection_object/dwc_extensions.rb', line 213 def dwc_coordinate_uncertainty_in_meters if georeference_attributes[:coordinateUncertaintyInMeters] georeference_attributes[:coordinateUncertaintyInMeters] else collecting_event&.verbatim_geolocation_uncertainty end end |
#dwc_country ⇒ Object
447 448 449 450 |
# File 'app/models/collection_object/dwc_extensions.rb', line 447 def dwc_country v = try(:collecting_event).try(:geographic_names) v[:country] if v end |
#dwc_county ⇒ Object
457 458 459 460 |
# File 'app/models/collection_object/dwc_extensions.rb', line 457 def dwc_county v = try(:collecting_event).try(:geographic_names) v[:county] if v end |
#dwc_date_identified ⇒ Object
ISO 8601:2004(E).
339 340 341 |
# File 'app/models/collection_object/dwc_extensions.rb', line 339 def dwc_date_identified current_taxon_determination&.date.presence end |
#dwc_day ⇒ Object
522 523 524 525 |
# File 'app/models/collection_object/dwc_extensions.rb', line 522 def dwc_day return unless collecting_event collecting_event.start_date_day.presence end |
#dwc_decimal_latitude ⇒ Object
466 467 468 |
# File 'app/models/collection_object/dwc_extensions.rb', line 466 def dwc_decimal_latitude georeference_attributes[:decimalLatitude] end |
#dwc_decimal_longitude ⇒ Object
470 471 472 |
# File 'app/models/collection_object/dwc_extensions.rb', line 470 def dwc_decimal_longitude georeference_attributes[:decimalLongitude] end |
#dwc_end_day_of_year ⇒ Object
532 533 534 535 |
# File 'app/models/collection_object/dwc_extensions.rb', line 532 def dwc_end_day_of_year return unless collecting_event collecting_event.end_day_of_year.presence end |
#dwc_event_date ⇒ Object
499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'app/models/collection_object/dwc_extensions.rb', line 499 def dwc_event_date return unless collecting_event %w{start_date end_date} .map { |d| %w{year month day} .map { |p| collecting_event["#{d}_#{p}"] } .map { |p| "%02d" % p if p } # At least two digits } .map { |d| d.compact.join('-') } .reject(&:blank?) .join("/").presence end |
#dwc_event_time ⇒ Object
482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'app/models/collection_object/dwc_extensions.rb', line 482 def dwc_event_time return unless collecting_event %w{start_time end_time} .map { |t| %w{hour minute second} .map { |p| collecting_event["#{t}_#{p}"] } .map { |p| "%02d" % p if p } # At least two digits } .map { |t| t.compact.join(':') } .reject(&:blank?) .join("/").presence end |
#dwc_family ⇒ Object
368 369 370 |
# File 'app/models/collection_object/dwc_extensions.rb', line 368 def dwc_family taxonomy['family'] end |
#dwc_field_number ⇒ Object
311 312 313 314 |
# File 'app/models/collection_object/dwc_extensions.rb', line 311 def dwc_field_number return nil unless collecting_event collecting_event.identifiers.where(type: 'Identifier::Local::TripCode').first&.cached end |
#dwc_footprint_wkt ⇒ Object
186 187 188 |
# File 'app/models/collection_object/dwc_extensions.rb', line 186 def dwc_footprint_wkt georeference_attributes[:footprintWKT] end |
#dwc_genus ⇒ Object
373 374 375 |
# File 'app/models/collection_object/dwc_extensions.rb', line 373 def dwc_genus taxonomy['genus'] && taxonomy['genus'].compact.join(' ').presence end |
#dwc_geodetic_datum ⇒ Object
198 199 200 |
# File 'app/models/collection_object/dwc_extensions.rb', line 198 def dwc_geodetic_datum georeference_attributes[:geodeticDatum] end |
#dwc_georeference_protocol ⇒ Object
551 552 553 |
# File 'app/models/collection_object/dwc_extensions.rb', line 551 def dwc_georeference_protocol georeference_attributes[:georeferenceProtocol] end |
#dwc_georeference_remarks ⇒ Object
182 183 184 |
# File 'app/models/collection_object/dwc_extensions.rb', line 182 def dwc_georeference_remarks georeference_attributes[:georeferenceRemarks] end |
#dwc_georeference_sources ⇒ Object
178 179 180 |
# File 'app/models/collection_object/dwc_extensions.rb', line 178 def dwc_georeference_sources georeference_attributes[:georeferenceSources] end |
#dwc_georeferenced_by ⇒ Object
190 191 192 |
# File 'app/models/collection_object/dwc_extensions.rb', line 190 def dwc_georeferenced_by georeference_attributes[:georeferencedBy] end |
#dwc_georeferenced_date ⇒ Object
georeferenceDate technically could look at papertrail to see when geographic_area_id appeared
208 209 210 |
# File 'app/models/collection_object/dwc_extensions.rb', line 208 def dwc_georeferenced_date georeference_attributes[:georeferencedDate] end |
#dwc_higher_classification ⇒ Object
343 344 345 346 347 348 349 |
# File 'app/models/collection_object/dwc_extensions.rb', line 343 def dwc_higher_classification v = taxonomy.values.collect{|a| a.kind_of?(Array) ? a.second : a} v.shift v.pop v.compact v.join(CollectionObject::DWC_DELIMITER) end |
#dwc_identified_by ⇒ Object
420 421 422 423 |
# File 'app/models/collection_object/dwc_extensions.rb', line 420 def dwc_identified_by # TaxonWorks allows for groups of determiners to collaborate on a single determination if they collectively came to a conclusion. current_taxon_determination&.determiners&.map(&:cached)&.join(CollectionObject::DWC_DELIMITER).presence end |
#dwc_identified_by_id ⇒ Object
425 426 427 428 |
# File 'app/models/collection_object/dwc_extensions.rb', line 425 def dwc_identified_by_id # TaxonWorks allows for groups of determiners to collaborate on a single determination if they collectively came to a conclusion. current_taxon_determination&.determiners&.map(&:orcid)&.join(CollectionObject::DWC_DELIMITER).presence end |
#dwc_individual_count ⇒ Object
TODO: handle ranged lots
443 444 445 |
# File 'app/models/collection_object/dwc_extensions.rb', line 443 def dwc_individual_count total end |
#dwc_infraspecific_epithet ⇒ Object
320 321 322 323 324 325 |
# File 'app/models/collection_object/dwc_extensions.rb', line 320 def dwc_infraspecific_epithet %w{variety form subspecies}.each do |n| # add more as observed return taxonomy[n].last if taxonomy[n] end nil end |
#dwc_institution_code ⇒ Object
we assert custody, NOT ownership
542 543 544 |
# File 'app/models/collection_object/dwc_extensions.rb', line 542 def dwc_institution_code repository.try(:acronym) end |
#dwc_institution_id ⇒ Object
we assert custody, NOT ownership
547 548 549 |
# File 'app/models/collection_object/dwc_extensions.rb', line 547 def dwc_institution_id repository_url end |
#dwc_internal_attribute_for(target = :collection_object, dwc_term_name) ⇒ Object
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
# File 'app/models/collection_object/dwc_extensions.rb', line 241 def dwc_internal_attribute_for(target = :collection_object, dwc_term_name) return nil if dwc_term_name.nil? case target when :collecting_event return nil unless collecting_event collecting_event.internal_attributes.includes(:predicate) .where( controlled_vocabulary_terms: {uri: ::DWC_ATTRIBUTE_URIS[dwc_term_name.to_sym] }) .pluck(:value)&.join(', ').presence when :collection_object internal_attributes.includes(:predicate) .where( controlled_vocabulary_terms: {uri: ::DWC_ATTRIBUTE_URIS[dwc_term_name.to_sym] }) .pluck(:value)&.join(', ').presence else nil end end |
#dwc_kingdom ⇒ Object
351 352 353 |
# File 'app/models/collection_object/dwc_extensions.rb', line 351 def dwc_kingdom taxonomy['kingdom'] end |
#dwc_life_stage ⇒ Object
TODO: consider CVT attributes with Predicates linked to URIs
278 279 280 281 |
# File 'app/models/collection_object/dwc_extensions.rb', line 278 def dwc_life_stage biocuration_classes.tagged_with_uri(::DWC_ATTRIBUTE_URIS[:lifeStage]) .pluck(:name)&.join(', ').presence # `.presence` is a Rails extension end |
#dwc_locality ⇒ Object
462 463 464 |
# File 'app/models/collection_object/dwc_extensions.rb', line 462 def dwc_locality collecting_event.try(:verbatim_locality) end |
#dwc_maximum_depth_in_meters ⇒ Object
269 270 271 |
# File 'app/models/collection_object/dwc_extensions.rb', line 269 def dwc_maximum_depth_in_meters dwc_internal_attribute_for(:collecting_event, :maximumDepthInMeters) end |
#dwc_maximum_elevation_in_meters ⇒ Object
298 299 300 |
# File 'app/models/collection_object/dwc_extensions.rb', line 298 def dwc_maximum_elevation_in_meters collecting_event&.maximum_elevation end |
#dwc_minimum_depth_in_meters ⇒ Object
265 266 267 |
# File 'app/models/collection_object/dwc_extensions.rb', line 265 def dwc_minimum_depth_in_meters dwc_internal_attribute_for(:collecting_event, :minimumDepthInMeters) end |
#dwc_minimum_elevation_in_meters ⇒ Object
302 303 304 |
# File 'app/models/collection_object/dwc_extensions.rb', line 302 def dwc_minimum_elevation_in_meters collecting_event&.minimum_elevation end |
#dwc_month ⇒ Object
517 518 519 520 |
# File 'app/models/collection_object/dwc_extensions.rb', line 517 def dwc_month return unless collecting_event collecting_event.start_date_month.presence end |
#dwc_nomenclatural_code ⇒ Object
478 479 480 |
# File 'app/models/collection_object/dwc_extensions.rb', line 478 def dwc_nomenclatural_code current_otu.try(:taxon_name).try(:nomenclatural_code) end |
#dwc_occurrence_remarks ⇒ Object
157 158 159 |
# File 'app/models/collection_object/dwc_extensions.rb', line 157 def dwc_occurrence_remarks notes.collect{|n| n.text}.join('|') end |
#dwc_occurrence_status ⇒ Object
152 153 154 |
# File 'app/models/collection_object/dwc_extensions.rb', line 152 def dwc_occurrence_status 'present' end |
#dwc_order ⇒ Object
363 364 365 |
# File 'app/models/collection_object/dwc_extensions.rb', line 363 def dwc_order taxonomy['order'] end |
#dwc_other_catalog_numbers ⇒ Object
229 230 231 232 233 |
# File 'app/models/collection_object/dwc_extensions.rb', line 229 def dwc_other_catalog_numbers i = identifiers.where.not('type ilike ?', 'Identifier::Global::Uuid%').order(:position).to_a i.shift i.map(&:cached).join(CollectionObject::DWC_DELIMITER).presence end |
#dwc_phylum ⇒ Object
355 356 357 |
# File 'app/models/collection_object/dwc_extensions.rb', line 355 def dwc_phylum taxonomy['phylum'] end |
#dwc_preparations ⇒ Object
537 538 539 |
# File 'app/models/collection_object/dwc_extensions.rb', line 537 def dwc_preparations preparation_type_name end |
#dwc_previous_identifications ⇒ Object
235 236 237 238 239 |
# File 'app/models/collection_object/dwc_extensions.rb', line 235 def dwc_previous_identifications a = taxon_determinations.order(:position).to_a a.shift a.collect{|d| ApplicationController.helpers.label_for_taxon_determination(d)}.join(CollectionObject::DWC_DELIMITER).presence end |
#dwc_recorded_by ⇒ Object
Definition: A list (concatenated and separated) of names of people, groups, or organizations responsible for recording the original Occurrence. The primary collector or observer, especially one who applies a personal identifier (recordNumber), should be listed first.
This was interpreted as collectors (in the field in this context), not those who recorded other aspectes of the data.
393 394 395 396 397 398 399 400 401 402 403 404 |
# File 'app/models/collection_object/dwc_extensions.rb', line 393 def dwc_recorded_by v = nil if collecting_event v = collecting_event.collectors .order('roles.position') .pluck(:cached) .join(CollectionObject::DWC_DELIMITER) .presence v = collecting_event.verbatim_collectors.presence if v.blank? end v end |
#dwc_recorded_by_id ⇒ Object
See dwc_recorded_by
407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'app/models/collection_object/dwc_extensions.rb', line 407 def dwc_recorded_by_id if collecting_event collecting_event.collectors .order('roles.position') .map(&:orcid) .compact .join(CollectionObject::DWC_DELIMITER) .presence end end |
#dwc_sampling_protocol ⇒ Object
TODO: Reconcile with Protocol (capital P) assignments
307 308 309 |
# File 'app/models/collection_object/dwc_extensions.rb', line 307 def dwc_sampling_protocol collecting_event&.verbatim_method end |
#dwc_scientific_name ⇒ Object
382 383 384 |
# File 'app/models/collection_object/dwc_extensions.rb', line 382 def dwc_scientific_name current_taxon_name.try(:cached_name_and_author_year) end |
#dwc_sex ⇒ Object
TODO: consider CVT attributes with Predicates linked to URIs
284 285 286 287 |
# File 'app/models/collection_object/dwc_extensions.rb', line 284 def dwc_sex biocuration_classes.tagged_with_uri(::DWC_ATTRIBUTE_URIS[:sex]) .pluck(:name)&.join(', ').presence end |
#dwc_specific_epithet ⇒ Object
378 379 380 |
# File 'app/models/collection_object/dwc_extensions.rb', line 378 def dwc_specific_epithet taxonomy['species'] && taxonomy['species'].compact.join(' ').presence end |
#dwc_start_day_of_year ⇒ Object
527 528 529 530 |
# File 'app/models/collection_object/dwc_extensions.rb', line 527 def dwc_start_day_of_year return unless collecting_event collecting_event.start_day_of_year.presence end |
#dwc_state_province ⇒ Object
452 453 454 455 |
# File 'app/models/collection_object/dwc_extensions.rb', line 452 def dwc_state_province v = try(:collecting_event).try(:geographic_names) v[:state] if v end |
#dwc_taxon_name_authorship ⇒ Object
386 387 388 |
# File 'app/models/collection_object/dwc_extensions.rb', line 386 def current_taxon_name.try(:cached_author_year) end |
#dwc_taxon_rank ⇒ Object
327 328 329 |
# File 'app/models/collection_object/dwc_extensions.rb', line 327 def dwc_taxon_rank current_taxon_name&.rank end |
#dwc_type_status ⇒ Object
holotype of Ctenomys sociabilis. Pearson O. P., and M. I. Christie. 1985. Historia Natural, 5(37):388, holotype of Pinus abies | holotype of Picea abies
332 333 334 335 336 |
# File 'app/models/collection_object/dwc_extensions.rb', line 332 def dwc_type_status type_materials.all.collect{|t| ApplicationController.helpers.label_for_type_material(t) }.join(CollectionObject::DWC_DELIMITER).presence end |
#dwc_verbatim_coordinates ⇒ Object
289 290 291 292 |
# File 'app/models/collection_object/dwc_extensions.rb', line 289 def dwc_verbatim_coordinates return nil unless collecting_event [collecting_event.verbatim_latitude, collecting_event.verbatim_longitude].compact.join(' ').presence end |
#dwc_verbatim_depth ⇒ Object
273 274 275 |
# File 'app/models/collection_object/dwc_extensions.rb', line 273 def dwc_verbatim_depth dwc_internal_attribute_for(:collecting_event, :verbatimDepth) end |
#dwc_verbatim_elevation ⇒ Object
294 295 296 |
# File 'app/models/collection_object/dwc_extensions.rb', line 294 def dwc_verbatim_elevation collecting_event&.verbatim_elevation end |
#dwc_verbatim_event_date ⇒ Object
495 496 497 |
# File 'app/models/collection_object/dwc_extensions.rb', line 495 def dwc_verbatim_event_date collecting_event&.verbatim_date end |
#dwc_verbatim_habitat ⇒ Object
316 317 318 |
# File 'app/models/collection_object/dwc_extensions.rb', line 316 def dwc_verbatim_habitat collecting_event&.verbatim_habitat end |
#dwc_verbatim_latitude ⇒ Object
221 222 223 |
# File 'app/models/collection_object/dwc_extensions.rb', line 221 def dwc_verbatim_latitude collecting_event&.verbatim_latitude end |
#dwc_verbatim_locality ⇒ Object
474 475 476 |
# File 'app/models/collection_object/dwc_extensions.rb', line 474 def dwc_verbatim_locality collecting_event.try(:verbatim_locality) end |
#dwc_verbatim_longitude ⇒ Object
225 226 227 |
# File 'app/models/collection_object/dwc_extensions.rb', line 225 def dwc_verbatim_longitude collecting_event&.verbatim_longitude end |
#dwc_verbatim_srs ⇒ Object
202 203 204 |
# File 'app/models/collection_object/dwc_extensions.rb', line 202 def dwc_verbatim_srs georeference_attributes[:dwcVerbatimSrs] end |
#dwc_water_body ⇒ Object
261 262 263 |
# File 'app/models/collection_object/dwc_extensions.rb', line 261 def dwc_water_body dwc_internal_attribute_for(:collecting_event, :waterBody) end |
#dwc_year ⇒ Object
512 513 514 515 |
# File 'app/models/collection_object/dwc_extensions.rb', line 512 def dwc_year return unless collecting_event collecting_event.start_date_year.presence end |
#is_fossil? ⇒ Boolean
148 149 150 |
# File 'app/models/collection_object/dwc_extensions.rb', line 148 def is_fossil? biocuration_classes.where(uri: DWC_FOSSIL_URI).any? end |
#set_georeference_attributes ⇒ Hash
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'app/models/collection_object/dwc_extensions.rb', line 118 def set_georeference_attributes case collecting_event&.dwc_georeference_source when :georeference collecting_event.preferred_georeference.dwc_georeference_attributes when :verbatim h = collecting_event.dwc_georeference_attributes if a = collecting_event&.attribute_updater(:verbatim_latitude) h[:georeferencedBy] = User.find(a).name end # verbatim_longitude could technically be different, but... h[:georeferencedDate] = collecting_event&.attribute_updated(:verbatim_latitude) h when :geographic_area h = collecting_event.geographic_area.dwc_georeference_attributes if a = collecting_event&.attribute_updater(:geographic_area_id) h[:georeferencedBy] = User.find(a).name end h[:georeferencedDate] = collecting_event&.attribute_updated(:geographic_area_id) h else {} end end |