lucid_intercom 0.6.1 → 0.7.0

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: ae5331c5e43c8500eba29e4aa59eb888b5cf36eb688e4261bb36a03e69c73668
4
- data.tar.gz: 512c22f9afc0ca22de424e8e7cb05620c962c97902c03f0f5ca700176be7f386
3
+ metadata.gz: 40151e3c0b77b0c04c814fdfa8a03a5c742e41d59f91decbad56707340ca2982
4
+ data.tar.gz: ead12913bf87b9b27fcdc77740c82bcbc1172f8fce9db7ef9e814983c5f63137
5
5
  SHA512:
6
- metadata.gz: 275bf250cc1623219ccc046a0209f7b3dc3424eba9b0ea7facdb293115b52c1048f7b974c01058e0c3110eee5cc0712542e116db445cc41ecff6aa4471b90552
7
- data.tar.gz: 5b933a4d0827a816cceec0ebcee906e2d5fffafb6d2b3472f4c64da792433e64a6bf05aec32ab46fb3dd8433e2720677b65cbd2d9d0daab49bcc0631a9c9c0c2
6
+ metadata.gz: edf6696d6613c69a1dead35474beddf87e21650d47a595356d081c70b81e8503117e8704281c5a226d8ce18e1628b26c29f56dd8b90404dd69b4331a069eba89
7
+ data.tar.gz: 4d5a29e39c4888affa6b7cc8d49881af4463732ad2735315d3344ce6882786fbe30da517d9295ab486e82e87e60f5deaa9e80dcdf96a4b41926f54e6ea7d1aff
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-initializer'
4
-
5
- require 'lucid_intercom/convert'
3
+ require 'lucid_intercom/container'
6
4
 
7
5
  module LucidIntercom
8
6
  class Attributes
@@ -10,6 +8,8 @@ module LucidIntercom
10
8
 
11
9
  # @return [Hash] shop attributes as returned by the Shopify API
12
10
  param :shopify_data, reader: :private
11
+ # @return [Hash] app attributes (unprefixed)
12
+ param :app_data, reader: :private, default: -> { {} }
13
13
 
14
14
  #
15
15
  # @abstract
@@ -18,7 +18,7 @@ module LucidIntercom
18
18
  #
19
19
  # @return [Hash]
20
20
  #
21
- def to_h(convert: Convert.new)
21
+ def to_h(convert: Container[:convert])
22
22
  convert.({})
23
23
  end
24
24
  end
@@ -1,16 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lucid_intercom/attributes'
3
+ require 'lucid_intercom/container'
4
4
 
5
5
  module LucidIntercom
6
6
  class CompanyAttributes < Attributes
7
+ # @return [CompanyCustomAttributes]
8
+ param :custom, default: -> { CompanyCustomAttributes.new(shopify_data, app_data) }
9
+
7
10
  #
8
11
  # @param browser [Boolean] format for browser snippet
9
12
  # @param convert [#call]
10
13
  #
11
14
  # @return [Hash]
12
15
  #
13
- def to_h(browser: false, convert: Convert.new)
16
+ def to_h(browser: false, convert: Container[:convert])
14
17
  convert.({}.tap do |h|
15
18
  h[browser ? :id : :company_id] = shopify_data['myshopify_domain']
16
19
  h[:name] = shopify_data['name']
@@ -1,19 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lucid_intercom/attributes'
4
- require 'lucid_intercom/config'
3
+ require 'lucid_intercom/container'
5
4
 
6
5
  module LucidIntercom
7
6
  class CompanyCustomAttributes < Attributes
8
- # @return [Hash] app attributes (unprefixed)
9
- param :app_data, reader: :private
10
-
11
7
  #
12
8
  # @param convert [#call]
13
9
  #
14
10
  # @return [Hash]
15
11
  #
16
- def to_h(convert: Convert.new)
12
+ def to_h(convert: Container[:convert])
17
13
  convert.(shopify.merge(app))
18
14
  end
19
15
 
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-initializer'
4
3
  require 'forwardable'
5
4
 
6
- require 'lucid_intercom/error'
5
+ require 'lucid_intercom'
7
6
 
8
7
  module LucidIntercom
9
8
  NotConfiguredError = Class.new(Error)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/container'
4
+
5
+ require 'lucid_intercom'
6
+
7
+ module LucidIntercom
8
+ Container = Dry::Container.new
9
+
10
+ # Services only (dependencies); no value objects, entities.
11
+ Container.register(:convert) { Convert.new }
12
+ Container.register(:notify_changed_plan) { NotifyChangedPlan.new }
13
+ Container.register(:notify_installed) { NotifyInstalled.new }
14
+ Container.register(:notify_uninstalled) { NotifyUninstalled.new }
15
+ Container.register(:post_request) { PostRequest.new }
16
+ Container.register(:render_snippet) { RenderSnippet.new }
17
+ Container.register(:update_user) { UpdateUser.new }
18
+ end
@@ -1,35 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lucid_intercom/company_attributes'
4
- require 'lucid_intercom/company_custom_attributes'
5
- require 'lucid_intercom/config'
6
- require 'lucid_intercom/user_attributes'
3
+ require 'lucid_intercom/container'
7
4
 
8
5
  module LucidIntercom
9
6
  class Event
10
- extend Dry::Initializer
7
+ #
8
+ # @param post_request [#call]
9
+ # @param update_user [#call]
10
+ #
11
+ def initialize(post_request: Container[:post_request],
12
+ update_user: Container[:update_user])
13
+ @post_request = post_request
14
+ @update_user = update_user
15
+ end
16
+
17
+ #
18
+ # @param shopify_data_or_user [Hash, UserAttributes] shop attributes as returned by the Shopify API
19
+ # @param *args [Array<Object>]
20
+ #
21
+ def notify(shopify_data_or_user, *args)
22
+ user = shopify_data_or_user
23
+ user = UserAttributes.new(user, app_data(*args)) if user.is_a?(Hash)
24
+
25
+ @post_request.('events', data(user, *args)).assert!
26
+
27
+ @update_user.(user)
28
+ end
29
+
30
+ alias_method :call, :notify
31
+
32
+ #
33
+ # @param user [UserAttributes]
34
+ # @param *args [Array<Object>]
35
+ #
36
+ # @return [Hash]
37
+ #
38
+ private def data(user, *args)
39
+ {
40
+ **data_user_id(user),
41
+ event_name: name,
42
+ created_at: Time.now.utc.to_i,
43
+ metadata: metadata(user, *args),
44
+ }
45
+ end
11
46
 
12
- # @return [Hash] shop attributes as returned by the Shopify API
13
- param :shopify_data
14
- # @return [CompanyAttributes]
15
- option :company, default: proc { CompanyAttributes.new(shopify_data) }
16
- # @return [CompanyCustomAttributes]
17
- option :company_custom, default: proc { CompanyCustomAttributes.new(shopify_data, app_data) }
18
- # @return [UserAttributes]
19
- option :user, default: proc { UserAttributes.new(shopify_data) }
47
+ #
48
+ # @param user [UserAttributes]
49
+ #
50
+ # @return [Hash]
51
+ #
52
+ private def data_user_id(user)
53
+ {
54
+ user.id_key => user.id,
55
+ }
56
+ end
20
57
 
21
58
  #
22
59
  # Set the event name for the subclass.
23
60
  #
24
- # @param event_name [String, #to_s]
61
+ # @param name [String, #to_s]
25
62
  #
26
63
  # @example
27
64
  # event :changed_plan
28
65
  #
29
- def self.event(event_name)
30
- define_method(:event_name) do
31
- "#{LucidIntercom.app_prefix}_#{event_name}"
32
- end
66
+ def self.event(name)
67
+ define_method(:name) { "#{LucidIntercom.app_prefix}_#{name}" }
68
+
69
+ private :name
33
70
  end
34
71
 
35
72
  #
@@ -37,16 +74,19 @@ module LucidIntercom
37
74
  #
38
75
  # @return [String]
39
76
  #
40
- def event_name
77
+ private def name
41
78
  raise NotImplementedError
42
79
  end
43
80
 
44
81
  #
45
82
  # @abstract
46
83
  #
84
+ # @param user [UserAttributes]
85
+ # @param *args [Array<Object>]
86
+ #
47
87
  # @return [Hash]
48
88
  #
49
- def event_metadata
89
+ private def metadata(user, *args)
50
90
  raise NotImplementedError
51
91
  end
52
92
 
@@ -61,17 +101,8 @@ module LucidIntercom
61
101
  #
62
102
  # @return [Hash]
63
103
  #
64
- def app_data
104
+ private def app_data(*)
65
105
  {}
66
106
  end
67
-
68
- #
69
- # @return [Hash]
70
- #
71
- def user_id
72
- {
73
- user.id_key => user.id,
74
- }
75
- end
76
107
  end
77
108
  end
@@ -3,26 +3,25 @@
3
3
  require 'lucid_intercom/event'
4
4
 
5
5
  module LucidIntercom
6
- class ChangedPlanEvent < Event
7
- # @return [String, nil] e.g. 'free', or nil to unset
8
- param :new_plan
9
-
6
+ class NotifyChangedPlan < Event
10
7
  event :changed_plan
11
8
 
12
9
  #
13
- # @return [Hash]
10
+ # @see Event#metadata
14
11
  #
15
- def event_metadata
12
+ private def metadata(user, new_plan)
16
13
  {
17
- company_id: company.to_h[:company_id],
14
+ company_id: user.company.to_h[:company_id],
18
15
  new_plan: new_plan,
19
16
  }
20
17
  end
21
18
 
19
+ #
20
+ # @param new_plan [String, nil] e.g. 'free', or nil to unset
22
21
  #
23
22
  # @return [Hash]
24
23
  #
25
- def app_data
24
+ private def app_data(new_plan)
26
25
  {
27
26
  plan: new_plan,
28
27
  }
@@ -3,26 +3,25 @@
3
3
  require 'lucid_intercom/event'
4
4
 
5
5
  module LucidIntercom
6
- class InstalledEvent < Event
7
- # @return [String] e.g. 'free'
8
- param :new_plan
9
-
6
+ class NotifyInstalled < Event
10
7
  event :installed
11
8
 
12
9
  #
13
- # @return [Hash]
10
+ # @see Event#metadata
14
11
  #
15
- def event_metadata
12
+ private def metadata(user, new_plan)
16
13
  {
17
- company_id: company.to_h[:company_id],
14
+ company_id: user.company.to_h[:company_id],
18
15
  new_plan: new_plan,
19
16
  }
20
17
  end
21
18
 
19
+ #
20
+ # @param new_plan [String] e.g. 'free'
22
21
  #
23
22
  # @return [Hash]
24
23
  #
25
- def app_data
24
+ private def app_data(new_plan)
26
25
  {
27
26
  plan: new_plan,
28
27
  }
@@ -3,22 +3,22 @@
3
3
  require 'lucid_intercom/event'
4
4
 
5
5
  module LucidIntercom
6
- class UninstalledEvent < Event
6
+ class NotifyUninstalled < Event
7
7
  event :uninstalled
8
8
 
9
9
  #
10
- # @return [Hash]
10
+ # @see Event#metadata
11
11
  #
12
- def event_metadata
12
+ private def metadata(user, *args)
13
13
  {
14
- company_id: company.to_h[:company_id],
14
+ company_id: user.company.to_h[:company_id],
15
15
  }
16
16
  end
17
17
 
18
18
  #
19
19
  # @return [Hash]
20
20
  #
21
- def app_data
21
+ private def app_data(*)
22
22
  {
23
23
  plan: nil,
24
24
  }
@@ -2,8 +2,7 @@
2
2
 
3
3
  require 'http'
4
4
 
5
- require 'lucid_intercom/config'
6
- require 'lucid_intercom/response'
5
+ require 'lucid_intercom'
7
6
 
8
7
  module LucidIntercom
9
8
  class PostRequest
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lucid_intercom/config'
3
+ require 'lucid_intercom'
4
4
 
5
5
  module LucidIntercom
6
6
  class RenderSnippet
7
7
  TEMPLATE = File.read("#{__dir__}/snippet.html").freeze
8
8
 
9
9
  #
10
- # @param shopify_data [Hash] shop attributes as returned by the Shopify API
10
+ # @param shopify_data_or_user [Hash, UserAttributes] shop attributes as returned by the Shopify API
11
11
  # @param app_data [Hash] app attributes (unprefixed)
12
12
  #
13
13
  # @example Unauthenticated visitor
@@ -18,17 +18,13 @@ module LucidIntercom
18
18
  #
19
19
  # @return [String]
20
20
  #
21
- def call(shopify_data = {}, app_data = {})
22
- settings = shopify_data.empty? ? unauthenticated_settings : {
23
- **unauthenticated_settings,
24
- **UserAttributes.new(shopify_data).to_h(browser: true),
25
- company: CompanyAttributes.new(shopify_data).to_h(browser: true).merge(CompanyCustomAttributes.new(shopify_data, app_data).to_h)
26
- }
21
+ def call(shopify_data_or_user = {}, app_data = {})
22
+ user = shopify_data_or_user
23
+ user = UserAttributes.new(user, app_data) if user.is_a?(Hash)
27
24
 
28
- TEMPLATE % {
29
- settings: settings.to_json,
30
- app_id: settings[:app_id],
31
- }
25
+ settings = shopify_data_or_user.is_a?(Hash) && shopify_data_or_user.empty? ? unauthenticated_settings : authenticated_settings(user)
26
+
27
+ TEMPLATE % {settings: settings.to_json, app_id: settings[:app_id]}
32
28
  end
33
29
 
34
30
  #
@@ -39,5 +35,18 @@ module LucidIntercom
39
35
  app_id: LucidIntercom.app_id,
40
36
  }
41
37
  end
38
+
39
+ #
40
+ # @param user [UserAttributes]
41
+ #
42
+ # @return [Hash]
43
+ #
44
+ private def authenticated_settings(user)
45
+ {
46
+ **unauthenticated_settings,
47
+ **user.to_h(browser: true),
48
+ company: user.company.to_h(browser: true).merge(user.company.custom.to_h),
49
+ }
50
+ end
42
51
  end
43
52
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-initializer'
4
-
5
- require 'lucid_intercom/error'
3
+ require 'lucid_intercom'
6
4
 
7
5
  module LucidIntercom
8
6
  class Response
@@ -1,41 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-initializer'
4
-
5
- require 'lucid_intercom/post_request'
3
+ require 'lucid_intercom/container'
6
4
 
7
5
  module LucidIntercom
8
6
  class UpdateUser
9
- extend Dry::Initializer
10
-
11
- # @return [PostRequest]
12
- option :post_request, default: proc { PostRequest.new }
7
+ #
8
+ # @param post_request [#call]
9
+ #
10
+ def initialize(post_request: Container[:post_request])
11
+ @post_request = post_request
12
+ end
13
13
 
14
14
  #
15
- # Create or update user identified by event attributes. This is only used in
16
- # the context of events.
15
+ # Create or update user.
17
16
  #
18
- # @param event [Events::Event]
17
+ # @param user [UserAttributes]
19
18
  #
20
19
  # @raise [Response::ClientError] for status 4xx
21
20
  # @raise [Response::ServerError] for status 5xx
22
21
  #
23
- def call(event)
24
- data = data(event)
25
-
26
- post_request.('users', data).assert!
22
+ def call(user)
23
+ @post_request.('users', data(user)).assert!
27
24
  end
28
25
 
29
26
  #
30
- # @param event [Events::Event]
27
+ # @param user [UserAttributes]
31
28
  #
32
29
  # @return [Hash]
33
30
  #
34
- private def data(event)
35
- event.user.to_h.merge(
31
+ private def data(user)
32
+ user.to_h.merge(
36
33
  companies: [
37
- event.company.to_h.merge(
38
- custom_attributes: event.company_custom.to_h
34
+ user.company.to_h.merge(
35
+ custom_attributes: user.company.custom.to_h
39
36
  ),
40
37
  ]
41
38
  )
@@ -1,17 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lucid_intercom/attributes'
4
- require 'lucid_intercom/config'
3
+ require 'lucid_intercom/container'
5
4
 
6
5
  module LucidIntercom
7
6
  class UserAttributes < Attributes
7
+ # @return [CompanyAttributes]
8
+ param :company, default: -> { CompanyAttributes.new(shopify_data, app_data) }
9
+
8
10
  #
9
11
  # @param browser [Boolean] format for browser snippet
10
12
  # @param convert [#call]
11
13
  #
12
14
  # @return [Hash]
13
15
  #
14
- def to_h(browser: false, convert: Convert.new)
16
+ def to_h(browser: false, convert: Container[:convert])
15
17
  convert.({}.tap do |h|
16
18
  h[:user_hash] = user_hash(id) if browser # or myshopify_domain
17
19
  h[:email] = shopify_data['email']
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LucidIntercom
4
- VERSION = '0.6.1'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -1,21 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Primarily for Bundler.
3
+ require 'dry/initializer'
4
4
 
5
- require 'lucid_intercom/attributes.rb'
6
- require 'lucid_intercom/changed_plan_event.rb'
7
- require 'lucid_intercom/company_attributes.rb'
8
- require 'lucid_intercom/company_custom_attributes.rb'
9
- require 'lucid_intercom/config.rb'
10
- require 'lucid_intercom/convert.rb'
11
- require 'lucid_intercom/error.rb'
12
- require 'lucid_intercom/event.rb'
13
- require 'lucid_intercom/installed_event.rb'
14
- require 'lucid_intercom/post_request.rb'
15
- require 'lucid_intercom/render_snippet.rb'
16
- require 'lucid_intercom/response.rb'
17
- require 'lucid_intercom/send_event.rb'
18
- require 'lucid_intercom/uninstalled_event.rb'
19
- require 'lucid_intercom/update_user.rb'
20
- require 'lucid_intercom/user_attributes.rb'
21
- require 'lucid_intercom/version.rb'
5
+ module LucidIntercom
6
+ autoload :Attributes, 'lucid_intercom/attributes.rb'
7
+ autoload :CompanyAttributes, 'lucid_intercom/company_attributes.rb'
8
+ autoload :CompanyCustomAttributes, 'lucid_intercom/company_custom_attributes.rb'
9
+ autoload :Config, 'lucid_intercom/config.rb'
10
+ autoload :Container, 'lucid_intercom/container.rb'
11
+ autoload :Convert, 'lucid_intercom/convert.rb'
12
+ autoload :Error, 'lucid_intercom/error.rb'
13
+ autoload :Event, 'lucid_intercom/event.rb'
14
+ autoload :NotifyChangedPlan, 'lucid_intercom/notify_changed_plan.rb'
15
+ autoload :NotifyInstalled, 'lucid_intercom/notify_installed.rb'
16
+ autoload :NotifyUninstalled, 'lucid_intercom/notify_uninstalled.rb'
17
+ autoload :PostRequest, 'lucid_intercom/post_request.rb'
18
+ autoload :RenderSnippet, 'lucid_intercom/render_snippet.rb'
19
+ autoload :Response, 'lucid_intercom/response.rb'
20
+ autoload :UpdateUser, 'lucid_intercom/update_user.rb'
21
+ autoload :UserAttributes, 'lucid_intercom/user_attributes.rb'
22
+ autoload :VERSION, 'lucid_intercom/version.rb'
23
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lucid_intercom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kelsey Judson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-11 00:00:00.000000000 Z
11
+ date: 2018-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,14 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 0.52.0
47
+ version: 0.58.2
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 0.52.0
54
+ version: 0.58.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-container
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.6'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: dry-initializer
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -89,20 +103,20 @@ files:
89
103
  - README.md
90
104
  - lib/lucid_intercom.rb
91
105
  - lib/lucid_intercom/attributes.rb
92
- - lib/lucid_intercom/changed_plan_event.rb
93
106
  - lib/lucid_intercom/company_attributes.rb
94
107
  - lib/lucid_intercom/company_custom_attributes.rb
95
108
  - lib/lucid_intercom/config.rb
109
+ - lib/lucid_intercom/container.rb
96
110
  - lib/lucid_intercom/convert.rb
97
111
  - lib/lucid_intercom/error.rb
98
112
  - lib/lucid_intercom/event.rb
99
- - lib/lucid_intercom/installed_event.rb
113
+ - lib/lucid_intercom/notify_changed_plan.rb
114
+ - lib/lucid_intercom/notify_installed.rb
115
+ - lib/lucid_intercom/notify_uninstalled.rb
100
116
  - lib/lucid_intercom/post_request.rb
101
117
  - lib/lucid_intercom/render_snippet.rb
102
118
  - lib/lucid_intercom/response.rb
103
- - lib/lucid_intercom/send_event.rb
104
119
  - lib/lucid_intercom/snippet.html
105
- - lib/lucid_intercom/uninstalled_event.rb
106
120
  - lib/lucid_intercom/update_user.rb
107
121
  - lib/lucid_intercom/user_attributes.rb
108
122
  - lib/lucid_intercom/version.rb
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'dry-initializer'
4
-
5
- require 'lucid_intercom/post_request'
6
-
7
- module LucidIntercom
8
- class SendEvent
9
- extend Dry::Initializer
10
-
11
- # @return [PostRequest]
12
- option :post_request, default: proc { PostRequest.new }
13
- # @return [UpdateUser]
14
- option :update_user, default: proc { UpdateUser.new }
15
-
16
- #
17
- # @param event [Events::Event]
18
- #
19
- # @raise [Response::ClientError] for status 4xx
20
- # @raise [Response::ServerError] for status 5xx
21
- #
22
- def call(event)
23
- post_request.('events', data(event)).assert!
24
-
25
- update_user.(event)
26
- end
27
-
28
- #
29
- # @param event [Events::Event]
30
- #
31
- # @return [Hash]
32
- #
33
- private def data(event)
34
- {
35
- **event.user_id,
36
- event_name: event.event_name,
37
- created_at: Time.now.utc.to_i,
38
- metadata: event.event_metadata,
39
- }
40
- end
41
- end
42
- end