trophy_api_client 1.5.0 → 1.7.0

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gemconfig.rb +1 -1
  3. data/lib/trophy_api_client/admin/attributes/client.rb +368 -0
  4. data/lib/trophy_api_client/admin/client.rb +21 -0
  5. data/lib/trophy_api_client/admin/leaderboards/client.rb +371 -0
  6. data/lib/trophy_api_client/admin/metrics/client.rb +366 -0
  7. data/lib/trophy_api_client/types/admin_attribute.rb +81 -0
  8. data/lib/trophy_api_client/types/admin_attribute_type.rb +9 -0
  9. data/lib/trophy_api_client/types/admin_leaderboard.rb +171 -0
  10. data/lib/trophy_api_client/types/admin_leaderboard_rank_by.rb +10 -0
  11. data/lib/trophy_api_client/types/admin_leaderboard_run_unit.rb +10 -0
  12. data/lib/trophy_api_client/types/admin_leaderboard_status.rb +11 -0
  13. data/lib/trophy_api_client/types/create_attribute_request_item.rb +76 -0
  14. data/lib/trophy_api_client/types/create_attribute_request_item_type.rb +9 -0
  15. data/lib/trophy_api_client/types/create_attributes_request.rb +7 -0
  16. data/lib/trophy_api_client/types/create_attributes_response.rb +74 -0
  17. data/lib/trophy_api_client/types/create_leaderboard_request_item.rb +171 -0
  18. data/lib/trophy_api_client/types/create_leaderboard_request_item_rank_by.rb +10 -0
  19. data/lib/trophy_api_client/types/create_leaderboard_request_item_run_unit.rb +11 -0
  20. data/lib/trophy_api_client/types/create_leaderboard_request_item_status.rb +13 -0
  21. data/lib/trophy_api_client/types/create_leaderboards_request.rb +7 -0
  22. data/lib/trophy_api_client/types/create_leaderboards_response.rb +74 -0
  23. data/lib/trophy_api_client/types/create_metric_request_item.rb +87 -0
  24. data/lib/trophy_api_client/types/create_metric_request_item_unit_type.rb +9 -0
  25. data/lib/trophy_api_client/types/create_metrics_request.rb +7 -0
  26. data/lib/trophy_api_client/types/create_metrics_response.rb +74 -0
  27. data/lib/trophy_api_client/types/created_metric.rb +88 -0
  28. data/lib/trophy_api_client/types/created_metric_unit_type.rb +9 -0
  29. data/lib/trophy_api_client/types/delete_attributes_response.rb +75 -0
  30. data/lib/trophy_api_client/types/delete_leaderboards_response.rb +75 -0
  31. data/lib/trophy_api_client/types/delete_metrics_response.rb +75 -0
  32. data/lib/trophy_api_client/types/delete_points_boosts_response.rb +2 -2
  33. data/lib/trophy_api_client/types/list_attributes_response.rb +7 -0
  34. data/lib/trophy_api_client/types/list_leaderboards_response.rb +7 -0
  35. data/lib/trophy_api_client/types/list_metrics_response.rb +7 -0
  36. data/lib/trophy_api_client/types/metric_response.rb +2 -17
  37. data/lib/trophy_api_client/types/update_attribute_request_item.rb +69 -0
  38. data/lib/trophy_api_client/types/update_attributes_request.rb +7 -0
  39. data/lib/trophy_api_client/types/update_attributes_response.rb +75 -0
  40. data/lib/trophy_api_client/types/update_leaderboard_request_item.rb +179 -0
  41. data/lib/trophy_api_client/types/update_leaderboard_request_item_rank_by.rb +11 -0
  42. data/lib/trophy_api_client/types/update_leaderboard_request_item_run_unit.rb +9 -0
  43. data/lib/trophy_api_client/types/update_leaderboard_request_item_status.rb +12 -0
  44. data/lib/trophy_api_client/types/update_leaderboards_request.rb +7 -0
  45. data/lib/trophy_api_client/types/update_leaderboards_response.rb +75 -0
  46. data/lib/trophy_api_client/types/update_metric_request_item.rb +86 -0
  47. data/lib/trophy_api_client/types/update_metric_request_item_unit_type.rb +9 -0
  48. data/lib/trophy_api_client/types/update_metrics_request.rb +7 -0
  49. data/lib/trophy_api_client/types/update_metrics_response.rb +75 -0
  50. data/lib/trophy_api_client/users/client.rb +2 -2
  51. data/lib/trophy_api_client/version.rb +1 -1
  52. data/lib/types_export.rb +51 -12
  53. metadata +45 -3
  54. data/lib/trophy_api_client/types/metric_status.rb +0 -9
  55. data/lib/trophy_api_client/types/notification_type.rb +0 -11
@@ -0,0 +1,371 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../requests"
4
+ require_relative "../../types/list_leaderboards_response"
5
+ require "json"
6
+ require_relative "../../types/create_leaderboards_request"
7
+ require_relative "../../types/create_leaderboards_response"
8
+ require_relative "../../types/delete_leaderboards_response"
9
+ require_relative "../../types/update_leaderboards_request"
10
+ require_relative "../../types/update_leaderboards_response"
11
+ require_relative "../../types/admin_leaderboard"
12
+ require "async"
13
+
14
+ module TrophyApiClient
15
+ module Admin
16
+ class LeaderboardsClient
17
+ # @return [TrophyApiClient::RequestClient]
18
+ attr_reader :request_client
19
+
20
+ # @param request_client [TrophyApiClient::RequestClient]
21
+ # @return [TrophyApiClient::Admin::LeaderboardsClient]
22
+ def initialize(request_client:)
23
+ @request_client = request_client
24
+ end
25
+
26
+ # List leaderboards.
27
+ #
28
+ # @param limit [Integer] Number of records to return.
29
+ # @param skip [Integer] Number of records to skip from the start of the list.
30
+ # @param request_options [TrophyApiClient::RequestOptions]
31
+ # @return [TrophyApiClient::LIST_LEADERBOARDS_RESPONSE]
32
+ # @example
33
+ # api = TrophyApiClient::Client.new(
34
+ # base_url: "https://api.example.com",
35
+ # environment: TrophyApiClient::Environment::PRODUCTION,
36
+ # api_key: "YOUR_API_KEY"
37
+ # )
38
+ # api.admin.leaderboards.list(limit: 1, skip: 1)
39
+ def list(limit: nil, skip: nil, request_options: nil)
40
+ response = @request_client.conn.get do |req|
41
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
42
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
43
+ req.headers = {
44
+ **(req.headers || {}),
45
+ **@request_client.get_headers,
46
+ **(request_options&.additional_headers || {})
47
+ }.compact
48
+ req.params = { **(request_options&.additional_query_parameters || {}), "limit": limit, "skip": skip }.compact
49
+ unless request_options.nil? || request_options&.additional_body_parameters.nil?
50
+ req.body = { **(request_options&.additional_body_parameters || {}) }.compact
51
+ end
52
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
53
+ end
54
+ parsed_json = JSON.parse(response.body)
55
+ parsed_json&.map do |item|
56
+ item = item.to_json
57
+ TrophyApiClient::AdminLeaderboard.from_json(json_object: item)
58
+ end
59
+ end
60
+
61
+ # Create leaderboards. Maximum 100 leaderboards per request.
62
+ #
63
+ # @param request [TrophyApiClient::CREATE_LEADERBOARDS_REQUEST]
64
+ # @param request_options [TrophyApiClient::RequestOptions]
65
+ # @return [TrophyApiClient::CreateLeaderboardsResponse]
66
+ # @example
67
+ # api = TrophyApiClient::Client.new(
68
+ # base_url: "https://api.example.com",
69
+ # environment: TrophyApiClient::Environment::PRODUCTION,
70
+ # api_key: "YOUR_API_KEY"
71
+ # )
72
+ # api.admin.leaderboards.create(request: [{ name: "Revenue Champions", key: "revenue-champions", status: INACTIVE, rank_by: METRIC, metric_id: "550e8400-e29b-41d4-a716-446655440000", max_participants: 100, start: "2026-04-20", breakdown_attributes: ["550e8400-e29b-41d4-a716-446655440010"], run_unit: MONTH, run_interval: 1 }, { name: "Streak Legends", key: "streak-legends", status: SCHEDULED, rank_by: STREAK, start: "2026-04-27" }])
73
+ def create(request:, request_options: nil)
74
+ response = @request_client.conn.post do |req|
75
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
76
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
77
+ req.headers = {
78
+ **(req.headers || {}),
79
+ **@request_client.get_headers,
80
+ **(request_options&.additional_headers || {})
81
+ }.compact
82
+ unless request_options.nil? || request_options&.additional_query_parameters.nil?
83
+ req.params = { **(request_options&.additional_query_parameters || {}) }.compact
84
+ end
85
+ req.body = { **(request || {}), **(request_options&.additional_body_parameters || {}) }.compact
86
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
87
+ end
88
+ TrophyApiClient::CreateLeaderboardsResponse.from_json(json_object: response.body)
89
+ end
90
+
91
+ # Delete leaderboards by ID.
92
+ #
93
+ # @param ids [String] Leaderboard IDs to delete. Repeat the query param or provide a comma-separated
94
+ # list.
95
+ # @param request_options [TrophyApiClient::RequestOptions]
96
+ # @return [TrophyApiClient::DeleteLeaderboardsResponse]
97
+ # @example
98
+ # api = TrophyApiClient::Client.new(
99
+ # base_url: "https://api.example.com",
100
+ # environment: TrophyApiClient::Environment::PRODUCTION,
101
+ # api_key: "YOUR_API_KEY"
102
+ # )
103
+ # api.admin.leaderboards.delete
104
+ def delete(ids: nil, request_options: nil)
105
+ response = @request_client.conn.delete do |req|
106
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
107
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
108
+ req.headers = {
109
+ **(req.headers || {}),
110
+ **@request_client.get_headers,
111
+ **(request_options&.additional_headers || {})
112
+ }.compact
113
+ req.params = { **(request_options&.additional_query_parameters || {}), "ids": ids }.compact
114
+ unless request_options.nil? || request_options&.additional_body_parameters.nil?
115
+ req.body = { **(request_options&.additional_body_parameters || {}) }.compact
116
+ end
117
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
118
+ end
119
+ TrophyApiClient::DeleteLeaderboardsResponse.from_json(json_object: response.body)
120
+ end
121
+
122
+ # Update leaderboards by ID. Updating `status` behaves the same as activating,
123
+ # scheduling, deactivating, or finishing a leaderboard in the dashboard.
124
+ #
125
+ # @param request [TrophyApiClient::UPDATE_LEADERBOARDS_REQUEST]
126
+ # @param request_options [TrophyApiClient::RequestOptions]
127
+ # @return [TrophyApiClient::UpdateLeaderboardsResponse]
128
+ # @example
129
+ # api = TrophyApiClient::Client.new(
130
+ # base_url: "https://api.example.com",
131
+ # environment: TrophyApiClient::Environment::PRODUCTION,
132
+ # api_key: "YOUR_API_KEY"
133
+ # )
134
+ # api.admin.leaderboards.update(request: [{ id: "550e8400-e29b-41d4-a716-446655440100", name: "Monthly Revenue Champions", description: "Ranked by monthly revenue", status: ACTIVE }, { id: "550e8400-e29b-41d4-a716-446655440101", status: FINISHED }])
135
+ def update(request:, request_options: nil)
136
+ response = @request_client.conn.patch do |req|
137
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
138
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
139
+ req.headers = {
140
+ **(req.headers || {}),
141
+ **@request_client.get_headers,
142
+ **(request_options&.additional_headers || {})
143
+ }.compact
144
+ unless request_options.nil? || request_options&.additional_query_parameters.nil?
145
+ req.params = { **(request_options&.additional_query_parameters || {}) }.compact
146
+ end
147
+ req.body = { **(request || {}), **(request_options&.additional_body_parameters || {}) }.compact
148
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
149
+ end
150
+ TrophyApiClient::UpdateLeaderboardsResponse.from_json(json_object: response.body)
151
+ end
152
+
153
+ # Get a leaderboard by ID.
154
+ #
155
+ # @param id [String] The UUID of the leaderboard to retrieve.
156
+ # @param request_options [TrophyApiClient::RequestOptions]
157
+ # @return [TrophyApiClient::AdminLeaderboard]
158
+ # @example
159
+ # api = TrophyApiClient::Client.new(
160
+ # base_url: "https://api.example.com",
161
+ # environment: TrophyApiClient::Environment::PRODUCTION,
162
+ # api_key: "YOUR_API_KEY"
163
+ # )
164
+ # api.admin.leaderboards.get(id: "550e8400-e29b-41d4-a716-446655440100")
165
+ def get(id:, request_options: nil)
166
+ response = @request_client.conn.get do |req|
167
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
168
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
169
+ req.headers = {
170
+ **(req.headers || {}),
171
+ **@request_client.get_headers,
172
+ **(request_options&.additional_headers || {})
173
+ }.compact
174
+ unless request_options.nil? || request_options&.additional_query_parameters.nil?
175
+ req.params = { **(request_options&.additional_query_parameters || {}) }.compact
176
+ end
177
+ unless request_options.nil? || request_options&.additional_body_parameters.nil?
178
+ req.body = { **(request_options&.additional_body_parameters || {}) }.compact
179
+ end
180
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards/#{id}"
181
+ end
182
+ TrophyApiClient::AdminLeaderboard.from_json(json_object: response.body)
183
+ end
184
+ end
185
+
186
+ class AsyncLeaderboardsClient
187
+ # @return [TrophyApiClient::AsyncRequestClient]
188
+ attr_reader :request_client
189
+
190
+ # @param request_client [TrophyApiClient::AsyncRequestClient]
191
+ # @return [TrophyApiClient::Admin::AsyncLeaderboardsClient]
192
+ def initialize(request_client:)
193
+ @request_client = request_client
194
+ end
195
+
196
+ # List leaderboards.
197
+ #
198
+ # @param limit [Integer] Number of records to return.
199
+ # @param skip [Integer] Number of records to skip from the start of the list.
200
+ # @param request_options [TrophyApiClient::RequestOptions]
201
+ # @return [TrophyApiClient::LIST_LEADERBOARDS_RESPONSE]
202
+ # @example
203
+ # api = TrophyApiClient::Client.new(
204
+ # base_url: "https://api.example.com",
205
+ # environment: TrophyApiClient::Environment::PRODUCTION,
206
+ # api_key: "YOUR_API_KEY"
207
+ # )
208
+ # api.admin.leaderboards.list(limit: 1, skip: 1)
209
+ def list(limit: nil, skip: nil, request_options: nil)
210
+ Async do
211
+ response = @request_client.conn.get do |req|
212
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
213
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
214
+ req.headers = {
215
+ **(req.headers || {}),
216
+ **@request_client.get_headers,
217
+ **(request_options&.additional_headers || {})
218
+ }.compact
219
+ req.params = {
220
+ **(request_options&.additional_query_parameters || {}),
221
+ "limit": limit,
222
+ "skip": skip
223
+ }.compact
224
+ unless request_options.nil? || request_options&.additional_body_parameters.nil?
225
+ req.body = { **(request_options&.additional_body_parameters || {}) }.compact
226
+ end
227
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
228
+ end
229
+ parsed_json = JSON.parse(response.body)
230
+ parsed_json&.map do |item|
231
+ item = item.to_json
232
+ TrophyApiClient::AdminLeaderboard.from_json(json_object: item)
233
+ end
234
+ end
235
+ end
236
+
237
+ # Create leaderboards. Maximum 100 leaderboards per request.
238
+ #
239
+ # @param request [TrophyApiClient::CREATE_LEADERBOARDS_REQUEST]
240
+ # @param request_options [TrophyApiClient::RequestOptions]
241
+ # @return [TrophyApiClient::CreateLeaderboardsResponse]
242
+ # @example
243
+ # api = TrophyApiClient::Client.new(
244
+ # base_url: "https://api.example.com",
245
+ # environment: TrophyApiClient::Environment::PRODUCTION,
246
+ # api_key: "YOUR_API_KEY"
247
+ # )
248
+ # api.admin.leaderboards.create(request: [{ name: "Revenue Champions", key: "revenue-champions", status: INACTIVE, rank_by: METRIC, metric_id: "550e8400-e29b-41d4-a716-446655440000", max_participants: 100, start: "2026-04-20", breakdown_attributes: ["550e8400-e29b-41d4-a716-446655440010"], run_unit: MONTH, run_interval: 1 }, { name: "Streak Legends", key: "streak-legends", status: SCHEDULED, rank_by: STREAK, start: "2026-04-27" }])
249
+ def create(request:, request_options: nil)
250
+ Async do
251
+ response = @request_client.conn.post do |req|
252
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
253
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
254
+ req.headers = {
255
+ **(req.headers || {}),
256
+ **@request_client.get_headers,
257
+ **(request_options&.additional_headers || {})
258
+ }.compact
259
+ unless request_options.nil? || request_options&.additional_query_parameters.nil?
260
+ req.params = { **(request_options&.additional_query_parameters || {}) }.compact
261
+ end
262
+ req.body = { **(request || {}), **(request_options&.additional_body_parameters || {}) }.compact
263
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
264
+ end
265
+ TrophyApiClient::CreateLeaderboardsResponse.from_json(json_object: response.body)
266
+ end
267
+ end
268
+
269
+ # Delete leaderboards by ID.
270
+ #
271
+ # @param ids [String] Leaderboard IDs to delete. Repeat the query param or provide a comma-separated
272
+ # list.
273
+ # @param request_options [TrophyApiClient::RequestOptions]
274
+ # @return [TrophyApiClient::DeleteLeaderboardsResponse]
275
+ # @example
276
+ # api = TrophyApiClient::Client.new(
277
+ # base_url: "https://api.example.com",
278
+ # environment: TrophyApiClient::Environment::PRODUCTION,
279
+ # api_key: "YOUR_API_KEY"
280
+ # )
281
+ # api.admin.leaderboards.delete
282
+ def delete(ids: nil, request_options: nil)
283
+ Async do
284
+ response = @request_client.conn.delete do |req|
285
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
286
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
287
+ req.headers = {
288
+ **(req.headers || {}),
289
+ **@request_client.get_headers,
290
+ **(request_options&.additional_headers || {})
291
+ }.compact
292
+ req.params = { **(request_options&.additional_query_parameters || {}), "ids": ids }.compact
293
+ unless request_options.nil? || request_options&.additional_body_parameters.nil?
294
+ req.body = { **(request_options&.additional_body_parameters || {}) }.compact
295
+ end
296
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
297
+ end
298
+ TrophyApiClient::DeleteLeaderboardsResponse.from_json(json_object: response.body)
299
+ end
300
+ end
301
+
302
+ # Update leaderboards by ID. Updating `status` behaves the same as activating,
303
+ # scheduling, deactivating, or finishing a leaderboard in the dashboard.
304
+ #
305
+ # @param request [TrophyApiClient::UPDATE_LEADERBOARDS_REQUEST]
306
+ # @param request_options [TrophyApiClient::RequestOptions]
307
+ # @return [TrophyApiClient::UpdateLeaderboardsResponse]
308
+ # @example
309
+ # api = TrophyApiClient::Client.new(
310
+ # base_url: "https://api.example.com",
311
+ # environment: TrophyApiClient::Environment::PRODUCTION,
312
+ # api_key: "YOUR_API_KEY"
313
+ # )
314
+ # api.admin.leaderboards.update(request: [{ id: "550e8400-e29b-41d4-a716-446655440100", name: "Monthly Revenue Champions", description: "Ranked by monthly revenue", status: ACTIVE }, { id: "550e8400-e29b-41d4-a716-446655440101", status: FINISHED }])
315
+ def update(request:, request_options: nil)
316
+ Async do
317
+ response = @request_client.conn.patch do |req|
318
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
319
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
320
+ req.headers = {
321
+ **(req.headers || {}),
322
+ **@request_client.get_headers,
323
+ **(request_options&.additional_headers || {})
324
+ }.compact
325
+ unless request_options.nil? || request_options&.additional_query_parameters.nil?
326
+ req.params = { **(request_options&.additional_query_parameters || {}) }.compact
327
+ end
328
+ req.body = { **(request || {}), **(request_options&.additional_body_parameters || {}) }.compact
329
+ req.url "#{@request_client.get_url(environment: admin, request_options: request_options)}/leaderboards"
330
+ end
331
+ TrophyApiClient::UpdateLeaderboardsResponse.from_json(json_object: response.body)
332
+ end
333
+ end
334
+
335
+ # Get a leaderboard by ID.
336
+ #
337
+ # @param id [String] The UUID of the leaderboard to retrieve.
338
+ # @param request_options [TrophyApiClient::RequestOptions]
339
+ # @return [TrophyApiClient::AdminLeaderboard]
340
+ # @example
341
+ # api = TrophyApiClient::Client.new(
342
+ # base_url: "https://api.example.com",
343
+ # environment: TrophyApiClient::Environment::PRODUCTION,
344
+ # api_key: "YOUR_API_KEY"
345
+ # )
346
+ # api.admin.leaderboards.get(id: "550e8400-e29b-41d4-a716-446655440100")
347
+ def get(id:, request_options: nil)
348
+ Async do
349
+ response = @request_client.conn.get do |req|
350
+ req.options.timeout = request_options.timeout_in_seconds unless request_options&.timeout_in_seconds.nil?
351
+ req.headers["X-API-KEY"] = request_options.api_key unless request_options&.api_key.nil?
352
+ req.headers = {
353
+ **(req.headers || {}),
354
+ **@request_client.get_headers,
355
+ **(request_options&.additional_headers || {})
356
+ }.compact
357
+ unless request_options.nil? || request_options&.additional_query_parameters.nil?
358
+ req.params = { **(request_options&.additional_query_parameters || {}) }.compact
359
+ end
360
+ unless request_options.nil? || request_options&.additional_body_parameters.nil?
361
+ req.body = { **(request_options&.additional_body_parameters || {}) }.compact
362
+ end
363
+ req.url "#{@request_client.get_url(environment: admin,
364
+ request_options: request_options)}/leaderboards/#{id}"
365
+ end
366
+ TrophyApiClient::AdminLeaderboard.from_json(json_object: response.body)
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end