kono_utils 0.15.15 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +5 -5
  2. data/README.rdoc +17 -78
  3. data/app/assets/javascripts/kono_utils/core.coffee +477 -0
  4. data/app/assets/stylesheets/kono_utils/{_kono_styles.css.scss → core.css.scss} +1 -16
  5. data/app/policies/kono_utils/base_editing_policy_concern.rb +52 -3
  6. data/app/policies/kono_utils/base_search_form_policy_concern.rb +25 -0
  7. data/config/initializers/mysql.rb +2 -2
  8. data/config/locales/it.yml +3 -1
  9. data/lib/generators/kono_utils/install/install_generator.rb +44 -0
  10. data/lib/generators/templates/base_editing_controller.template +3 -0
  11. data/lib/generators/templates/base_editing_helper.template +3 -0
  12. data/lib/generators/templates/base_editing_policy.template +4 -0
  13. data/lib/generators/templates/initializer.rb +3 -1
  14. data/lib/kono_utils.rb +29 -18
  15. data/lib/kono_utils/application_core_helper.rb +524 -0
  16. data/lib/kono_utils/application_enum_helper.rb +53 -0
  17. data/lib/kono_utils/application_helper.rb +4 -578
  18. data/lib/kono_utils/base_editing_core_helper.rb +194 -0
  19. data/lib/kono_utils/base_editing_helper.rb +3 -186
  20. data/lib/kono_utils/base_search.rb +32 -19
  21. data/lib/kono_utils/concerns.rb +12 -10
  22. data/lib/kono_utils/concerns/active_record_translation.rb +8 -4
  23. data/lib/kono_utils/concerns/active_storage_remover_helper.rb +61 -0
  24. data/lib/kono_utils/concerns/base_editing.rb +199 -53
  25. data/lib/kono_utils/configuration.rb +18 -0
  26. data/lib/kono_utils/engine.rb +15 -6
  27. data/lib/kono_utils/paginate_proxer.rb +17 -0
  28. data/lib/kono_utils/search_form_builder.rb +24 -0
  29. data/lib/kono_utils/version.rb +1 -1
  30. data/spec/dummy/.gitignore +2 -0
  31. data/spec/dummy/app/assets/config/manifest.js +2 -0
  32. data/spec/dummy/app/assets/javascripts/application.js +2 -0
  33. data/spec/dummy/app/controllers/application_controller.rb +10 -0
  34. data/spec/dummy/app/controllers/base_editing_controller.rb +3 -0
  35. data/spec/dummy/app/controllers/users_controller.rb +2 -0
  36. data/spec/dummy/app/helpers/application_helper.rb +1 -0
  37. data/spec/dummy/app/helpers/base_editing_helper.rb +3 -0
  38. data/spec/dummy/app/models/application_record.rb +5 -0
  39. data/spec/dummy/app/models/user.rb +2 -0
  40. data/spec/dummy/app/policies/application_policy.rb +49 -0
  41. data/spec/dummy/app/policies/base_editing_policy.rb +4 -0
  42. data/spec/dummy/app/policies/user_policy.rb +23 -0
  43. data/spec/dummy/bin/rails +1 -1
  44. data/spec/dummy/bin/setup +20 -13
  45. data/spec/dummy/bin/update +31 -0
  46. data/spec/dummy/bin/yarn +11 -0
  47. data/spec/dummy/config/application.rb +15 -17
  48. data/spec/dummy/config/environment.rb +1 -1
  49. data/spec/dummy/config/environments/development.rb +31 -11
  50. data/spec/dummy/config/environments/production.rb +26 -16
  51. data/spec/dummy/config/environments/test.rb +10 -6
  52. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  53. data/spec/dummy/config/initializers/assets.rb +6 -3
  54. data/spec/dummy/config/initializers/content_security_policy.rb +25 -0
  55. data/spec/dummy/config/initializers/cookies_serializer.rb +2 -0
  56. data/spec/dummy/config/initializers/kono_utils.rb +5 -0
  57. data/spec/dummy/config/initializers/new_framework_defaults_5_2.rb +38 -0
  58. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -2
  59. data/spec/dummy/config/locales/en.yml +10 -0
  60. data/spec/dummy/config/routes.rb +3 -52
  61. data/spec/dummy/config/storage.yml +34 -0
  62. data/spec/dummy/db/migrate/20190716093114_create_users.rb +11 -0
  63. data/spec/dummy/db/schema.rb +23 -0
  64. data/spec/dummy/package.json +5 -0
  65. data/spec/dummy/spec/models/user_spec.rb +5 -0
  66. data/spec/dummy/yarn.lock +21 -0
  67. metadata +83 -144
  68. data/app/assets/javascripts/kono_utils/utilities.coffee +0 -481
  69. data/app/assets/stylesheets/kono_utils/utils.css.scss +0 -4
  70. data/app/input/bs_aceeditor_input.rb +0 -53
  71. data/app/input/bs_autocomplete_input.rb +0 -60
  72. data/app/input/bs_datepicker_input.rb +0 -16
  73. data/app/input/bs_datetimepicker_input.rb +0 -80
  74. data/app/input/bs_file_download_input.rb +0 -35
  75. data/app/input/bs_image_input.rb +0 -35
  76. data/app/input/bs_label_with_container_input.rb +0 -22
  77. data/app/input/bs_location_picker_input.rb +0 -95
  78. data/app/input/bs_readonly_input.rb +0 -52
  79. data/app/input/bs_timepicker_input.rb +0 -14
  80. data/app/views/kono_utils/application/_search_panel.html.erb +0 -36
  81. data/app/views/kono_utils/base_editing/_edit.html.erb +0 -3
  82. data/app/views/kono_utils/base_editing/_edit_page_side_title_header.html.erb +0 -3
  83. data/app/views/kono_utils/base_editing/_edit_page_title_header.html.erb +0 -3
  84. data/app/views/kono_utils/base_editing/_form.html.erb +0 -15
  85. data/app/views/kono_utils/base_editing/_index_buttons.html.erb +0 -2
  86. data/app/views/kono_utils/base_editing/_index_page_side_title_header.html.erb +0 -3
  87. data/app/views/kono_utils/base_editing/_index_page_title_header.html.erb +0 -3
  88. data/app/views/kono_utils/base_editing/_index_tfoot.html.erb +0 -0
  89. data/app/views/kono_utils/base_editing/_new.html.erb +0 -3
  90. data/app/views/kono_utils/base_editing/_new_page_side_title_header.html.erb +0 -3
  91. data/app/views/kono_utils/base_editing/_new_page_title_header.html.erb +0 -3
  92. data/app/views/kono_utils/base_editing/_search_form.html.erb +0 -1
  93. data/app/views/kono_utils/base_editing/application/_edit_page_side_title_header.html.erb +0 -1
  94. data/app/views/kono_utils/base_editing/application/_edit_page_title_header.html.erb +0 -1
  95. data/app/views/kono_utils/base_editing/application/_index_page_side_title_header.html.erb +0 -1
  96. data/app/views/kono_utils/base_editing/application/_index_page_title_header.html.erb +0 -1
  97. data/app/views/kono_utils/base_editing/application/_new_page_side_title_header.html.erb +0 -1
  98. data/app/views/kono_utils/base_editing/application/_new_page_title_header.html.erb +0 -1
  99. data/app/views/kono_utils/base_editing/application/edit.html.erb +0 -1
  100. data/app/views/kono_utils/base_editing/application/new.html.erb +0 -1
  101. data/app/views/kono_utils/base_editing/edit.html.erb +0 -1
  102. data/app/views/kono_utils/base_editing/index.html.erb +0 -36
  103. data/app/views/kono_utils/base_editing/new.html.erb +0 -1
  104. data/lib/kono_utils/encoder.rb +0 -47
  105. data/lib/kono_utils/fiscal_code.rb +0 -47
  106. data/lib/kono_utils/params_hash_array.rb +0 -37
  107. data/lib/kono_utils/percentage.rb +0 -60
  108. data/lib/kono_utils/tmp_file.rb +0 -81
  109. data/lib/kono_utils/virtual_model.rb +0 -22
  110. data/lib/tasks/kono_utils_tasks.rake +0 -4
  111. data/spec/lib/kono_utils/fiscal_code_spec.rb +0 -56
  112. data/vendor/assets/javascripts/EventEmitter.js +0 -473
@@ -1,4 +0,0 @@
1
- @import 'bootstrap-sprockets';
2
- @import 'bootstrap';
3
- @import 'bootstrap-datetimepicker';
4
- @import 'kono_styles';
@@ -1,53 +0,0 @@
1
- class BsAceeditorInput < Formtastic::Inputs::StringInput
2
- include FormtasticBootstrap::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Collections
4
- include ActionView::Helpers::TagHelper
5
- include ActionView::Context
6
- include FontAwesome::Rails::IconHelper
7
- include ActionView::Helpers::JavaScriptHelper
8
-
9
-
10
- ##
11
- # Nel caso di collection si può definire con
12
- # :show_hidden => [true] per stampare il campo hidden o meno con il vero valore
13
- # :display_field come options quale campo usare per stampare
14
- #
15
- def to_html
16
-
17
- theme = options[:theme] || 'twilight'
18
- mode = options[:mode] || 'ruby'
19
- height = options[:height] || '300px'
20
-
21
- bootstrap_wrapping do
22
- content_tag(:div) do
23
-
24
- id = SecureRandom.hex
25
-
26
- buff = ActiveSupport::SafeBuffer.new
27
-
28
- buff<< content_tag(:div, :class => "container_editor clearfix", :style => 'width:100%;') do
29
- content_tag(:div, object.send(method), id: id, style: "height:#{height};width:100px;")
30
- end
31
-
32
- id_hidden = SecureRandom.hex
33
- buff<< builder.hidden_field(method, form_control_input_html_options.merge(:id => id_hidden))
34
-
35
- buff<< content_tag(:script, :type => "text/javascript") do
36
- raw "var editor = ace.edit('#{id}');\n
37
- editor.setTheme('ace/theme/#{theme}');\n
38
- editor.getSession().setMode('ace/mode/#{mode}');\n
39
- $('##{id}').width($('##{id}').closest('.container_editor').width());\n
40
- editor.resize();\n
41
- editor.getSession().on('change', function(e) {
42
- $('##{id_hidden}').val(editor.getValue());
43
- });
44
- "
45
- end
46
-
47
- buff
48
-
49
- end
50
- end
51
- end
52
-
53
- end
@@ -1,60 +0,0 @@
1
- ##
2
- # <%= f.input :city,
3
- # :as => :bs_autocomplete,
4
- # :url => tikal_core.autocomplete_city_nome_autoclts_cities,
5
- # :display_field => :nome,
6
- # :value_field => :city_id %>
7
- #
8
- #
9
- # -- display_field
10
- # serve per indicare quale campo utilizzare come metodo per estrapolare i dati dal record associato
11
- # può anche essere una proc a cui passiamo l'oggetto
12
- # -- value_field
13
- # indica quale campo utilizzare per estrapolare il dato del valore del record associato
14
- # e quale nome dare al campo per creare una form corretta
15
- #
16
- #se è presente il Formtastic::Inputs::AutocompleteInput
17
- begin
18
- class BsAutocompleteInput < Formtastic::Inputs::AutocompleteInput
19
-
20
- include FormtasticBootstrap::Inputs::Base
21
-
22
- def input_html_options
23
- id = super[:id]
24
-
25
- opts = {class: "form-control", id: "autocomplete_#{id}"}
26
-
27
- ##Setto valore utilizzando le impostazioni di identificativo del campo per autocomplete :display_field
28
- unless options[:display_field].nil?
29
- opts[:value] = object.send(method).try(options[:display_field])
30
- end
31
-
32
- super.merge(opts)
33
- end
34
-
35
- def to_html
36
- bootstrap_wrapping do
37
- buffer = ActiveSupport::SafeBuffer.new
38
-
39
- html_options = input_html_options
40
-
41
- hidden_field = nil
42
- unless options[:value_field].nil?
43
- hidden_id = "hidden_#{html_options[:id]}_#{SecureRandom.hex}"
44
- html_options[:id_element] = "##{hidden_id}"
45
- hidden_field = builder.hidden_field(options[:value_field], id: hidden_id)
46
- end
47
-
48
- buffer << builder.autocomplete_field(method, options.delete(:url), html_options)
49
-
50
- buffer << hidden_field unless hidden_field.nil?
51
-
52
- buffer
53
- end
54
- end
55
- end
56
- rescue Exception => e
57
- if defined?(Rails)
58
- Rails.logger.debug {"Non riesco a caricare questa input BsAutocompleteInput #{__FILE__}"}
59
- end
60
- end
@@ -1,16 +0,0 @@
1
- ##
2
- # Classe per la stampa del DatePicker con bootstrap
3
- #
4
- #
5
- class BsDatepickerInput < BsDatetimepickerInput
6
-
7
-
8
- def default_javascript_options
9
- {
10
- server_format: 'YYYY-MM-DD',
11
- server_match: '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/',
12
- format: 'DD/MM/YYYY'
13
- }
14
- end
15
-
16
- end
@@ -1,80 +0,0 @@
1
- ##
2
- # Classe per la stampa del DatetimePicker con bootstrap
3
- #
4
- # * *Opzioni* :
5
- # - inject_js => True|False|Hash per ozioni js
6
- #
7
- class BsDatetimepickerInput < Formtastic::Inputs::StringInput
8
- include FormtasticBootstrap::Inputs::Base
9
- include ActionView::Helpers::TagHelper
10
- include ActionView::Context
11
- include FontAwesome::Rails::IconHelper
12
- include ActionView::Helpers::JavaScriptHelper
13
- include ActionView::Helpers::OutputSafetyHelper
14
-
15
- ##
16
- # Serve per avere icone differenti nell'interfaccia
17
- def icon
18
- fa_icon(:calendar)
19
- end
20
-
21
- def to_html
22
-
23
- bootstrap_wrapping do
24
- tmp = ActiveSupport::SafeBuffer.new
25
-
26
- tmp<< content_tag(:div, class: 'input-group date tk_date_time_picker', id: picker_container_id) do
27
- builder.text_field(method, form_control_input_html_options)<<
28
- content_tag(:span, icon, class: 'input-group-addon')
29
-
30
- end
31
-
32
- if options[:inject_js]
33
- tmp << javascript_initializations
34
- end
35
- tmp
36
- end
37
- end
38
-
39
- def picker_container_id
40
- if @_container_id.nil?
41
- @_container_id = "date_time_picker_#{form_control_input_html_options[:id]}_#{Random.new_seed}"
42
- end
43
- @_container_id
44
- end
45
-
46
- def javascript_initializations
47
-
48
- opt = options[:inject_js]
49
- unless opt.is_a?(Hash)
50
- opt ={}
51
- end
52
-
53
- opt=default_javascript_options.merge(opt)
54
-
55
- if block_given?
56
- yield opt
57
- else
58
- content_tag(:script, :type => "text/javascript") do
59
- raw "(function(){var data_picker = new Kn.utilities.DateTimePicker({
60
- selector: $('##{picker_container_id}'),
61
- server_format: \"#{opt[:server_format]}\",
62
- server_match: #{opt[:server_match]},
63
- format: \"#{opt[:format]}\"
64
- }) ;
65
- data_picker.initialize() ;
66
- })();
67
- "
68
- end
69
- end
70
- end
71
-
72
- def default_javascript_options
73
- {
74
- server_format: 'YYYY-MM-DD',
75
- server_match: '/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/',
76
- format: 'DD/MM/YYYY HH:mm'
77
- }
78
- end
79
-
80
- end
@@ -1,35 +0,0 @@
1
- class BsFileDownloadInput < Formtastic::Inputs::StringInput
2
- include FormtasticBootstrap::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Collections
4
- include ActionView::Helpers::TagHelper
5
- include ActionView::Context
6
- include ActionView::Helpers::UrlHelper
7
-
8
-
9
- ##
10
- # Passare nelle opzioni la chiave :content con una proc che richiamo per generare il buffer
11
- #
12
- def to_html
13
-
14
- bootstrap_wrapping do
15
- content_tag(:div, class: 'input-group bs_label_with_content') do
16
- content_tag(:div, class: 'row') do
17
- tmp = ActiveSupport::SafeBuffer.new
18
-
19
- tmp << content_tag(:div, class: "col-md-6") do
20
- builder.input method, :label => false
21
- end
22
-
23
- if object.send(method).exists?
24
- tmp << content_tag(:div, class: "col-md-6 col-lg-6") do
25
- link_to I18n.t('formtastic.inputs.bs_file_download.download'), object.send(method).url, class: 'btn btn-default'
26
- end
27
- end
28
-
29
- tmp
30
- end
31
- end
32
- end
33
- end
34
-
35
- end
@@ -1,35 +0,0 @@
1
- class BsImageInput < Formtastic::Inputs::StringInput
2
- include FormtasticBootstrap::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Collections
4
- include ActionView::Helpers::TagHelper
5
- include ActionView::Context
6
- include ActionView::Helpers::AssetTagHelper
7
-
8
-
9
- ##
10
- # Passare nelle opzioni la chiave :content con una proc che richiamo per generare il buffer
11
- #
12
- def to_html
13
-
14
- bootstrap_wrapping do
15
- content_tag(:div, class: 'input-group bs_label_with_content') do
16
- content_tag(:div, class: 'row') do
17
- tmp = ActiveSupport::SafeBuffer.new
18
-
19
- tmp << content_tag(:div, class: "col-md-6 col-lg-6") do
20
- builder.input method, :label => false
21
- end
22
-
23
- if object.send(method).exists?
24
- tmp << content_tag(:div, class: "col-md-6 col-lg-6") do
25
- image_tag object.send(method).url,class:'img-responsive img-thumbnail',style:'max-height:200px;'
26
- end
27
- end
28
-
29
- tmp
30
- end
31
- end
32
- end
33
- end
34
-
35
- end
@@ -1,22 +0,0 @@
1
- class BsLabelWithContainerInput < Formtastic::Inputs::StringInput
2
- include FormtasticBootstrap::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Collections
4
- include ActionView::Helpers::TagHelper
5
- include ActionView::Context
6
-
7
-
8
- ##
9
- # Passare nelle opzioni la chiave :content con una proc che richiamo per generare il buffer
10
- #
11
- def to_html
12
-
13
- bootstrap_wrapping do
14
- content_tag(:div, class: 'input-group bs_label_with_content') do
15
- buff = ActiveSupport::SafeBuffer.new
16
- buff<< content_tag(:p, options[:content].call, class: 'form-control-static',id:"#{form_control_input_html_options[:id]}_container")
17
- buff
18
- end
19
- end
20
- end
21
-
22
- end
@@ -1,95 +0,0 @@
1
- class BsLocationPickerInput < Formtastic::Inputs::StringInput
2
- include FormtasticBootstrap::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Collections
4
- include ActionView::Helpers::TagHelper
5
- include ActionView::Context
6
- include FontAwesome::Rails::IconHelper
7
- include ActionView::Helpers::JavaScriptHelper
8
-
9
- class ZoomInvalid < StandardError
10
- def initialize(msg="Zoom non valido, deve essere intero")
11
- super
12
- end
13
- end
14
-
15
-
16
- ##
17
- # Stampa Una Mappa di Google Maps, che rende possibile la selezione di un punto sulla mappa
18
- # e di salvarlo nei due campi Lat Lng della form.
19
- #
20
- # Necessario aver aggiunto anche l'asset kono_utils/utilities
21
- # per avere il javascript necessario alla generazione della mappa
22
- #
23
- # Nell'inizializzatore di kono_utils installato con il generatore impostare la chiave di google:
24
- # google_api_key
25
- #
26
- # La mappa ha un contenitore
27
- #
28
- # Options:
29
- # - default_center -> Array con [lat,lng] nel caso non siano impostati i valori iniziali
30
- # - height -> [300px] Altezza da mettere nello stile della canvas di google maps
31
- # - fields -> Array[:lat,:lng] campi che identificano la Latitudine e Longitudine
32
- # nel record
33
- # - zoom_level -> [5] Integer livello zoom della mappa, se passo una Proc viene elaborata
34
- # passando il record, deve tornare un Integer
35
- #
36
- def to_html
37
-
38
- default_center = options[:default_center] || [42.90887521920127, 12.303765624999983]
39
- center = default_center
40
-
41
- height = options[:height] || '300px'
42
- fields = options[:fields] || [:lat, :lng]
43
- zoom_level = options[:zoom_level] || 5
44
-
45
- if zoom_level.is_a?(Proc)
46
- zoom_level = zoom_level.call(object)
47
- end
48
-
49
- raise ZoomInvalid unless zoom_level.is_a?(Integer)
50
-
51
-
52
- bootstrap_wrapping do
53
- content_tag(:div) do
54
-
55
- id = SecureRandom.hex
56
-
57
- callback_name = "initMap#{id}"
58
-
59
- buff = ActiveSupport::SafeBuffer.new
60
-
61
- buff<< content_tag(:div, :class => "container_google_maps clearfix", :style => 'width:100%;') do
62
- content_tag(:div, nil, id: id, style: "height:#{height}")
63
- end
64
-
65
- id_hidden_lat = SecureRandom.hex
66
- buff<< builder.hidden_field(fields[0], form_control_input_html_options.merge(:id => id_hidden_lat))
67
- id_hidden_lng = SecureRandom.hex
68
- buff<< builder.hidden_field(fields[1], form_control_input_html_options.merge(:id => id_hidden_lng))
69
-
70
- unless object.send(fields[0]).blank? or object.send(fields[1]).blank?
71
- center = [object.send(fields[0]), object.send(fields[1])]
72
- end
73
-
74
- buff<< content_tag(:script, :type => "text/javascript") do
75
- raw "function #{callback_name}(){
76
- $('##{id}').kono_util_location_picker({
77
- center:{lat:#{center[0]},lng:#{center[1]}},
78
- zoom_level:#{zoom_level},
79
- selector_field_lat:'##{id_hidden_lat}',
80
- selector_field_lng:'##{id_hidden_lng}'
81
- });
82
- }"
83
- end
84
-
85
- buff<< content_tag(:script, nil,
86
- src: "https://maps.googleapis.com/maps/api/js?key=#{KonoUtils.configuration.google_api_key}&callback=#{callback_name}",
87
- :type => "text/javascript", async: '', defer: '')
88
-
89
- buff
90
-
91
- end
92
- end
93
- end
94
-
95
- end
@@ -1,52 +0,0 @@
1
- class BsReadonlyInput < Formtastic::Inputs::StringInput
2
- include FormtasticBootstrap::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Collections
4
- include ActionView::Helpers::TagHelper
5
- include ActionView::Context
6
- include FontAwesome::Rails::IconHelper
7
- include ActionView::Helpers::JavaScriptHelper
8
-
9
-
10
- ##
11
- # Nel caso di collection si può definire con
12
- # :show_hidden => [true] per stampare il campo hidden o meno con il vero valore
13
- # :display_field come options quale campo usare per stampare
14
- # :value_renderer => Proc da aggiungere, a cui passiamo
15
- # campo, valore , se passato nulla viene
16
- # renderizzato standard un p contenente il valore
17
- #
18
- def to_html
19
-
20
- field_name = method
21
- show_value = object.send(method)
22
- if show_value.is_a?(ActiveRecord::Base) and !options[:display_field].blank?
23
- #vuol dire che siamo in una collection
24
- show_value = show_value.send(options[:display_field])
25
- field_name = input_name
26
- end
27
-
28
- if !options[:value_renderer].is_a?(Proc)
29
- options[:value_renderer]=Proc.new { |field, value|
30
- buff = ActiveSupport::SafeBuffer.new
31
- buff<<content_tag(:p, value, class: 'form-control-static', id: "#{field.form_control_input_html_options[:id]}_container")
32
- buff
33
- }
34
- end
35
-
36
-
37
- bootstrap_wrapping do
38
- content_tag(:div, class: 'input-group date') do
39
-
40
- buff = ActiveSupport::SafeBuffer.new
41
-
42
- buff<< options[:value_renderer].call(self, show_value)
43
-
44
- buff<< builder.hidden_field(field_name, form_control_input_html_options)
45
-
46
- buff
47
-
48
- end
49
- end
50
- end
51
-
52
- end