linked_rails 0.0.4.pre.g76dedd8ba → 0.0.4.pre.g83aa52ab3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c64c5a485e952fa401c1bcea4761f493b4f94650bbec75d7f19e9787dad1f84
4
- data.tar.gz: 4616e0044f6e3fefb204a464347c2dfc5d98adc0d12d11e8ef65e074968af3e0
3
+ metadata.gz: bc8a8c53b8422c4f81be3dbb64c8488b6d80a659b0fb585f252c6d66842f240c
4
+ data.tar.gz: 83172f0d901f0ad055186902ea9f9b5e9500b16bfa2071cad5533127765b57ec
5
5
  SHA512:
6
- metadata.gz: '08c5759176b7e96922b54ba4fdc60c42aa8513ea7265ac9e7e86e9b1f77726e4f113485896f891dc88f8ce056feebef844db3263dfc2d4327e43eb390e31f7f3'
7
- data.tar.gz: b915500d88b3a0cdb03d9e2d8e1d5f724967a353c138e0977afaef890162c423e0f57f2303db73b03004426042066cdeb24dfe6edc169efb104575bf3324c749
6
+ metadata.gz: 0c00be6915256007188a56ed84b1b485dd5c56fcf6e310ab525d66488f26498b0127abb4bf39f6e6b206192d0eed9410b891ba21407794653349bbcde95fc95b
7
+ data.tar.gz: d1488f86b20714eb98e4cbfdf9c8a6765e84be907dae2573274c02adc22047f0a6c206dc10ce2086823ab42028517d7f440e65b121aee53e35ba84b1e57f72b6
@@ -21,11 +21,8 @@ module LinkedRails
21
21
  return response_for_wrong_host(opts) if wrong_host?(opts[:iri])
22
22
 
23
23
  include = opts[:include].to_s == 'true'
24
- resource = LinkedRails.iri_mapper.resource_from_iri(request_path_to_url(opts[:iri]), user_context)
25
24
 
26
- return response_from_request(include, RDF::URI(opts[:iri])) if resource.blank?
27
-
28
- response_from_resource(include, opts[:iri], resource)
25
+ response_from_request(include, RDF::URI(opts[:iri]))
29
26
  rescue StandardError => e
30
27
  handle_resource_error(opts, e)
31
28
  end
@@ -87,13 +84,6 @@ module LinkedRails
87
84
  false
88
85
  end
89
86
 
90
- def resource_cache_control(cacheable, status, resource_policy)
91
- return :private unless status == 200 && cacheable
92
- return 'no-cache' unless resource_policy.try(:public_resource?)
93
-
94
- :public
95
- end
96
-
97
87
  def resource_params(param)
98
88
  params = param.permit(:include, :iri)
99
89
  params[:iri] = URI(params[:iri])
@@ -141,12 +131,6 @@ module LinkedRails
141
131
  }.merge(opts)
142
132
  end
143
133
 
144
- def resource_status(resource_policy)
145
- raise(LinkedRails::Errors::Forbidden.new(query: :show?)) unless resource_policy.show?
146
-
147
- 200
148
- end
149
-
150
134
  def response_for_wrong_host(opts)
151
135
  iri = opts[:iri]
152
136
  term = term_from_vocab(iri)
@@ -155,23 +139,6 @@ module LinkedRails
155
139
  ontology_term_response(iri, term, opts[:include])
156
140
  end
157
141
 
158
- def response_from_resource(include, iri, resource)
159
- resource_policy = policy(resource)
160
- status = resource_status(resource_policy)
161
-
162
- resource_response(
163
- iri,
164
- body: response_from_resource_body(include, iri, resource, status),
165
- cache: resource_cache_control(resource.try(:cacheable?), status, resource_policy),
166
- language: I18n.locale,
167
- status: status
168
- )
169
- end
170
-
171
- def response_from_resource_body(include, _iri, resource, status)
172
- include && status == 200 ? resource_body(resource) : nil
173
- end
174
-
175
142
  def term_from_vocab(iri)
176
143
  vocab = Vocab.for(iri)
177
144
  tag = iri.to_s.split(vocab.to_s).last
@@ -5,7 +5,6 @@ require 'pundit'
5
5
  module LinkedRails
6
6
  class Form # rubocop:disable Metrics/ClassLength
7
7
  include LinkedRails::Model
8
- include LinkedRails::Model::Cacheable
9
8
 
10
9
  class_attribute :abstract_form, :pages, :model_class
11
10
 
@@ -5,27 +5,6 @@ module LinkedRails
5
5
  include ActiveModel::Model
6
6
  include LinkedRails::Model
7
7
 
8
- def save
9
- Storage.hset(
10
- :persistent,
11
- :manifest,
12
- URL.as_href(LinkedRails.iri) => web_manifest.to_json
13
- )
14
- end
15
-
16
- def web_manifest
17
- web_manifest_base.merge(
18
- ontola: web_manifest_ontola_section,
19
- serviceworker: web_manifest_sw_section
20
- )
21
- end
22
-
23
- private
24
-
25
- def allowed_external_sources
26
- []
27
- end
28
-
29
8
  def app_name
30
9
  Rails.application.railtie_name.chomp('_application').humanize
31
10
  end
@@ -38,27 +17,8 @@ module LinkedRails
38
17
  '#eef0f2'
39
18
  end
40
19
 
41
- def blob_preview_iri
42
- return unless ActiveStorage::Blob.service.present?
43
-
44
- LinkedRails.iri(path: 'rails/active_storage/blobs/redirect/{signed_id}/preview')
45
- end
46
-
47
- def blob_upload_iri
48
- return unless ActiveStorage::Blob.service.present?
49
-
50
- LinkedRails.iri(path: 'rails/active_storage/direct_uploads')
51
- end
52
-
53
20
  def css_class; end
54
21
 
55
- def csp_entries
56
- {
57
- connectSrc: [ActiveStorage::Blob.service.try(:bucket)&.url].compact,
58
- scriptSrc: [ActiveStorage::Blob.service.try(:bucket)&.url].compact
59
- }
60
- end
61
-
62
22
  def header_background
63
23
  :primary
64
24
  end
@@ -67,16 +27,17 @@ module LinkedRails
67
27
  :white
68
28
  end
69
29
 
70
- def icons
71
- []
72
- end
73
-
74
- def lang
75
- :nl
30
+ def preload_iris
31
+ [
32
+ scope,
33
+ LinkedRails.iri(path: 'ns/core').to_s,
34
+ LinkedRails.iri(path: 'c_a').to_s,
35
+ LinkedRails.iri(path: 'menus').to_s
36
+ ]
76
37
  end
77
38
 
78
39
  def scope
79
- LinkedRails.iri.to_s
40
+ @scope ||= LinkedRails.iri.to_s
80
41
  end
81
42
 
82
43
  def site_theme_color
@@ -91,46 +52,43 @@ module LinkedRails
91
52
  app_name
92
53
  end
93
54
 
94
- def start_url
95
- scope == '/' ? scope : "#{scope}/"
96
- end
97
-
98
55
  def theme; end
99
56
 
100
57
  def theme_options
101
58
  {}
102
59
  end
103
60
 
61
+ def web_manifest
62
+ web_manifest_base.merge(
63
+ ontola: web_manifest_ontola_section,
64
+ serviceworker: web_manifest_sw_section
65
+ )
66
+ end
67
+
104
68
  def web_manifest_base # rubocop:disable Metrics/MethodLength
105
69
  {
106
70
  background_color: background_color,
107
71
  dir: :rtl,
108
72
  display: :standalone,
109
- icons: icons,
110
- lang: lang,
73
+ lang: :nl,
111
74
  name: app_name,
112
75
  scope: scope,
113
76
  short_name: app_name,
114
- start_url: start_url,
77
+ start_url: scope,
115
78
  theme_color: site_theme_color
116
79
  }
117
80
  end
118
81
 
119
82
  def web_manifest_ontola_section # rubocop:disable Metrics/MethodLength
120
83
  {
121
- allowed_external_sources: allowed_external_sources,
122
- blob_preview_iri: blob_preview_iri,
123
- blob_upload_iri: blob_upload_iri,
124
- csp: csp_entries,
84
+ css_class: css_class,
125
85
  header_background: header_background,
126
86
  header_text: header_text,
127
- preconnect: preconnect,
87
+ preload: preload_iris,
128
88
  primary_color: site_theme_color,
129
89
  secondary_color: site_secondary_color,
130
- styled_headers: styled_headers,
131
90
  theme: theme,
132
91
  theme_options: theme_options.to_query,
133
- tracking: tracking,
134
92
  website_iri: LinkedRails.iri.to_s,
135
93
  websocket_path: websocket_path
136
94
  }
@@ -138,7 +96,7 @@ module LinkedRails
138
96
 
139
97
  def web_manifest_sw_section
140
98
  {
141
- src: "#{scope.chomp('/')}/sw.js",
99
+ src: "#{scope}/sw.js?manifestLocation=#{Rack::Utils.escape("#{scope}/manifest.json")}",
142
100
  scope: scope
143
101
  }
144
102
  end
@@ -146,37 +104,5 @@ module LinkedRails
146
104
  def websocket_path
147
105
  Rails.application.config.try(:action_cable).try(:mount_path).try(:[], 1..-1)
148
106
  end
149
-
150
- def preconnect
151
- []
152
- end
153
-
154
- def styled_headers
155
- false
156
- end
157
-
158
- def tracking
159
- []
160
- end
161
-
162
- class << self
163
- def destroy(iri)
164
- Storage.hdel(:persistent, :manifest, URL.as_href(iri))
165
- end
166
-
167
- def move(from, to)
168
- Storage.hset(
169
- :persistent,
170
- :redirect_prefix,
171
- URL.as_href(from) => URL.as_href(to)
172
- )
173
-
174
- data = Storage.hget(:persistent, :manifest, URL.as_href(from))
175
-
176
- Storage.hset(:persistent, :manifest, URL.as_href(to), data) if data
177
-
178
- destroy(from)
179
- end
180
- end
181
107
  end
182
108
  end
@@ -26,7 +26,7 @@ module LinkedRails
26
26
  end
27
27
 
28
28
  def menus
29
- @menus ||= available_menus.map(&method(:memoized_menu_item))
29
+ @menus ||= available_menus.map(&method(:memoised_menu_item))
30
30
  end
31
31
 
32
32
  def menu(tag)
@@ -4,7 +4,6 @@ module LinkedRails
4
4
  class Ontology
5
5
  include ActiveModel::Model
6
6
  include LinkedRails::Model
7
- include LinkedRails::Model::Cacheable
8
7
 
9
8
  def classes
10
9
  @classes ||= LinkedRails.linked_models.map do |klass|
@@ -11,8 +11,6 @@ en:
11
11
  update:
12
12
  label: "Edit"
13
13
  success: 'Updated successfully'
14
- errors:
15
- access_denied: "You're not authorized for this action. (%{action})"
16
14
  linked_rails:
17
15
  status:
18
16
  400: "Error in request"
@@ -6,10 +6,6 @@ module LinkedRails
6
6
  extend ActiveSupport::Concern
7
7
  include ActiveSupport::Rescuable
8
8
 
9
- included do
10
- rescue_from LinkedRails::Errors::Forbidden, with: :handle_error
11
- end
12
-
13
9
  private
14
10
 
15
11
  def add_error_snackbar(error)
@@ -73,7 +69,6 @@ module LinkedRails
73
69
  'Doorkeeper::Errors::InvalidGrantReuse' => 422,
74
70
  'LinkedRails::Auth::Errors::Expired' => 410,
75
71
  'LinkedRails::Auth::Errors::Unauthorized' => 401,
76
- 'LinkedRails::Errors::Forbidden' => 403,
77
72
  'Pundit::NotAuthorizedError' => 403
78
73
  }
79
74
  end
@@ -46,13 +46,6 @@ module LinkedRails
46
46
 
47
47
  private
48
48
 
49
- def request_path_to_url(path)
50
- return path unless path.present? && URI(path).relative?
51
-
52
- port = [80, 443].include?(request.port) ? nil : request.port
53
- URI::Generic.new(request.scheme, nil, request.host, port, nil, path, nil, nil, nil).to_s
54
- end
55
-
56
49
  def build_new_resource
57
50
  controller_class.build_new(user_context: user_context)
58
51
  end
@@ -62,7 +62,6 @@ module LinkedRails
62
62
  iri = root_relative_iri.dup
63
63
  iri.scheme = LinkedRails.scheme
64
64
  iri.host = LinkedRails.host
65
- iri.path = iri.path.presence || '/'
66
65
  iri
67
66
  end
68
67
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'model/actionable'
4
- require_relative 'model/cacheable'
5
4
  require_relative 'model/collections'
6
5
  require_relative 'model/dirty'
7
6
  require_relative 'model/enhancements'
@@ -46,10 +46,6 @@ module LinkedRails
46
46
  self.class.policy_class
47
47
  end
48
48
 
49
- def public_resource?
50
- false
51
- end
52
-
53
49
  def show?
54
50
  false
55
51
  end
data/lib/linked_rails.rb CHANGED
@@ -22,10 +22,6 @@ module LinkedRails
22
22
 
23
23
  mattr_accessor :whitelisted_spi_ips
24
24
  mattr_writer :host, :scheme
25
- mattr_accessor :persistent_redis_database, default: ENV['PERSISTENT_REDIS_DATABASE'].presence || 6
26
- mattr_accessor :stream_redis_database, default: ENV['STREAM_REDIS_DATABASE'].presence || 7
27
- mattr_accessor :cache_redis_database, default: ENV['CACHE_REDIS_DATABASE'].presence || 8
28
- mattr_accessor :cache_stream, default: ENV['CACHE_STREAM'].presence || 'transactions'
29
25
 
30
26
  def self.configurable_class(parent, klass, default: nil, reader: nil) # rubocop:disable Metrics/AbcSize
31
27
  method = :"#{[parent, klass.to_s.downcase].compact.join('_')}_class"
@@ -54,10 +50,8 @@ module LinkedRails
54
50
  @@scheme ||= Rails.application.routes.default_url_options[:protocol] || :http # rubocop:disable Style/ClassVars
55
51
  end
56
52
 
57
- def iri(**args)
58
- opts = {scheme: LinkedRails.scheme, host: LinkedRails.host}.merge(args)
59
- opts[:path] = opts[:path].presence || '/'
60
- RDF::URI.new(**opts)
53
+ def iri(**opts)
54
+ RDF::URI.new(**{scheme: LinkedRails.scheme, host: LinkedRails.host}.merge(opts))
61
55
  end
62
56
  end
63
57
 
@@ -90,7 +84,6 @@ ActiveSupport::Inflector.inflections do |inflect|
90
84
  inflect.acronym 'SHACL'
91
85
  end
92
86
 
93
- require 'linked_rails/errors'
94
87
  require 'linked_rails/uri_template'
95
88
  require 'linked_rails/vocab'
96
89
  require 'linked_rails/cache'
@@ -108,5 +101,3 @@ require 'linked_rails/routes'
108
101
  require 'linked_rails/serializer'
109
102
  require 'linked_rails/translate'
110
103
  require 'linked_rails/railtie'
111
- require 'linked_rails/url'
112
- require 'linked_rails/storage'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linked_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4.pre.g76dedd8ba
4
+ version: 0.0.4.pre.g83aa52ab3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arthur Dingemans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-15 00:00:00.000000000 Z
11
+ date: 2022-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_response
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: redis
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: rdf
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -299,10 +285,8 @@ files:
299
285
  - app/policies/linked_rails/collection/view_policy.rb
300
286
  - app/policies/linked_rails/collection_policy.rb
301
287
  - app/policies/linked_rails/enum_value_policy.rb
302
- - app/policies/linked_rails/form_policy.rb
303
288
  - app/policies/linked_rails/menus/item_policy.rb
304
289
  - app/policies/linked_rails/menus/list_policy.rb
305
- - app/policies/linked_rails/ontology_policy.rb
306
290
  - app/policies/linked_rails/sequence_policy.rb
307
291
  - app/serializers/linked_rails/actions/item_serializer.rb
308
292
  - app/serializers/linked_rails/actions/object_serializer.rb
@@ -340,7 +324,6 @@ files:
340
324
  - app/serializers/linked_rails/web_page_serializer.rb
341
325
  - app/serializers/linked_rails/web_site_serializer.rb
342
326
  - app/serializers/linked_rails/widget_serializer.rb
343
- - app/workers/linked_rails/invalidation_stream_worker.rb
344
327
  - config/initializers/inflections.rb
345
328
  - lib/generators/linked_rails/install/install_generator.rb
346
329
  - lib/generators/linked_rails/install/templates/README
@@ -390,8 +373,6 @@ files:
390
373
  - lib/linked_rails/enhancements/destroyable/controller.rb
391
374
  - lib/linked_rails/enhancements/updatable/controller.rb
392
375
  - lib/linked_rails/enhancements/updatable/serializer.rb
393
- - lib/linked_rails/errors.rb
394
- - lib/linked_rails/errors/forbidden.rb
395
376
  - lib/linked_rails/helpers/delta_helper.rb
396
377
  - lib/linked_rails/helpers/ontola_actions_helper.rb
397
378
  - lib/linked_rails/helpers/resource_helper.rb
@@ -400,7 +381,6 @@ files:
400
381
  - lib/linked_rails/middleware/linked_data_params.rb
401
382
  - lib/linked_rails/model.rb
402
383
  - lib/linked_rails/model/actionable.rb
403
- - lib/linked_rails/model/cacheable.rb
404
384
  - lib/linked_rails/model/collections.rb
405
385
  - lib/linked_rails/model/dirty.rb
406
386
  - lib/linked_rails/model/enhancements.rb
@@ -424,12 +404,10 @@ files:
424
404
  - lib/linked_rails/serializer/actionable.rb
425
405
  - lib/linked_rails/serializer/menuable.rb
426
406
  - lib/linked_rails/serializer/singularable.rb
427
- - lib/linked_rails/storage.rb
428
407
  - lib/linked_rails/test_methods.rb
429
408
  - lib/linked_rails/translate.rb
430
409
  - lib/linked_rails/types/iri_type.rb
431
410
  - lib/linked_rails/uri_template.rb
432
- - lib/linked_rails/url.rb
433
411
  - lib/linked_rails/version.rb
434
412
  - lib/linked_rails/vocab.rb
435
413
  - lib/nill_class_renderer.rb
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LinkedRails
4
- class FormPolicy < LinkedRails.policy_parent_class
5
- def show?
6
- true
7
- end
8
-
9
- def public_resource?
10
- true
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LinkedRails
4
- class OntologyPolicy < LinkedRails.policy_parent_class
5
- def show?
6
- true
7
- end
8
-
9
- def public_resource?
10
- true
11
- end
12
- end
13
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LinkedRails
4
- class InvalidationStreamWorker < ActiveJob::Base
5
- def perform(type, iri, resource_type)
6
- entry = {
7
- type: type,
8
- resource: iri,
9
- resourceType: resource_type
10
- }
11
- id = Storage.xadd(:stream, LinkedRails.cache_stream, entry)
12
-
13
- raise('No message id returned, implies failure') if id.blank?
14
- end
15
- end
16
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LinkedRails
4
- module Errors
5
- class Forbidden < StandardError
6
- attr_reader :query, :record, :policy, :action
7
-
8
- # @param [Hash] options
9
- # @option options [String] query The action of the request
10
- # @option options [ActiveRecord::Base] record The record that was requested
11
- # @option options [Policy] policy The policy that raised the exception
12
- # @option options [String] message Override the default error message
13
- # @return [String] the message
14
- def initialize(**options)
15
- @query = options.fetch(:query).to_s
16
- @record = options[:record]
17
- @policy = options[:policy]
18
- @action = @query[-1] == '?' ? @query[0..-2] : @query
19
- @message = options[:message]
20
-
21
- raise StandardError if @query.blank? && @message.blank?
22
-
23
- super(@message || default_message)
24
- end
25
-
26
- private
27
-
28
- def default_message
29
- I18n.t(
30
- "pundit.#{@policy.class.to_s.underscore}.#{@query}",
31
- action: @action,
32
- default: I18n.t('errors.access_denied')
33
- )
34
- end
35
- end
36
- end
37
- end
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'errors/forbidden'
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LinkedRails
4
- module Model
5
- module Cacheable
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- if respond_to?(:after_commit)
10
- after_commit :publish_create, on: :create, if: :should_publish_changes
11
- after_commit :publish_update, on: :update, if: :should_publish_changes
12
- after_commit :publish_delete, on: :destroy, if: :should_publish_changes
13
- end
14
- end
15
-
16
- def cacheable?
17
- true
18
- end
19
-
20
- def publish_create
21
- publish_message('io.ontola.transactions.Created')
22
- end
23
-
24
- def publish_update
25
- publish_message('io.ontola.transactions.Updated')
26
- end
27
-
28
- def publish_delete
29
- publish_message('io.ontola.transactions.Deleted')
30
- end
31
-
32
- private
33
-
34
- def publish_message(type)
35
- LinkedRails::InvalidationStreamWorker.perform_now(type, iri.to_s, self.class.iri.to_s)
36
- rescue StandardError
37
- LinkedRails::InvalidationStreamWorker.perform_later(type, iri.to_s, self.class.iri.to_s)
38
- end
39
-
40
- def should_publish_changes
41
- cacheable? && !Rails.env.test?
42
- end
43
- end
44
- end
45
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'redis'
4
-
5
- module LinkedRails
6
- class Storage
7
- REDIS_DB = {
8
- cache: LinkedRails.cache_redis_database,
9
- persistent: LinkedRails.persistent_redis_database,
10
- stream: LinkedRails.stream_redis_database
11
- }.freeze
12
- KEYS = {
13
- manifest: 'cache:Manifest',
14
- redirect_exact: 'cache:Redirect:Exact',
15
- redirect_prefix: 'cache:Redirect:Prefix'
16
- }.freeze
17
-
18
- class << self
19
- %i[xadd].each do |method|
20
- define_method(method) do |db, *args|
21
- Redis.new(db: REDIS_DB.fetch(db)).send(method, *args)
22
- end
23
- end
24
-
25
- %i[hset hdel hget].each do |method|
26
- define_method(method) do |db, key, *args|
27
- Redis.new(db: REDIS_DB.fetch(db)).send(method, KEYS.fetch(key), *args)
28
- end
29
- end
30
- end
31
- end
32
- end
@@ -1,11 +0,0 @@
1
- module LinkedRails
2
- class URL
3
- class << self
4
- def as_href(url)
5
- uri = URI(url)
6
- uri.path = uri.path.presence || '/'
7
- uri.to_s
8
- end
9
- end
10
- end
11
- end