formtastic 3.0.0 → 5.0.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 (175) hide show
  1. checksums.yaml +5 -13
  2. data/.gitattributes +1 -0
  3. data/.github/workflows/test.yml +61 -0
  4. data/.gitignore +3 -2
  5. data/CHANGELOG.md +61 -0
  6. data/Gemfile.lock +140 -0
  7. data/MIT-LICENSE +1 -1
  8. data/{README.textile → README.md} +191 -168
  9. data/RELEASE_PROCESS +3 -1
  10. data/Rakefile +24 -8
  11. data/app/assets/stylesheets/formtastic.css +1 -1
  12. data/bin/appraisal +8 -0
  13. data/formtastic.gemspec +13 -17
  14. data/gemfiles/rails_6.0/Gemfile +5 -0
  15. data/gemfiles/rails_6.1/Gemfile +5 -0
  16. data/gemfiles/rails_7.0/Gemfile +5 -0
  17. data/gemfiles/rails_7.1/Gemfile +5 -0
  18. data/gemfiles/rails_edge/Gemfile +13 -0
  19. data/lib/formtastic/action_class_finder.rb +19 -0
  20. data/lib/formtastic/actions/base.rb +1 -0
  21. data/lib/formtastic/actions/button_action.rb +56 -53
  22. data/lib/formtastic/actions/buttonish.rb +1 -0
  23. data/lib/formtastic/actions/input_action.rb +60 -57
  24. data/lib/formtastic/actions/link_action.rb +69 -67
  25. data/lib/formtastic/actions.rb +7 -3
  26. data/lib/formtastic/deprecation.rb +6 -0
  27. data/lib/formtastic/engine.rb +4 -1
  28. data/lib/formtastic/form_builder.rb +32 -25
  29. data/lib/formtastic/helpers/action_helper.rb +22 -31
  30. data/lib/formtastic/helpers/actions_helper.rb +1 -0
  31. data/lib/formtastic/helpers/enum.rb +14 -0
  32. data/lib/formtastic/helpers/errors_helper.rb +3 -2
  33. data/lib/formtastic/helpers/fieldset_wrapper.rb +16 -11
  34. data/lib/formtastic/helpers/file_column_detection.rb +1 -0
  35. data/lib/formtastic/helpers/form_helper.rb +4 -3
  36. data/lib/formtastic/helpers/input_helper.rb +59 -80
  37. data/lib/formtastic/helpers/inputs_helper.rb +33 -27
  38. data/lib/formtastic/helpers/reflection.rb +5 -4
  39. data/lib/formtastic/helpers.rb +2 -2
  40. data/lib/formtastic/html_attributes.rb +13 -1
  41. data/lib/formtastic/i18n.rb +2 -1
  42. data/lib/formtastic/input_class_finder.rb +19 -0
  43. data/lib/formtastic/inputs/base/associations.rb +1 -0
  44. data/lib/formtastic/inputs/base/choices.rb +4 -3
  45. data/lib/formtastic/inputs/base/collections.rb +47 -11
  46. data/lib/formtastic/inputs/base/database.rb +8 -5
  47. data/lib/formtastic/inputs/base/datetime_pickerish.rb +1 -0
  48. data/lib/formtastic/inputs/base/errors.rb +7 -6
  49. data/lib/formtastic/inputs/base/fileish.rb +1 -0
  50. data/lib/formtastic/inputs/base/hints.rb +2 -1
  51. data/lib/formtastic/inputs/base/html.rb +12 -10
  52. data/lib/formtastic/inputs/base/labelling.rb +3 -2
  53. data/lib/formtastic/inputs/base/naming.rb +5 -4
  54. data/lib/formtastic/inputs/base/numeric.rb +1 -0
  55. data/lib/formtastic/inputs/base/options.rb +3 -3
  56. data/lib/formtastic/inputs/base/placeholder.rb +1 -0
  57. data/lib/formtastic/inputs/base/stringish.rb +1 -0
  58. data/lib/formtastic/inputs/base/timeish.rb +9 -4
  59. data/lib/formtastic/inputs/base/validations.rb +39 -12
  60. data/lib/formtastic/inputs/base/wrapping.rb +2 -3
  61. data/lib/formtastic/inputs/base.rb +17 -12
  62. data/lib/formtastic/inputs/boolean_input.rb +2 -1
  63. data/lib/formtastic/inputs/check_boxes_input.rb +16 -24
  64. data/lib/formtastic/inputs/color_input.rb +1 -1
  65. data/lib/formtastic/inputs/country_input.rb +4 -1
  66. data/lib/formtastic/inputs/datalist_input.rb +42 -0
  67. data/lib/formtastic/inputs/date_picker_input.rb +1 -0
  68. data/lib/formtastic/inputs/date_select_input.rb +1 -0
  69. data/lib/formtastic/inputs/datetime_picker_input.rb +1 -0
  70. data/lib/formtastic/inputs/datetime_select_input.rb +1 -0
  71. data/lib/formtastic/inputs/email_input.rb +1 -0
  72. data/lib/formtastic/inputs/file_input.rb +3 -2
  73. data/lib/formtastic/inputs/hidden_input.rb +3 -2
  74. data/lib/formtastic/inputs/number_input.rb +1 -0
  75. data/lib/formtastic/inputs/password_input.rb +1 -0
  76. data/lib/formtastic/inputs/phone_input.rb +1 -0
  77. data/lib/formtastic/inputs/radio_input.rb +26 -21
  78. data/lib/formtastic/inputs/range_input.rb +1 -0
  79. data/lib/formtastic/inputs/search_input.rb +1 -0
  80. data/lib/formtastic/inputs/select_input.rb +32 -10
  81. data/lib/formtastic/inputs/string_input.rb +1 -0
  82. data/lib/formtastic/inputs/text_input.rb +1 -0
  83. data/lib/formtastic/inputs/time_picker_input.rb +1 -0
  84. data/lib/formtastic/inputs/time_select_input.rb +1 -0
  85. data/lib/formtastic/inputs/time_zone_input.rb +17 -6
  86. data/lib/formtastic/inputs/url_input.rb +1 -0
  87. data/lib/formtastic/inputs.rb +33 -28
  88. data/lib/formtastic/localized_string.rb +2 -1
  89. data/lib/formtastic/localizer.rb +23 -24
  90. data/lib/formtastic/namespaced_class_finder.rb +98 -0
  91. data/lib/formtastic/version.rb +2 -1
  92. data/lib/formtastic.rb +19 -14
  93. data/lib/generators/formtastic/form/form_generator.rb +8 -2
  94. data/lib/generators/formtastic/input/input_generator.rb +47 -0
  95. data/lib/generators/formtastic/install/install_generator.rb +2 -0
  96. data/lib/generators/templates/formtastic.rb +29 -7
  97. data/lib/generators/templates/input.rb +19 -0
  98. data/sample/basic_inputs.html +1 -1
  99. data/script/integration-template.rb +73 -0
  100. data/script/integration.sh +19 -0
  101. data/spec/action_class_finder_spec.rb +13 -0
  102. data/spec/actions/button_action_spec.rb +21 -20
  103. data/spec/actions/generic_action_spec.rb +134 -133
  104. data/spec/actions/input_action_spec.rb +20 -19
  105. data/spec/actions/link_action_spec.rb +30 -29
  106. data/spec/builder/custom_builder_spec.rb +39 -22
  107. data/spec/builder/error_proc_spec.rb +6 -5
  108. data/spec/builder/semantic_fields_for_spec.rb +46 -45
  109. data/spec/fast_spec_helper.rb +13 -0
  110. data/spec/generators/formtastic/form/form_generator_spec.rb +33 -32
  111. data/spec/generators/formtastic/input/input_generator_spec.rb +125 -0
  112. data/spec/generators/formtastic/install/install_generator_spec.rb +10 -9
  113. data/spec/helpers/action_helper_spec.rb +70 -97
  114. data/spec/helpers/actions_helper_spec.rb +43 -42
  115. data/spec/helpers/form_helper_spec.rb +56 -39
  116. data/spec/helpers/input_helper_spec.rb +314 -255
  117. data/spec/helpers/inputs_helper_spec.rb +217 -202
  118. data/spec/helpers/reflection_helper_spec.rb +7 -6
  119. data/spec/helpers/semantic_errors_helper_spec.rb +26 -25
  120. data/spec/i18n_spec.rb +30 -29
  121. data/spec/input_class_finder_spec.rb +11 -0
  122. data/spec/inputs/base/collections_spec.rb +78 -0
  123. data/spec/inputs/base/validations_spec.rb +481 -0
  124. data/spec/inputs/boolean_input_spec.rb +73 -72
  125. data/spec/inputs/check_boxes_input_spec.rb +174 -123
  126. data/spec/inputs/color_input_spec.rb +53 -64
  127. data/spec/inputs/country_input_spec.rb +23 -22
  128. data/spec/inputs/custom_input_spec.rb +3 -6
  129. data/spec/inputs/datalist_input_spec.rb +62 -0
  130. data/spec/inputs/date_picker_input_spec.rb +114 -113
  131. data/spec/inputs/date_select_input_spec.rb +76 -61
  132. data/spec/inputs/datetime_picker_input_spec.rb +123 -122
  133. data/spec/inputs/datetime_select_input_spec.rb +85 -68
  134. data/spec/inputs/email_input_spec.rb +17 -16
  135. data/spec/inputs/file_input_spec.rb +18 -17
  136. data/spec/inputs/hidden_input_spec.rb +32 -31
  137. data/spec/inputs/include_blank_spec.rb +10 -9
  138. data/spec/inputs/label_spec.rb +36 -31
  139. data/spec/inputs/number_input_spec.rb +212 -211
  140. data/spec/inputs/password_input_spec.rb +17 -16
  141. data/spec/inputs/phone_input_spec.rb +17 -16
  142. data/spec/inputs/placeholder_spec.rb +18 -17
  143. data/spec/inputs/radio_input_spec.rb +92 -65
  144. data/spec/inputs/range_input_spec.rb +136 -135
  145. data/spec/inputs/readonly_spec.rb +51 -0
  146. data/spec/inputs/search_input_spec.rb +16 -15
  147. data/spec/inputs/select_input_spec.rb +209 -102
  148. data/spec/inputs/string_input_spec.rb +51 -50
  149. data/spec/inputs/text_input_spec.rb +34 -33
  150. data/spec/inputs/time_picker_input_spec.rb +115 -114
  151. data/spec/inputs/time_select_input_spec.rb +84 -70
  152. data/spec/inputs/time_zone_input_spec.rb +58 -31
  153. data/spec/inputs/url_input_spec.rb +17 -16
  154. data/spec/inputs/with_options_spec.rb +9 -8
  155. data/spec/localizer_spec.rb +18 -17
  156. data/spec/namespaced_class_finder_spec.rb +91 -0
  157. data/spec/schema.rb +22 -0
  158. data/spec/spec_helper.rb +180 -249
  159. data/spec/support/custom_macros.rb +128 -98
  160. data/spec/support/deprecation.rb +2 -1
  161. data/spec/support/shared_examples.rb +13 -0
  162. data/spec/support/specialized_class_finder_shared_example.rb +28 -0
  163. data/spec/support/test_environment.rb +25 -10
  164. metadata +95 -136
  165. data/.travis.yml +0 -28
  166. data/Appraisals +0 -25
  167. data/CHANGELOG +0 -27
  168. data/gemfiles/rails_3.2.gemfile +0 -7
  169. data/gemfiles/rails_4.0.4.gemfile +0 -7
  170. data/gemfiles/rails_4.1.gemfile +0 -7
  171. data/gemfiles/rails_4.gemfile +0 -7
  172. data/gemfiles/rails_edge.gemfile +0 -10
  173. data/lib/formtastic/util.rb +0 -53
  174. data/spec/support/deferred_garbage_collection.rb +0 -21
  175. data/spec/util_spec.rb +0 -52
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  # Set the default text field size when input is a string. Default is nil.
4
5
  # Formtastic::FormBuilder.default_text_field_size = 50
@@ -17,15 +18,15 @@
17
18
  # Defaults to true.
18
19
  # Formtastic::FormBuilder.include_blank_for_select_by_default = true
19
20
 
20
- # Set the string that will be appended to the labels/fieldsets which are required
21
+ # Set the string that will be appended to the labels/fieldsets which are required.
21
22
  # It accepts string or procs and the default is a localized version of
22
23
  # '<abbr title="required">*</abbr>'. In other words, if you configure formtastic.required
23
24
  # in your locale, it will replace the abbr title properly. But if you don't want to use
24
- # abbr tag, you can simply give a string as below
25
+ # abbr tag, you can simply give a string as below.
25
26
  # Formtastic::FormBuilder.required_string = "(required)"
26
27
 
27
- # Set the string that will be appended to the labels/fieldsets which are optional
28
- # Defaults to an empty string ("") and also accepts procs (see required_string above)
28
+ # Set the string that will be appended to the labels/fieldsets which are optional.
29
+ # Defaults to an empty string ("") and also accepts procs (see required_string above).
29
30
  # Formtastic::FormBuilder.optional_string = "(optional)"
30
31
 
31
32
  # Set the way inline errors will be displayed.
@@ -33,7 +34,7 @@
33
34
  # Formtastic::FormBuilder.inline_errors = :sentence
34
35
  # Formtastic uses the following classes as default for hints, inline_errors and error list
35
36
 
36
- # If you override the class here, please ensure to override it in your stylesheets as well
37
+ # If you override the class here, please ensure to override it in your stylesheets as well.
37
38
  # Formtastic::FormBuilder.default_hint_class = "inline-hints"
38
39
  # Formtastic::FormBuilder.default_inline_error_class = "inline-errors"
39
40
  # Formtastic::FormBuilder.default_error_list_class = "errors"
@@ -70,7 +71,7 @@
70
71
  # can change it to any class you want.
71
72
  # Formtastic::Helpers::FormHelper.default_form_class = 'formtastic'
72
73
 
73
- # Formtastic will infer a class name from the model, array, string ot symbol you pass to the
74
+ # Formtastic will infer a class name from the model, array, string or symbol you pass to the
74
75
  # form builder. You can customize the way that class is presented by overriding
75
76
  # this proc.
76
77
  # Formtastic::Helpers::FormHelper.default_form_model_class_proc = proc { |model_class_name| model_class_name }
@@ -85,6 +86,27 @@
85
86
  # Formtastic::FormBuilder.use_required_attribute = false
86
87
 
87
88
  # You can opt-in to new HTML5 browser validations (for things like email and url inputs) by setting
88
- # this to true. Doing so will add a `novalidate` attribute to the `<form>` tag.
89
+ # this to true. Doing so will omit the `novalidate` attribute from the `<form>` tag.
89
90
  # See http://diveintohtml5.org/forms.html#validation for more info.
90
91
  # Formtastic::FormBuilder.perform_browser_validations = true
92
+
93
+ # By creating custom input class finder, you can change how input classes are looked up.
94
+ # For example you can make it to search for TextInputFilter instead of TextInput.
95
+ # See https://github.com/formtastic/formtastic/wiki/Custom-Class-Finders
96
+ # Formtastic::FormBuilder.input_class_finder = Formtastic::InputClassFinder
97
+
98
+ # Define custom namespaces in which to look up your Input classes. Default is
99
+ # to look up in the global scope and in Formtastic::Inputs.
100
+ # Formtastic::FormBuilder.input_namespaces = [ ::Object, ::MyInputsModule, ::Formtastic::Inputs ]
101
+
102
+ # By creating custom action class finder, you can change how action classes are looked up.
103
+ # For example you can make it to search for MyButtonAction instead of ButtonAction.
104
+ # See https://github.com/formtastic/formtastic/wiki/Custom-Class-Finders
105
+ # Formtastic::FormBuilder.action_class_finder = Formtastic::ActionClassFinder
106
+
107
+ # Define custom namespaces in which to look up your Action classes. Default is
108
+ # to look up in the global scope and in Formtastic::Actions.
109
+ # Formtastic::FormBuilder.action_namespaces = [ ::Object, ::MyActionsModule, ::Formtastic::Actions ]
110
+
111
+ # Which columns to skip when automatically rendering a form without any fields specified.
112
+ # Formtastic::FormBuilder.skipped_columns = [:created_at, :updated_at, :created_on, :updated_on, :lock_version, :version]
@@ -0,0 +1,19 @@
1
+ class <%= name.camelize %>Input <%= @extension_sentence %>
2
+ <%- if !options[:extend] -%>
3
+ include Formtastic::Inputs::Base
4
+ <%- end -%>
5
+
6
+ <%- if !options[:extend] || (options[:extend] == "extend") -%>
7
+ def to_html
8
+ # Add your custom input definition here.
9
+ <%- if options[:extend] == "extend" -%>
10
+ super
11
+ <%- end -%>
12
+ end
13
+
14
+ <%- else -%>
15
+ def input_html_options
16
+ # Add your custom input extension here.
17
+ end
18
+ <%- end -%>
19
+ end
@@ -36,7 +36,7 @@
36
36
  <li class="input url stringish optional" id="gem_url_input">
37
37
  <label class="label" for="gem_url">URL</label>
38
38
  <input id="gem_url" name="gem[url]" type="url">
39
- <p class="inline-hints">Example: https://github.com/justinfrench/formtastic</p>
39
+ <p class="inline-hints">Example: https://github.com/formtastic/formtastic</p>
40
40
  </li>
41
41
 
42
42
  <li class="input password stringish required" id="gem_password_input">
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+ gem 'formtastic', path: '..'
3
+ gem 'bcrypt', '~> 3.1.7'
4
+ gem 'rails-dom-testing', group: :test
5
+ gem 'rexml', '~> 3.2' # to compensate for missing dependency in selenium-webdriver
6
+
7
+ # to speed up bundle install, reuse the bundle path
8
+ def bundle_path
9
+ File.expand_path ENV.fetch('BUNDLE_PATH', 'vendor/bundle')
10
+ end
11
+
12
+ if Rails.version >= '6.2'
13
+ gsub_file 'Gemfile', /gem 'rails'.*/, "gem 'rails', '~> #{Rails.version}', github: 'rails/rails'"
14
+ elsif Rails.version >= '6.1'
15
+ gsub_file 'Gemfile', /gem 'rails'.*/, "gem 'rails', '~> #{Rails.version}', github: 'rails/rails', branch: '6-1-stable'"
16
+ elsif Rails.version >= '6.0'
17
+ gsub_file 'Gemfile', /gem 'rails'.*/, "gem 'rails', '~> #{Rails.version}', github: 'rails/rails', branch: '6-0-stable'"
18
+ end
19
+
20
+ ### Ensure Dummy App's Ruby version matches the current environments Ruby Version
21
+ ruby_version = "ruby '#{RUBY_VERSION}'"
22
+ gsub_file 'Gemfile', /ruby '\d+.\d+.\d+'/, ruby_version
23
+
24
+ if bundle_install?
25
+ def run_bundle
26
+ previous_bundle_path = bundle_path
27
+
28
+ require "bundler"
29
+ Bundler.with_clean_env do
30
+ system("bundle install --jobs=3 --retry=3 --path=#{previous_bundle_path}")
31
+ end
32
+ end
33
+ end
34
+
35
+ in_root do
36
+ ENV['BUNDLE_GEMFILE'] = File.expand_path('Gemfile')
37
+ end
38
+
39
+ formtastic = -> do
40
+ generate(:scaffold, 'user name:string password:digest')
41
+ generate('formtastic:install')
42
+ generate('formtastic:form', 'user name password --force')
43
+
44
+ rails_command('db:migrate')
45
+
46
+ in_root do
47
+ inject_into_class 'app/models/user.rb', 'User', " has_secure_password\n"
48
+ inject_into_file 'app/assets/stylesheets/application.css', " *= require formtastic\n", before: ' *= require_self'
49
+ inject_into_class 'test/controllers/users_controller_test.rb', 'UsersControllerTest', <<-RUBY
50
+
51
+ test "should show form" do
52
+ get edit_user_path(@user)
53
+
54
+ assert_select 'form' do
55
+ assert_select 'li.input.string' do
56
+ assert_select 'input#user_name[type=text]'
57
+ end
58
+ assert_select 'li.input.password' do
59
+ assert_select 'input#user_password[type=password]'
60
+ end
61
+
62
+ assert_select 'fieldset.actions' do
63
+ assert_select 'li.action.input_action' do
64
+ assert_select 'input[type=submit]'
65
+ end
66
+ end
67
+ end
68
+ end # test "should show form"
69
+ RUBY
70
+ end
71
+ end
72
+
73
+ after_bundle(&formtastic)
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env sh
2
+
3
+ set -e
4
+ set -o verbose
5
+
6
+ test_app=dummy
7
+
8
+ rm -rf ${test_app}
9
+
10
+ bundle exec rails new ${test_app} \
11
+ --template=$(dirname "$0")/integration-template.rb \
12
+ --skip-bootsnap \
13
+ --skip-javascript \
14
+ --skip-spring \
15
+ --skip-turbolinks
16
+
17
+ cd ${test_app} && export BUNDLE_GEMFILE=Gemfile
18
+
19
+ bundle exec rake test
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'spec_helper'
4
+ require 'formtastic/action_class_finder'
5
+
6
+ RSpec.describe Formtastic::ActionClassFinder do
7
+ include FormtasticSpecHelper
8
+
9
+ it_behaves_like 'Specialized Class Finder' do
10
+ let(:default) { Formtastic::Actions }
11
+ let(:namespaces_setting) { :action_namespaces }
12
+ end
13
+ end
@@ -1,63 +1,64 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'spec_helper'
3
4
 
4
- describe 'ButtonAction', 'when submitting' do
5
+ RSpec.describe 'ButtonAction', 'when submitting' do
5
6
 
6
7
  include FormtasticSpecHelper
7
8
 
8
9
  before do
9
- @output_buffer = ''
10
+ @output_buffer = ActionView::OutputBuffer.new ''
10
11
  mock_everything
11
-
12
+
12
13
  concat(semantic_form_for(@new_post) do |builder|
13
14
  concat(builder.action(:submit, :as => :button))
14
15
  end)
15
16
  end
16
-
17
+
17
18
  it 'should render a submit type of button' do
18
- output_buffer.should have_tag('li.action.button_action button[@type="submit"]')
19
+ expect(output_buffer.to_str).to have_tag('li.action.button_action button[@type="submit"]')
19
20
  end
20
21
 
21
22
  end
22
23
 
23
- describe 'ButtonAction', 'when resetting' do
24
+ RSpec.describe 'ButtonAction', 'when resetting' do
24
25
 
25
26
  include FormtasticSpecHelper
26
-
27
+
27
28
  before do
28
- @output_buffer = ''
29
+ @output_buffer = ActionView::OutputBuffer.new ''
29
30
  mock_everything
30
-
31
+
31
32
  concat(semantic_form_for(@new_post) do |builder|
32
33
  concat(builder.action(:reset, :as => :button))
33
34
  end)
34
35
  end
35
-
36
+
36
37
  it 'should render a reset type of button' do
37
- output_buffer.should have_tag('li.action.button_action button[@type="reset"]', :text => "Reset Post")
38
+ expect(output_buffer.to_str).to have_tag('li.action.button_action button[@type="reset"]', :text => "Reset Post")
38
39
  end
39
40
 
40
41
  it 'should not render a value attribute' do
41
- output_buffer.should_not have_tag('li.action.button_action button[@value]')
42
+ expect(output_buffer.to_str).not_to have_tag('li.action.button_action button[@value]')
42
43
  end
43
-
44
+
44
45
  end
45
46
 
46
- describe 'InputAction', 'when cancelling' do
47
+ RSpec.describe 'InputAction', 'when cancelling' do
47
48
 
48
49
  include FormtasticSpecHelper
49
-
50
+
50
51
  before do
51
- @output_buffer = ''
52
+ @output_buffer = ActionView::OutputBuffer.new ''
52
53
  mock_everything
53
54
  end
54
-
55
+
55
56
  it 'should raise an error' do
56
- lambda {
57
+ expect {
57
58
  concat(semantic_form_for(@new_post) do |builder|
58
59
  concat(builder.action(:cancel, :as => :button))
59
60
  end)
60
- }.should raise_error(Formtastic::UnsupportedMethodForAction)
61
+ }.to raise_error(Formtastic::UnsupportedMethodForAction)
61
62
  end
62
-
63
+
63
64
  end