arel_extensions 1.2.5 → 1.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -4
  3. data/README.md +7 -2
  4. data/Rakefile +23 -23
  5. data/arel_extensions.gemspec +1 -1
  6. data/functions.html +2 -2
  7. data/gemfiles/rails6.gemfile +30 -0
  8. data/gemspec_v2/arel_extensions-v2.gemspec +28 -0
  9. data/generate_gems.sh +13 -0
  10. data/lib/arel_extensions.rb +4 -1
  11. data/lib/arel_extensions/boolean_functions.rb +0 -2
  12. data/lib/arel_extensions/common_sql_functions.rb +5 -4
  13. data/lib/arel_extensions/insert_manager.rb +24 -24
  14. data/lib/arel_extensions/math.rb +3 -3
  15. data/lib/arel_extensions/math_functions.rb +4 -4
  16. data/lib/arel_extensions/nodes/case.rb +0 -2
  17. data/lib/arel_extensions/nodes/collate.rb +1 -1
  18. data/lib/arel_extensions/nodes/date_diff.rb +1 -3
  19. data/lib/arel_extensions/nodes/duration.rb +0 -2
  20. data/lib/arel_extensions/nodes/formatted_number.rb +20 -20
  21. data/lib/arel_extensions/nodes/json.rb +28 -30
  22. data/lib/arel_extensions/nodes/power.rb +5 -4
  23. data/lib/arel_extensions/nodes/replace.rb +23 -5
  24. data/lib/arel_extensions/nodes/round.rb +5 -5
  25. data/lib/arel_extensions/nodes/soundex.rb +14 -13
  26. data/lib/arel_extensions/nodes/substring.rb +8 -15
  27. data/lib/arel_extensions/nodes/trim.rb +1 -1
  28. data/lib/arel_extensions/nodes/union.rb +0 -1
  29. data/lib/arel_extensions/nodes/union_all.rb +0 -1
  30. data/lib/arel_extensions/predications.rb +16 -17
  31. data/lib/arel_extensions/string_functions.rb +12 -6
  32. data/lib/arel_extensions/tasks.rb +5 -5
  33. data/lib/arel_extensions/version.rb +1 -1
  34. data/lib/arel_extensions/visitors/mssql.rb +13 -12
  35. data/lib/arel_extensions/visitors/mysql.rb +50 -35
  36. data/lib/arel_extensions/visitors/oracle.rb +7 -6
  37. data/lib/arel_extensions/visitors/oracle12.rb +1 -1
  38. data/lib/arel_extensions/visitors/postgresql.rb +45 -27
  39. data/lib/arel_extensions/visitors/sqlite.rb +41 -27
  40. data/lib/arel_extensions/visitors/to_sql.rb +18 -5
  41. data/test/visitors/test_bulk_insert_oracle.rb +6 -6
  42. data/test/visitors/test_bulk_insert_sqlite.rb +5 -5
  43. data/test/visitors/test_to_sql.rb +10 -2
  44. data/test/with_ar/all_agnostic_test.rb +44 -33
  45. data/test/with_ar/test_bulk_sqlite.rb +1 -1
  46. data/test/with_ar/test_math_sqlite.rb +1 -1
  47. data/test/with_ar/test_string_mysql.rb +1 -3
  48. data/test/with_ar/test_string_sqlite.rb +1 -5
  49. data/version_v1.rb +3 -0
  50. data/version_v2.rb +3 -0
  51. metadata +9 -4
@@ -97,26 +97,28 @@ module ArelExtensions
97
97
  end
98
98
 
99
99
  def visit_ArelExtensions_Nodes_Collate o, collector
100
- case o.expressions.first
101
- when Arel::Attributes::Attribute
102
- charset = case o.option
100
+ charset =
101
+ case o.expressions.first
102
+ when Arel::Attributes::Attribute
103
+ case o.option
103
104
  when 'latin1','utf8'
104
105
  o.option
105
106
  else
106
107
  Arel::Table.engine.connection.charset || 'utf8'
107
108
  end
108
- else
109
- charset = (o.option == 'latin1') ? 'latin1' : 'utf8'
110
- end
109
+ else
110
+ (o.option == 'latin1') ? 'latin1' : 'utf8'
111
+ end
111
112
  collector = visit o.expressions.first, collector
112
- if o.ai
113
- collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
113
+ collector <<
114
+ if o.ai
115
+ " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
114
116
  #doesn't work in latin1
115
- elsif o.ci
116
- collector << " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
117
- else
118
- collector << " COLLATE #{charset}_bin"
119
- end
117
+ elsif o.ci
118
+ " COLLATE #{charset == 'latin1' ? 'latin1_general_ci' : 'utf8_unicode_ci' }"
119
+ else
120
+ " COLLATE #{charset}_bin"
121
+ end
120
122
  collector
121
123
  end
122
124
 
@@ -262,7 +264,7 @@ module ArelExtensions
262
264
  else
263
265
  if o.with_interval
264
266
  case o.left
265
- when 'd','m','y'
267
+ when 'd','m','y'
266
268
  interval = 'DAY'
267
269
  when 'h','mn','s'
268
270
  interval = 'SECOND'
@@ -362,20 +364,21 @@ module ArelExtensions
362
364
  else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
363
365
  sign_length = ArelExtensions::Nodes::Length.new([sign])
364
366
 
365
- if o.scientific_notation
366
- number = ArelExtensions::Nodes::Concat.new([
367
- Arel::Nodes::NamedFunction.new('FORMAT',[
368
- col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
369
- ]+params),
370
- o.type,
371
- Arel::Nodes::NamedFunction.new('FORMAT',[
372
- col.abs.log10.floor,
373
- 0
367
+ number =
368
+ if o.scientific_notation
369
+ ArelExtensions::Nodes::Concat.new([
370
+ Arel::Nodes::NamedFunction.new('FORMAT',[
371
+ col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor)
372
+ ]+params),
373
+ o.type,
374
+ Arel::Nodes::NamedFunction.new('FORMAT',[
375
+ col.abs.log10.floor,
376
+ 0
377
+ ])
374
378
  ])
375
- ])
376
- else
377
- number = Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
378
- end
379
+ else
380
+ Arel::Nodes::NamedFunction.new('FORMAT',[col.abs]+params)
381
+ end
379
382
 
380
383
  repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
381
384
  when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
@@ -399,19 +402,19 @@ module ArelExtensions
399
402
  end
400
403
 
401
404
  def visit_Aggregate_For_AggregateFunction o, collector
402
- if !(Arel::Table.engine.connection.send(:version) >= (Arel::Table.engine.connection.send(:mariadb?) ? '10.2.3' : '8.0'))
405
+ if !window_supported?
403
406
  warn("Warning : ArelExtensions: Window Functions are not available in the current version on the DBMS.")
404
407
  return collector
405
408
  end
406
409
 
407
- if o.order || o.group
410
+ if !o.order.empty? || !o.group.empty?
408
411
  collector << " OVER ("
409
- if o.group
412
+ if !o.group.empty?
410
413
  collector << " PARTITION BY ("
411
414
  visit o.group, collector
412
415
  collector << ")"
413
416
  end
414
- if o.order
417
+ if !o.order.empty?
415
418
  collector << " ORDER BY ("
416
419
  visit o.order, collector
417
420
  collector << ")"
@@ -433,15 +436,27 @@ module ArelExtensions
433
436
  collector << (o.unbiased_estimator ? "VAR_SAMP(" : "VAR_POP(")
434
437
  visit o.left, collector
435
438
  collector << ")"
439
+ visit_Aggregate_For_AggregateFunction o, collector
436
440
  collector
437
441
  end
438
442
 
439
443
  # JSON if implemented only after 10.2.3 in MariaDb and 5.7 in MySql
440
444
  def json_supported?
441
- Arel::Table.engine.connection.send(:mariadb?) &&
442
- Arel::Table.engine.connection.send(:version) >= '10.2.3' ||
443
- !Arel::Table.engine.connection.send(:mariadb?) &&
444
- Arel::Table.engine.connection.send(:version) >= '5.7.0'
445
+ version_supported?('10.2.3', '5.7.0')
446
+ end
447
+
448
+ def window_supported?
449
+ version_supported?('10.2.3', '8.0')
450
+ end
451
+
452
+ def version_supported?(mysql_v = '10.2.3',mariadb_v = '5.7.0')
453
+ conn = Arel::Table.engine.connection
454
+ conn.send(:mariadb?) &&
455
+ (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mysql_v ||
456
+ conn.respond_to?(:version) && conn.send(:version) >= mysql_v) ||
457
+ !Arel::Table.engine.connection.send(:mariadb?) &&
458
+ (conn.respond_to?(:get_database_version) && conn.send(:get_database_version) >= mariadb_v ||
459
+ conn.respond_to?(:version) && conn.send(:version) >= mariadb_v)
445
460
  end
446
461
 
447
462
  def visit_ArelExtensions_Nodes_Json o,collector
@@ -131,11 +131,12 @@ module ArelExtensions
131
131
  collector << "(LISTAGG("
132
132
  collector = visit o.left, collector
133
133
  collector << Arel::Visitors::Oracle::COMMA
134
- if o.separator && o.separator != 'NULL'
135
- collector = visit o.separator, collector
136
- else
137
- collector = visit Arel::Nodes.build_quoted(','), collector
138
- end
134
+ collector =
135
+ if o.separator && o.separator != 'NULL'
136
+ visit o.separator, collector
137
+ else
138
+ visit Arel::Nodes.build_quoted(','), collector
139
+ end
139
140
  collector << ") WITHIN GROUP (ORDER BY "
140
141
  if !o.order.blank?
141
142
  o.order.each_with_index do |order,i|
@@ -154,7 +155,7 @@ module ArelExtensions
154
155
  o.expressions.each_with_index { |arg, i|
155
156
  collector << Arel::Visitors::Oracle::COMMA unless i == 0
156
157
  if i > 0 && o.left_node_type == :text
157
- if arg == '' || (arg.is_a?(Arel::Nodes::Quoted) && (arg.expr == ''))
158
+ if arg == '' || (arg.is_a?(Arel::Nodes::Quoted) && (arg.expr == ''))
158
159
  collector << "NULL"
159
160
  else
160
161
  collector << 'TO_CLOB('
@@ -68,7 +68,7 @@ module ArelExtensions
68
68
  if i != 0
69
69
  collector << Arel::Visitors::MySQL::COMMA
70
70
  end
71
- collector = visit v, collector
71
+ collector = visit v, collector
72
72
  end
73
73
  collector << ')'
74
74
  when Hash
@@ -120,11 +120,12 @@ module ArelExtensions
120
120
  o.order = nil
121
121
  visit_Aggregate_For_AggregateFunction o, collector
122
122
  collector << Arel::Visitors::PostgreSQL::COMMA
123
- if o.separator && o.separator != 'NULL'
124
- collector = visit o.separator, collector
125
- else
126
- collector = visit Arel::Nodes.build_quoted(','), collector
127
- end
123
+ collector =
124
+ if o.separator && o.separator != 'NULL'
125
+ visit o.separator, collector
126
+ else
127
+ visit Arel::Nodes.build_quoted(','), collector
128
+ end
128
129
  collector << ")"
129
130
  collector
130
131
  end
@@ -302,6 +303,22 @@ module ArelExtensions
302
303
  collector
303
304
  end
304
305
 
306
+ def visit_ArelExtensions_Nodes_RegexpReplace o, collector
307
+ collector << "REGEXP_REPLACE("
308
+ visit o.left, collector
309
+ collector << Arel::Visitors::ToSql::COMMA
310
+ tab = o.pattern.inspect+ 'g' # Make it always global
311
+ pattern = tab.split('/')[1..-2].join('/')
312
+ flags = tab.split('/')[-1]
313
+ visit Arel::Nodes.build_quoted(pattern), collector
314
+ collector << Arel::Visitors::ToSql::COMMA
315
+ visit o.substitute, collector
316
+ collector << Arel::Visitors::ToSql::COMMA
317
+ visit Arel::Nodes.build_quoted(flags+"g"), collector
318
+ collector << ")"
319
+ collector
320
+ end
321
+
305
322
  def visit_ArelExtensions_Nodes_IsNull o, collector
306
323
  collector = visit o.expr, collector
307
324
  collector << ' IS NULL'
@@ -371,27 +388,28 @@ module ArelExtensions
371
388
  else(o.flags.include?('+') ? '+' : (o.flags.include?(' ') ? ' ' : ''))
372
389
  sign_length = ArelExtensions::Nodes::Length.new([sign])
373
390
 
374
- if o.scientific_notation
375
- number = ArelExtensions::Nodes::Concat.new([
376
- Arel::Nodes::NamedFunction.new('TRIM',[
377
- Arel::Nodes::NamedFunction.new('TO_CHAR',[
378
- col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
379
- Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
380
- ])]),
381
- o.type,
382
- Arel::Nodes::NamedFunction.new('TRIM',[
383
- Arel::Nodes::NamedFunction.new('TO_CHAR',[
384
- col.abs.log10.floor,
385
- Arel::Nodes.build_quoted('FM'+nines_before)
386
- ])])
387
- ])
388
- else
389
- number = Arel::Nodes::NamedFunction.new('TRIM',[
390
- Arel::Nodes::NamedFunction.new('TO_CHAR',[
391
- Arel::Nodes.build_quoted(col.abs),
392
- Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
393
- ])])
394
- end
391
+ number =
392
+ if o.scientific_notation
393
+ ArelExtensions::Nodes::Concat.new([
394
+ Arel::Nodes::NamedFunction.new('TRIM',[
395
+ Arel::Nodes::NamedFunction.new('TO_CHAR',[
396
+ col.abs/Arel::Nodes.build_quoted(10).pow(col.abs.log10.floor),
397
+ Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
398
+ ])]),
399
+ o.type,
400
+ Arel::Nodes::NamedFunction.new('TRIM',[
401
+ Arel::Nodes::NamedFunction.new('TO_CHAR',[
402
+ col.abs.log10.floor,
403
+ Arel::Nodes.build_quoted('FM'+nines_before)
404
+ ])])
405
+ ])
406
+ else
407
+ Arel::Nodes::NamedFunction.new('TRIM',[
408
+ Arel::Nodes::NamedFunction.new('TO_CHAR',[
409
+ Arel::Nodes.build_quoted(col.abs),
410
+ Arel::Nodes.build_quoted('FM'+nines_before+'"'+comma+'"V'+nines_after)
411
+ ])])
412
+ end
395
413
 
396
414
  repeated_char = (o.width == 0) ? Arel::Nodes.build_quoted('') : ArelExtensions::Nodes::Case.new().
397
415
  when(Arel::Nodes.build_quoted(o.width).abs-(number.length+sign_length)>0).
@@ -466,7 +484,7 @@ module ArelExtensions
466
484
  if i != 0
467
485
  collector << Arel::Visitors::MySQL::COMMA
468
486
  end
469
- collector = visit v, collector
487
+ collector = visit v, collector
470
488
  end
471
489
  collector << '])'
472
490
  when Hash
@@ -193,18 +193,28 @@ module ArelExtensions
193
193
  collector
194
194
  end
195
195
 
196
- # CASE WHEN ROUND(3.42,1) > round(3.42) THEN round(3.42) ELSE round(3.42)-1 END
197
- # OR CAST(3.14 AS INTEGER)
196
+ # CAST(
197
+ # CASE
198
+ # WHEN 3.42 >= 0 THEN CAST(3.42 AS INT)
199
+ # WHEN CAST(3.42 AS INT) = 3.42 THEN CAST(3.42 AS INT)
200
+ # ELSE CAST((3.42 - 1.0) AS INT)
201
+ # END
202
+ # AS FLOAT
203
+ # )
198
204
  def visit_ArelExtensions_Nodes_Floor o, collector
199
- collector << "CASE WHEN ROUND("
205
+ collector << "CAST(CASE WHEN "
200
206
  collector = visit o.left, collector
201
- collector << ", 1) > ROUND("
207
+ collector << " >= 0 THEN CAST("
202
208
  collector = visit o.left, collector
203
- collector << ") THEN ROUND("
209
+ collector << " AS INT) WHEN CAST("
210
+ collector = visit o.left, collector
211
+ collector << " AS INT) = "
204
212
  collector = visit o.left, collector
205
- collector << ") ELSE ROUND("
213
+ collector << " THEN CAST("
206
214
  collector = visit o.left, collector
207
- collector << ") - 1 END"
215
+ collector << " AS INT) ELSE CAST(("
216
+ collector = visit o.left, collector
217
+ collector << " - 1.0) AS INT) END AS FLOAT)"
208
218
  collector
209
219
  end
210
220
 
@@ -270,32 +280,36 @@ module ArelExtensions
270
280
  end
271
281
 
272
282
  def visit_ArelExtensions_Nodes_Union o, collector
273
- if o.left.is_a?(Arel::SelectManager)
274
- collector = visit o.left.ast, collector
275
- else
276
- collector = visit o.left, collector
277
- end
283
+ collector =
284
+ if o.left.is_a?(Arel::SelectManager)
285
+ visit o.left.ast, collector
286
+ else
287
+ visit o.left, collector
288
+ end
278
289
  collector << " UNION "
279
- if o.right.is_a?(Arel::SelectManager)
280
- collector = visit o.right.ast, collector
281
- else
282
- collector = visit o.right, collector
283
- end
290
+ collector =
291
+ if o.right.is_a?(Arel::SelectManager)
292
+ visit o.right.ast, collector
293
+ else
294
+ visit o.right, collector
295
+ end
284
296
  collector
285
297
  end
286
298
 
287
299
  def visit_ArelExtensions_Nodes_UnionAll o, collector
288
- if o.left.is_a?(Arel::SelectManager)
289
- collector = visit o.left.ast, collector
290
- else
291
- collector = visit o.left, collector
292
- end
300
+ collector =
301
+ if o.left.is_a?(Arel::SelectManager)
302
+ visit o.left.ast, collector
303
+ else
304
+ visit o.left, collector
305
+ end
293
306
  collector << " UNION ALL "
294
- if o.right.is_a?(Arel::SelectManager)
295
- collector = visit o.right.ast, collector
296
- else
297
- collector = visit o.right, collector
298
- end
307
+ collector =
308
+ if o.right.is_a?(Arel::SelectManager)
309
+ visit o.right.ast, collector
310
+ else
311
+ visit o.right, collector
312
+ end
299
313
  collector
300
314
  end
301
315
 
@@ -1,6 +1,7 @@
1
1
  module ArelExtensions
2
2
  module Visitors
3
- Arel::Visitors::ToSql.class_eval do
3
+ Arel::Visitors::ToSql.class_eval do
4
+ Arel::Visitors::ToSql::COMMA = ', ' unless defined?(Arel::Visitors::ToSql::COMMA)
4
5
 
5
6
  # Math Functions
6
7
  def visit_ArelExtensions_Nodes_Abs o, collector
@@ -134,10 +135,22 @@ module ArelExtensions
134
135
 
135
136
  def visit_ArelExtensions_Nodes_Replace o, collector
136
137
  collector << "REPLACE("
137
- o.expressions.each_with_index { |arg, i|
138
- collector << Arel::Visitors::ToSql::COMMA unless i == 0
139
- collector = visit arg, collector
140
- }
138
+ visit o.left, collector
139
+ collector << Arel::Visitors::ToSql::COMMA
140
+ visit o.pattern, collector
141
+ collector << Arel::Visitors::ToSql::COMMA
142
+ visit o.substitute, collector
143
+ collector << ")"
144
+ collector
145
+ end
146
+
147
+ def visit_ArelExtensions_Nodes_RegexpReplace o, collector
148
+ collector << "REGEXP_REPLACE("
149
+ visit o.left, collector
150
+ collector << Arel::Visitors::ToSql::COMMA
151
+ visit Arel::Nodes.build_quoted(o.pattern.to_s), collector
152
+ collector << Arel::Visitors::ToSql::COMMA
153
+ visit o.substitute, collector
141
154
  collector << ")"
142
155
  collector
143
156
  end
@@ -9,8 +9,8 @@ module ArelExtensions
9
9
  @table = Arel::Table.new(:users)
10
10
  @cols = ['name', 'comments', 'created_at']
11
11
  @data = [
12
- ['nom1', "sdfdsfdsfsdf", '2016-01-01'],
13
- ['nom2', "sdfdsfdsfsdf", '2016-01-01']
12
+ ['nom1', "sdfdsfdsfsdf", '2016-01-01'],
13
+ ['nom2', "sdfdsfdsfsdf", '2016-01-01']
14
14
  ]
15
15
  end
16
16
 
@@ -24,11 +24,11 @@ module ArelExtensions
24
24
 
25
25
  it "should import large set of data in Oracle" do
26
26
  insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
27
- insert_manager.bulk_insert(@cols, @data)
28
- sql = compile(insert_manager.ast)
29
- sql.must_be_like %Q[INSERT INTO "users" ("name", "comments", "created_at") ((SELECT 'nom1', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL) UNION ALL (SELECT 'nom2', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL))]
27
+ insert_manager.bulk_insert(@cols, @data)
28
+ sql = compile(insert_manager.ast)
29
+ sql.must_be_like %Q[INSERT INTO "users" ("name", "comments", "created_at") ((SELECT 'nom1', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL) UNION ALL (SELECT 'nom2', 'sdfdsfdsfsdf', '2016-01-01' FROM DUAL))]
30
30
  end
31
31
 
32
- end
32
+ end
33
33
  end
34
34
  end
@@ -11,8 +11,8 @@ module ArelExtensions
11
11
  Arel::Table.engine = @conn
12
12
  @cols = ['id', 'name', 'comments', 'created_at']
13
13
  @data = [
14
- [23, 'nom1', "sdfdsfdsfsdf", '2016-01-01'],
15
- [25, 'nom2', "sdfdsfdsfsdf", '2016-01-01']
14
+ [23, 'nom1', "sdfdsfdsfsdf", '2016-01-01'],
15
+ [25, 'nom2', "sdfdsfdsfsdf", '2016-01-01']
16
16
  ]
17
17
  end
18
18
 
@@ -28,9 +28,9 @@ module ArelExtensions
28
28
  insert_manager = Arel::VERSION.to_i > 6 ? Arel::InsertManager.new().into(@table) : Arel::InsertManager.new(@conn).into(@table)
29
29
  insert_manager.bulk_insert(@cols, @data)
30
30
  sql = compile(insert_manager.ast)
31
- sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") SELECT 23 AS 'id', 'nom1' AS 'name', 'sdfdsfdsfsdf' AS 'comments', '2016-01-01' AS 'created_at' UNION ALL SELECT 25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01']
31
+ sql.must_be_like %Q[INSERT INTO "users" ("id", "name", "comments", "created_at") SELECT 23 AS 'id', 'nom1' AS 'name', 'sdfdsfdsfsdf' AS 'comments', '2016-01-01' AS 'created_at' UNION ALL SELECT 25, 'nom2', 'sdfdsfdsfsdf', '2016-01-01']
32
32
  end
33
33
 
34
- end
34
+ end
35
35
  end
36
- end
36
+ end