avo 0.5.0.beta9 → 0.5.0.beta10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of avo might be problematic. Click here for more details.

Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +47 -48
  3. data/Gemfile.lock +1 -1
  4. data/Rakefile +14 -14
  5. data/app/components/avo/common/multiple_file_viewer_component.rb +1 -1
  6. data/app/components/avo/common/single_file_viewer_component.rb +1 -1
  7. data/app/components/avo/edit/field_wrapper_component.rb +3 -3
  8. data/app/components/avo/index/field_wrapper_component.rb +1 -1
  9. data/app/components/avo/index/grid_item_component.rb +10 -9
  10. data/app/components/avo/index/resource_controls_component.rb +2 -2
  11. data/app/components/avo/panel_component.rb +7 -6
  12. data/app/components/avo/resource_component.rb +4 -3
  13. data/app/components/avo/show/field_wrapper_component.rb +3 -3
  14. data/app/components/avo/views/resource_edit_component.rb +4 -3
  15. data/app/components/avo/views/resource_index_component.rb +8 -7
  16. data/app/components/avo/views/resource_new_component.rb +4 -3
  17. data/app/components/avo/views/resource_show_component.rb +21 -21
  18. data/app/controllers/avo/actions_controller.rb +30 -29
  19. data/app/controllers/avo/application_controller.rb +113 -126
  20. data/app/controllers/avo/attachments_controller.rb +3 -3
  21. data/app/controllers/avo/base_controller.rb +81 -80
  22. data/app/controllers/avo/home_controller.rb +2 -2
  23. data/app/controllers/avo/relations_controller.rb +29 -28
  24. data/app/controllers/avo/resources_controller.rb +1 -1
  25. data/app/controllers/avo/search_controller.rb +20 -19
  26. data/app/helpers/avo/application_helper.rb +48 -42
  27. data/app/helpers/avo/resources_helper.rb +11 -11
  28. data/app/mailers/avo/application_mailer.rb +2 -2
  29. data/app/packs/entrypoints/application.js +9 -7
  30. data/app/packs/js/controllers/fields/code_field_controller.js +14 -14
  31. data/app/packs/js/controllers/filter_controller.js +9 -8
  32. data/app/packs/js/toastr.js +1 -0
  33. data/avo.gemspec +31 -31
  34. data/config/initializers/inline_svg.rb +1 -1
  35. data/config/initializers/pagy.rb +1 -1
  36. data/config/routes.rb +12 -12
  37. data/config/spring.rb +5 -5
  38. data/db/factories.rb +3 -5
  39. data/lib/avo.rb +6 -6
  40. data/lib/avo/app.rb +18 -18
  41. data/lib/avo/base_action.rb +20 -20
  42. data/lib/avo/base_resource.rb +41 -45
  43. data/lib/avo/configuration.rb +16 -18
  44. data/lib/avo/engine.rb +18 -18
  45. data/lib/avo/fields/badge_field.rb +2 -2
  46. data/lib/avo/fields/base_field.rb +24 -25
  47. data/lib/avo/fields/belongs_to_field.rb +13 -12
  48. data/lib/avo/fields/boolean_field.rb +4 -4
  49. data/lib/avo/fields/boolean_group_field.rb +3 -3
  50. data/lib/avo/fields/code_field.rb +4 -4
  51. data/lib/avo/fields/country_field.rb +2 -2
  52. data/lib/avo/fields/currency_field.rb +3 -3
  53. data/lib/avo/fields/date_field.rb +3 -3
  54. data/lib/avo/fields/date_time_field.rb +2 -2
  55. data/lib/avo/fields/external_image_field.rb +2 -2
  56. data/lib/avo/fields/field_extensions/has_field_name.rb +2 -2
  57. data/lib/avo/fields/field_extensions/visible_in_different_views.rb +34 -33
  58. data/lib/avo/fields/file_field.rb +1 -1
  59. data/lib/avo/fields/files_field.rb +2 -2
  60. data/lib/avo/fields/gravatar_field.rb +9 -9
  61. data/lib/avo/fields/has_and_belongs_to_many_field.rb +1 -1
  62. data/lib/avo/fields/has_many_field.rb +1 -1
  63. data/lib/avo/fields/has_one_field.rb +2 -2
  64. data/lib/avo/fields/heading_field.rb +2 -2
  65. data/lib/avo/fields/hidden_field.rb +1 -1
  66. data/lib/avo/fields/id_field.rb +3 -3
  67. data/lib/avo/fields/key_value_field.rb +12 -12
  68. data/lib/avo/fields/markdown_field.rb +2 -2
  69. data/lib/avo/fields/number_field.rb +3 -3
  70. data/lib/avo/fields/password_field.rb +1 -1
  71. data/lib/avo/fields/select_field.rb +8 -12
  72. data/lib/avo/fields/status_field.rb +4 -4
  73. data/lib/avo/fields/text_field.rb +2 -2
  74. data/lib/avo/fields/textarea_field.rb +2 -2
  75. data/lib/avo/fields/trix_field.rb +1 -1
  76. data/lib/avo/fields_collector.rb +4 -5
  77. data/lib/avo/filters/base_filter.rb +6 -6
  78. data/lib/avo/filters/boolean_filter.rb +1 -1
  79. data/lib/avo/filters/select_filter.rb +1 -1
  80. data/lib/avo/licensing/h_q.rb +56 -55
  81. data/lib/avo/licensing/license.rb +5 -5
  82. data/lib/avo/licensing/license_manager.rb +4 -4
  83. data/lib/avo/licensing/null_license.rb +2 -2
  84. data/lib/avo/licensing/pro_license.rb +1 -1
  85. data/lib/avo/loaders/fields_loader.rb +4 -4
  86. data/lib/avo/services/authorization_service.rb +2 -2
  87. data/lib/avo/services/panel_service.rb +4 -4
  88. data/lib/avo/version.rb +1 -1
  89. data/lib/generators/avo/action_generator.rb +4 -4
  90. data/lib/generators/avo/controller_generator.rb +4 -4
  91. data/lib/generators/avo/filter_generator.rb +5 -5
  92. data/lib/generators/avo/install_generator.rb +8 -8
  93. data/lib/generators/avo/locales_generator.rb +5 -5
  94. data/lib/generators/avo/partials_generator.rb +4 -4
  95. data/lib/generators/avo/resource_generator.rb +5 -5
  96. data/lib/tasks/avo_tasks.rake +52 -53
  97. data/public/avo-packs/css/{application-38e7e91b.css → application-4e16d6a6.css} +4 -4
  98. data/public/avo-packs/css/application-4e16d6a6.css.br +0 -0
  99. data/public/avo-packs/css/{application-38e7e91b.css.gz → application-4e16d6a6.css.gz} +0 -0
  100. data/public/avo-packs/css/{application-38e7e91b.css.map → application-4e16d6a6.css.map} +1 -1
  101. data/public/avo-packs/css/application-4e16d6a6.css.map.br +0 -0
  102. data/public/avo-packs/css/application-4e16d6a6.css.map.gz +0 -0
  103. data/public/avo-packs/js/{application-2b90fe889f7d6df1ad92.js → application-8eb130a4688f2c667703.js} +4 -4
  104. data/public/avo-packs/js/{application-2b90fe889f7d6df1ad92.js.LICENSE.txt → application-8eb130a4688f2c667703.js.LICENSE.txt} +0 -0
  105. data/public/avo-packs/js/application-8eb130a4688f2c667703.js.br +0 -0
  106. data/public/avo-packs/js/application-8eb130a4688f2c667703.js.gz +0 -0
  107. data/public/avo-packs/js/application-8eb130a4688f2c667703.js.map +1 -0
  108. data/public/avo-packs/js/application-8eb130a4688f2c667703.js.map.br +0 -0
  109. data/public/avo-packs/js/application-8eb130a4688f2c667703.js.map.gz +0 -0
  110. data/public/avo-packs/manifest.json +15 -15
  111. metadata +15 -15
  112. data/public/avo-packs/css/application-38e7e91b.css.br +0 -0
  113. data/public/avo-packs/css/application-38e7e91b.css.map.br +0 -0
  114. data/public/avo-packs/css/application-38e7e91b.css.map.gz +0 -0
  115. data/public/avo-packs/js/application-2b90fe889f7d6df1ad92.js.br +0 -0
  116. data/public/avo-packs/js/application-2b90fe889f7d6df1ad92.js.gz +0 -0
  117. data/public/avo-packs/js/application-2b90fe889f7d6df1ad92.js.map +0 -1
  118. data/public/avo-packs/js/application-2b90fe889f7d6df1ad92.js.map.br +0 -0
  119. data/public/avo-packs/js/application-2b90fe889f7d6df1ad92.js.map.gz +0 -0
@@ -1,36 +1,36 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  module Avo
4
4
  module Fields
5
5
  class KeyValueField < BaseField
6
6
  def initialize(name, **args, &block)
7
7
  @defaults = {
8
- partial_name: 'key-value-field',
8
+ partial_name: "key-value-field"
9
9
  }
10
10
 
11
11
  super(name, **args, &block)
12
12
 
13
13
  hide_on :index
14
14
 
15
- @key_label = args[:key_label].present? ? args[:key_label].to_s : 'Key'
16
- @value_label = args[:value_label].present? ? args[:value_label].to_s : 'Value'
17
- @action_text = args[:action_text].present? ? args[:action_text].to_s : 'Add row'
18
- @delete_text = args[:delete_text].present? ? args[:delete_text].to_s : 'Delete row'
15
+ @key_label = args[:key_label].present? ? args[:key_label].to_s : "Key"
16
+ @value_label = args[:value_label].present? ? args[:value_label].to_s : "Value"
17
+ @action_text = args[:action_text].present? ? args[:action_text].to_s : "Add row"
18
+ @delete_text = args[:delete_text].present? ? args[:delete_text].to_s : "Delete row"
19
19
 
20
20
  @disable_editing_keys = args[:disable_editing_keys].present? ? args[:disable_editing_keys] : false
21
21
  # disabling editing keys also disables adding rows (doesn't take into account the value of disable_adding_rows)
22
- if args[:disable_editing_keys].present? && args[:disable_editing_keys] == true
23
- @disable_adding_rows = true
22
+ @disable_adding_rows = if args[:disable_editing_keys].present? && args[:disable_editing_keys] == true
23
+ true
24
24
  elsif args[:disable_adding_rows].present?
25
- @disable_adding_rows = args[:disable_adding_rows]
25
+ args[:disable_adding_rows]
26
26
  else
27
- @disable_adding_rows = false
27
+ false
28
28
  end
29
29
  @disable_deleting_rows = args[:disable_deleting_rows].present? ? args[:disable_deleting_rows] : false
30
30
  end
31
31
 
32
32
  def to_permitted_param
33
- [:"#{id}", "#{id}": {} ]
33
+ [:"#{id}", "#{id}": {}]
34
34
  end
35
35
 
36
36
  def hydrate_field(fields, model, resource, view)
@@ -41,7 +41,7 @@ module Avo
41
41
  delete_text: @delete_text,
42
42
  disable_editing_keys: @disable_editing_keys,
43
43
  disable_adding_rows: @disable_adding_rows,
44
- disable_deleting_rows: @disable_deleting_rows,
44
+ disable_deleting_rows: @disable_deleting_rows
45
45
  }
46
46
  end
47
47
  end
@@ -3,7 +3,7 @@ module Avo
3
3
  class MarkdownField < BaseField
4
4
  def initialize(name, **args, &block)
5
5
  @defaults = {
6
- partial_name: 'markdown-field',
6
+ partial_name: "markdown-field"
7
7
  }
8
8
 
9
9
  super(name, **args, &block)
@@ -11,7 +11,7 @@ module Avo
11
11
  hide_on :index
12
12
 
13
13
  @always_show = args[:always_show].present? ? args[:always_show] : false
14
- @height = args[:height].present? ? args[:height].to_s : 'auto'
14
+ @height = args[:height].present? ? args[:height].to_s : "auto"
15
15
  end
16
16
 
17
17
  def hydrate_field(fields, model, resource, view)
@@ -3,8 +3,8 @@ module Avo
3
3
  class NumberField < TextField
4
4
  def initialize(name, **args, &block)
5
5
  @defaults = {
6
- partial_name: 'number-field',
7
- computable: true,
6
+ partial_name: "number-field",
7
+ computable: true
8
8
  }
9
9
 
10
10
  super(name, **args, &block)
@@ -12,7 +12,7 @@ module Avo
12
12
  @meta = {
13
13
  min: args[:min].present? ? args[:min].to_f : nil,
14
14
  max: args[:max].present? ? args[:max].to_f : nil,
15
- step: args[:step].present? ? args[:step].to_f : nil,
15
+ step: args[:step].present? ? args[:step].to_f : nil
16
16
  }
17
17
  end
18
18
  end
@@ -3,7 +3,7 @@ module Avo
3
3
  class PasswordField < TextField
4
4
  def initialize(name, **args, &block)
5
5
  @defaults = {
6
- partial_name: 'password-field',
6
+ partial_name: "password-field"
7
7
  }
8
8
 
9
9
  show_on :forms
@@ -7,7 +7,7 @@ module Avo
7
7
 
8
8
  def initialize(name, **args, &block)
9
9
  @defaults = {
10
- partial_name: 'select-field',
10
+ partial_name: "select-field"
11
11
  }
12
12
 
13
13
  super(name, **args, &block)
@@ -16,7 +16,7 @@ module Avo
16
16
  @options = ActiveSupport::HashWithIndifferentAccess.new @options
17
17
  @enum = args[:enum].present? ? args[:enum] : nil
18
18
  @display_value = args[:display_value].present? ? args[:display_value] : false
19
- @placeholder = args[:placeholder].present? ? args[:placeholder].to_s : I18n.t('avo.choose_an_option')
19
+ @placeholder = args[:placeholder].present? ? args[:placeholder].to_s : I18n.t("avo.choose_an_option")
20
20
  end
21
21
 
22
22
  def options_for_select
@@ -26,24 +26,20 @@ module Avo
26
26
  else
27
27
  options.map { |label, value| [label, label] }.to_h
28
28
  end
29
+ elsif display_value
30
+ options.map { |label, value| [value, value] }.to_h
29
31
  else
30
- if display_value
31
- options.map { |label, value| [value, value] }.to_h
32
- else
33
- options
34
- end
32
+ options
35
33
  end
36
34
  end
37
35
 
38
36
  def label
39
37
  if display_value
40
38
  value
39
+ elsif enum.present?
40
+ options[value]
41
41
  else
42
- if enum.present?
43
- options[value]
44
- else
45
- options.invert[value]
46
- end
42
+ options.invert[value]
47
43
  end
48
44
  end
49
45
  end
@@ -3,7 +3,7 @@ module Avo
3
3
  class StatusField < BaseField
4
4
  def initialize(name, **args, &block)
5
5
  @defaults = {
6
- partial_name: 'status-field',
6
+ partial_name: "status-field"
7
7
  }
8
8
 
9
9
  super(name, **args, &block)
@@ -13,10 +13,10 @@ module Avo
13
13
  end
14
14
 
15
15
  def status
16
- status = 'success'
16
+ status = "success"
17
17
  if value.present?
18
- status = 'failed' if @failed_when.include? value.to_sym
19
- status = 'loading' if @loading_when.include? value.to_sym
18
+ status = "failed" if @failed_when.include? value.to_sym
19
+ status = "loading" if @loading_when.include? value.to_sym
20
20
  end
21
21
 
22
22
  status
@@ -3,8 +3,8 @@ module Avo
3
3
  class TextField < BaseField
4
4
  def initialize(name, **args, &block)
5
5
  @defaults = {
6
- partial_name: 'text-field',
7
- computable: true,
6
+ partial_name: "text-field",
7
+ computable: true
8
8
  }.merge(@defaults || {})
9
9
 
10
10
  super(name, **args, &block)
@@ -3,8 +3,8 @@ module Avo
3
3
  class TextareaField < TextField
4
4
  def initialize(name, **args, &block)
5
5
  @defaults = {
6
- partial_name: 'textarea-field',
7
- computable: true,
6
+ partial_name: "textarea-field",
7
+ computable: true
8
8
  }
9
9
 
10
10
  super(name, **args, &block)
@@ -5,7 +5,7 @@ module Avo
5
5
 
6
6
  def initialize(name, **args, &block)
7
7
  @defaults = {
8
- partial_name: 'trix-field',
8
+ partial_name: "trix-field"
9
9
  }
10
10
 
11
11
  super(name, **args, &block)
@@ -11,16 +11,15 @@ module Avo
11
11
  field[:name].to_s == as.to_s
12
12
  end
13
13
 
14
- if matched_field.present? and matched_field[:class].present?
14
+ if matched_field.present? && matched_field[:class].present?
15
15
  klass = matched_field[:class]
16
16
 
17
- if block_given?
18
- field = klass.new(field_name, **args || {}, &block)
17
+ if block
18
+ klass.new(field_name, **args || {}, &block)
19
19
  else
20
- field = klass.new(field_name, **args || {})
20
+ klass.new(field_name, **args || {})
21
21
  end
22
22
 
23
- field
24
23
  end
25
24
  end
26
25
 
@@ -1,19 +1,19 @@
1
1
  module Avo
2
2
  module Filters
3
3
  class BaseFilter
4
- class_attribute :name, default: 'Filter'
5
- class_attribute :component, default: 'boolean-filter'
6
- class_attribute :default, default: ''
7
- class_attribute :template, default: 'avo/base/select_filter'
4
+ class_attribute :name, default: "Filter"
5
+ class_attribute :component, default: "boolean-filter"
6
+ class_attribute :default, default: ""
7
+ class_attribute :template, default: "avo/base/select_filter"
8
8
 
9
9
  def apply_query(request, query, value)
10
10
  value.symbolize_keys! if value.is_a? Hash
11
11
 
12
- self.apply(request, query, value)
12
+ apply(request, query, value)
13
13
  end
14
14
 
15
15
  def id
16
- self.class.name.underscore.gsub('/', '_')
16
+ self.class.name.underscore.tr("/", "_")
17
17
  end
18
18
  end
19
19
  end
@@ -1,7 +1,7 @@
1
1
  module Avo
2
2
  module Filters
3
3
  class BooleanFilter < BaseFilter
4
- self.template = 'avo/base/boolean_filter'
4
+ self.template = "avo/base/boolean_filter"
5
5
  end
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  module Avo
2
2
  module Filters
3
3
  class SelectFilter < BaseFilter
4
- self.template = 'avo/base/select_filter'
4
+ self.template = "avo/base/select_filter"
5
5
  end
6
6
  end
7
7
  end
@@ -3,8 +3,8 @@ module Avo
3
3
  class HQ
4
4
  attr_accessor :current_request
5
5
 
6
- ENDPOINT = 'https://avohq.io/api/v1/licenses/check' unless const_defined?(:ENDPOINT)
7
- CACHE_KEY = 'avo.hq.response' unless const_defined?(:CACHE_KEY)
6
+ ENDPOINT = "https://avohq.io/api/v1/licenses/check" unless const_defined?(:ENDPOINT)
7
+ CACHE_KEY = "avo.hq.response" unless const_defined?(:CACHE_KEY)
8
8
  REQUEST_TIMEOUT = 5 unless const_defined?(:REQUEST_TIMEOUT) # seconds
9
9
 
10
10
  def initialize(current_request)
@@ -13,76 +13,77 @@ module Avo
13
13
  end
14
14
 
15
15
  def response
16
- @hq_response or request
16
+ @hq_response || request
17
17
  end
18
18
 
19
19
  private
20
- def request
21
- return cached_response if has_cached_response
22
-
23
- begin
24
- perform_and_cache_request
25
- rescue HTTParty::Error => exception
26
- cache_and_return_error 'HTTP client error.', exception.message
27
- rescue Net::OpenTimeout => exception
28
- cache_and_return_error 'Request timeout.', exception.message
29
- rescue SocketError => exception
30
- cache_and_return_error 'Connection error.', exception.message
31
- end
20
+
21
+ def request
22
+ return cached_response if has_cached_response
23
+
24
+ begin
25
+ perform_and_cache_request
26
+ rescue HTTParty::Error => exception
27
+ cache_and_return_error "HTTP client error.", exception.message
28
+ rescue Net::OpenTimeout => exception
29
+ cache_and_return_error "Request timeout.", exception.message
30
+ rescue SocketError => exception
31
+ cache_and_return_error "Connection error.", exception.message
32
32
  end
33
+ end
33
34
 
34
- def perform_and_cache_request
35
- hq_response = perform_request
35
+ def perform_and_cache_request
36
+ hq_response = perform_request
36
37
 
37
- return cache_and_return_error 'Avo HQ Internal server error.', hq_response.body if hq_response.code == 500
38
+ return cache_and_return_error "Avo HQ Internal server error.", hq_response.body if hq_response.code == 500
38
39
 
39
- cache_response 1.hour.to_i, hq_response.parsed_response if hq_response.code == 200
40
- end
40
+ cache_response 1.hour.to_i, hq_response.parsed_response if hq_response.code == 200
41
+ end
41
42
 
42
- def cache_response(time, response)
43
- response.merge!(
44
- expiry: time,
45
- **payload,
46
- ).stringify_keys!
43
+ def cache_response(time, response)
44
+ response.merge!(
45
+ expiry: time,
46
+ **payload
47
+ ).stringify_keys!
47
48
 
48
- @cache_store.write(CACHE_KEY, response, expires_in: time)
49
+ @cache_store.write(CACHE_KEY, response, expires_in: time)
49
50
 
50
- @hq_response = response
51
+ @hq_response = response
51
52
 
52
- response
53
- end
53
+ response
54
+ end
54
55
 
55
- def perform_request
56
- puts 'Performing request to avohq.io API to check license availability.'.inspect if Rails.env.development?
56
+ def perform_request
57
+ puts "Performing request to avohq.io API to check license availability.".inspect if Rails.env.development?
57
58
 
58
- HTTParty.post ENDPOINT, body: payload.to_json, headers: { 'Content-type': 'application/json' }, timeout: REQUEST_TIMEOUT
59
- end
59
+ HTTParty.post ENDPOINT, body: payload.to_json, headers: {'Content-type': "application/json"}, timeout: REQUEST_TIMEOUT
60
+ end
60
61
 
61
- def payload
62
- {
63
- license: Avo.configuration.license,
64
- license_key: Avo.configuration.license_key,
65
- avo_version: Avo::VERSION,
66
- rails_version: Rails::VERSION::STRING,
67
- ruby_version: RUBY_VERSION,
68
- environment: Rails.env,
69
- ip: current_request.ip,
70
- host: current_request.host,
71
- port: current_request.port,
72
- }
73
- end
62
+ def payload
63
+ {
64
+ license: Avo.configuration.license,
65
+ license_key: Avo.configuration.license_key,
66
+ avo_version: Avo::VERSION,
67
+ rails_version: Rails::VERSION::STRING,
68
+ ruby_version: RUBY_VERSION,
69
+ environment: Rails.env,
70
+ ip: current_request.ip,
71
+ host: current_request.host,
72
+ port: current_request.port
73
+ }
74
+ end
74
75
 
75
- def cache_and_return_error(error, exception_message = '')
76
- cache_response 5.minutes.to_i, { error: error, exception_message: exception_message }.stringify_keys
77
- end
76
+ def cache_and_return_error(error, exception_message = "")
77
+ cache_response 5.minutes.to_i, {error: error, exception_message: exception_message}.stringify_keys
78
+ end
78
79
 
79
- def has_cached_response
80
- @cache_store.exist? CACHE_KEY
81
- end
80
+ def has_cached_response
81
+ @cache_store.exist? CACHE_KEY
82
+ end
82
83
 
83
- def cached_response
84
- @cache_store.read CACHE_KEY
85
- end
84
+ def cached_response
85
+ @cache_store.read CACHE_KEY
86
+ end
86
87
  end
87
88
  end
88
89
  end
@@ -7,8 +7,8 @@ module Avo
7
7
 
8
8
  def initialize(response)
9
9
  @response = response
10
- @id = response['id']
11
- @valid = response['valid']
10
+ @id = response["id"]
11
+ @valid = response["valid"]
12
12
  end
13
13
 
14
14
  def valid?
@@ -20,15 +20,15 @@ module Avo
20
20
  end
21
21
 
22
22
  def pro?
23
- id == 'pro'
23
+ id == "pro"
24
24
  end
25
25
 
26
26
  def error
27
- @response['error']
27
+ @response["error"]
28
28
  end
29
29
 
30
30
  def properties
31
- @response.slice('valid', 'id', 'error').symbolize_keys
31
+ @response.slice("valid", "id", "error").symbolize_keys
32
32
  end
33
33
 
34
34
  def abilities