devise 1.5.4 → 2.0.0.rc

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

Potentially problematic release.


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

Files changed (58) hide show
  1. data/.gitignore +0 -2
  2. data/CHANGELOG.rdoc +18 -7
  3. data/Gemfile.lock +168 -0
  4. data/README.rdoc +2 -0
  5. data/app/controllers/devise/registrations_controller.rb +6 -1
  6. data/app/controllers/devise/unlocks_controller.rb +1 -2
  7. data/app/views/devise/mailer/confirmation_instructions.html.erb +1 -1
  8. data/config/locales/en.yml +1 -0
  9. data/lib/devise.rb +41 -22
  10. data/lib/devise/controllers/internal_helpers.rb +9 -2
  11. data/lib/devise/models/authenticatable.rb +30 -12
  12. data/lib/devise/models/confirmable.rb +73 -18
  13. data/lib/devise/models/database_authenticatable.rb +0 -11
  14. data/lib/devise/models/recoverable.rb +5 -5
  15. data/lib/devise/models/rememberable.rb +5 -20
  16. data/lib/devise/models/timeoutable.rb +1 -3
  17. data/lib/devise/models/token_authenticatable.rb +1 -4
  18. data/lib/devise/models/validatable.rb +1 -1
  19. data/lib/devise/orm/active_record.rb +6 -0
  20. data/lib/devise/param_filter.rb +2 -1
  21. data/lib/devise/rails.rb +31 -0
  22. data/lib/devise/schema.rb +5 -0
  23. data/lib/devise/strategies/authenticatable.rb +12 -8
  24. data/lib/devise/strategies/token_authenticatable.rb +3 -3
  25. data/lib/devise/version.rb +1 -1
  26. data/lib/generators/active_record/devise_generator.rb +40 -2
  27. data/lib/generators/active_record/templates/migration.rb +1 -9
  28. data/lib/generators/active_record/templates/migration_existing.rb +1 -9
  29. data/lib/generators/mongoid/devise_generator.rb +43 -0
  30. data/lib/generators/templates/devise.rb +15 -9
  31. data/test/controllers/internal_helpers_test.rb +4 -2
  32. data/test/devise_test.rb +2 -2
  33. data/test/integration/confirmable_test.rb +55 -3
  34. data/test/integration/http_authenticatable_test.rb +16 -1
  35. data/test/integration/lockable_test.rb +3 -3
  36. data/test/integration/registerable_test.rb +32 -1
  37. data/test/integration/rememberable_test.rb +0 -50
  38. data/test/integration/token_authenticatable_test.rb +2 -2
  39. data/test/integration/trackable_test.rb +1 -1
  40. data/test/mapping_test.rb +2 -3
  41. data/test/models/confirmable_test.rb +86 -8
  42. data/test/models/database_authenticatable_test.rb +6 -6
  43. data/test/models/encryptable_test.rb +1 -1
  44. data/test/models/recoverable_test.rb +0 -27
  45. data/test/models/rememberable_test.rb +41 -160
  46. data/test/models/serializable_test.rb +1 -1
  47. data/test/models_test.rb +7 -7
  48. data/test/rails_app/app/mongoid/admin.rb +22 -1
  49. data/test/rails_app/app/mongoid/user.rb +35 -0
  50. data/test/rails_app/config/initializers/devise.rb +6 -7
  51. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +58 -12
  52. data/test/rails_app/lib/shared_admin.rb +5 -2
  53. data/test/support/assertions.rb +4 -1
  54. data/test/support/integration.rb +3 -1
  55. data/test/test_helpers_test.rb +2 -2
  56. metadata +21 -39
  57. data/test/models/authenticatable_test.rb +0 -9
  58. data/test/schema_test.rb +0 -33
data/.gitignore CHANGED
@@ -8,5 +8,3 @@ rdoc/*
8
8
  pkg
9
9
  log
10
10
  test/tmp/*
11
- Gemfile.lock
12
-
@@ -1,7 +1,20 @@
1
- == 1.5.4
1
+ == 2.0.0.rc
2
2
 
3
- * bug fix
4
- * Require string conversion for all values
3
+ Notes: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
4
+
5
+ * enhancements
6
+ * Add support for e-mail reconfirmation on change (by github.com/Mandaryn and github.com/heimidal)
7
+ * Redirect users to sign in page after unlock (by github.com/nashby)
8
+
9
+ * deprecation
10
+ * Devise.apply_schema is deprecated
11
+ * Devise migration helpers are deprecated
12
+ * Usage of Devise.remember_across_browsers was deprecated
13
+ * Usage of Devise.confirm_within was deprecated in favor Devise.allow_unconfirmed_access_for
14
+ * Usage of rememberable with remember_token was removed
15
+ * Usage of recoverable without reset_password_sent_at was removed
16
+ * Usage of Devise.case_insensitive_keys equals to false was removed
17
+ * Usage of Devise.stateless_token= is deprecated in favor of appending :token_auth to Devise.skip_session_storage
5
18
 
6
19
  == 1.5.3
7
20
 
@@ -10,13 +23,11 @@
10
23
  * Ensure passing :format => false to devise_for is not permanent
11
24
  * Ensure path checker does not check invalid routes
12
25
 
13
- * warden regression
14
- * using warden 1.2.1 with Devise 1.5.3 introduces a regression for some types of functional tests (see github.com/plataformatec/devise/issues/1928). Can peg warden to 1.2.0 in your Gemfile to fix this.
15
26
  == 1.5.2
16
27
 
17
28
  * enhancements
18
- * Add support for rails 3.1 new mass assignment conventions (by github.com/kirs)
19
- * Add timeout_in method to Timeoutable, it can be overriden in a model (by github.com/lest)
29
+ * Add support for Rails 3.1 new mass assignment conventions (by github.com/kirs)
30
+ * Add timeout_in method to Timeoutable, it can be overridden in a model (by github.com/lest)
20
31
 
21
32
  * bug fix
22
33
  * OmniAuth error message now shows the proper option (:strategy_class instead of :klass)
@@ -0,0 +1,168 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ devise (1.5.2)
5
+ bcrypt-ruby (~> 3.0)
6
+ orm_adapter (~> 0.0.3)
7
+ warden (~> 1.1)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ actionmailer (3.1.3)
13
+ actionpack (= 3.1.3)
14
+ mail (~> 2.3.0)
15
+ actionpack (3.1.3)
16
+ activemodel (= 3.1.3)
17
+ activesupport (= 3.1.3)
18
+ builder (~> 3.0.0)
19
+ erubis (~> 2.7.0)
20
+ i18n (~> 0.6)
21
+ rack (~> 1.3.5)
22
+ rack-cache (~> 1.1)
23
+ rack-mount (~> 0.8.2)
24
+ rack-test (~> 0.6.1)
25
+ sprockets (~> 2.0.3)
26
+ activemodel (3.1.3)
27
+ activesupport (= 3.1.3)
28
+ builder (~> 3.0.0)
29
+ i18n (~> 0.6)
30
+ activerecord (3.1.3)
31
+ activemodel (= 3.1.3)
32
+ activesupport (= 3.1.3)
33
+ arel (~> 2.2.1)
34
+ tzinfo (~> 0.3.29)
35
+ activeresource (3.1.3)
36
+ activemodel (= 3.1.3)
37
+ activesupport (= 3.1.3)
38
+ activesupport (3.1.3)
39
+ multi_json (~> 1.0)
40
+ addressable (2.2.6)
41
+ arel (2.2.1)
42
+ bcrypt-ruby (3.0.1)
43
+ bson (1.5.1)
44
+ bson_ext (1.3.1)
45
+ builder (3.0.0)
46
+ columnize (0.3.5)
47
+ erubis (2.7.0)
48
+ faraday (0.7.5)
49
+ addressable (~> 2.2.6)
50
+ multipart-post (~> 1.1.3)
51
+ rack (>= 1.1.0, < 2)
52
+ hashie (1.2.0)
53
+ hike (1.2.1)
54
+ i18n (0.6.0)
55
+ json (1.6.3)
56
+ linecache (0.46)
57
+ rbx-require-relative (> 0.0.4)
58
+ mail (2.3.0)
59
+ i18n (>= 0.4.0)
60
+ mime-types (~> 1.16)
61
+ treetop (~> 1.4.8)
62
+ metaclass (0.0.1)
63
+ mime-types (1.17.2)
64
+ mocha (0.10.0)
65
+ metaclass (~> 0.0.1)
66
+ mongo (1.3.1)
67
+ bson (>= 1.3.1)
68
+ mongoid (2.3.4)
69
+ activemodel (~> 3.1)
70
+ mongo (~> 1.3)
71
+ tzinfo (~> 0.3.22)
72
+ multi_json (1.0.4)
73
+ multipart-post (1.1.4)
74
+ nokogiri (1.5.0)
75
+ oauth2 (0.5.1)
76
+ faraday (~> 0.7.4)
77
+ multi_json (~> 1.0.3)
78
+ omniauth (1.0.1)
79
+ hashie (~> 1.2)
80
+ rack
81
+ omniauth-facebook (1.0.0)
82
+ omniauth-oauth2 (~> 1.0.0)
83
+ omniauth-oauth2 (1.0.0)
84
+ oauth2 (~> 0.5.0)
85
+ omniauth (~> 1.0)
86
+ omniauth-openid (1.0.1)
87
+ omniauth (~> 1.0)
88
+ rack-openid (~> 1.3.1)
89
+ orm_adapter (0.0.5)
90
+ polyglot (0.3.3)
91
+ rack (1.3.5)
92
+ rack-cache (1.1)
93
+ rack (>= 0.4)
94
+ rack-mount (0.8.3)
95
+ rack (>= 1.0.0)
96
+ rack-openid (1.3.1)
97
+ rack (>= 1.1.0)
98
+ ruby-openid (>= 2.1.8)
99
+ rack-ssl (1.3.2)
100
+ rack
101
+ rack-test (0.6.1)
102
+ rack (>= 1.0)
103
+ rails (3.1.3)
104
+ actionmailer (= 3.1.3)
105
+ actionpack (= 3.1.3)
106
+ activerecord (= 3.1.3)
107
+ activeresource (= 3.1.3)
108
+ activesupport (= 3.1.3)
109
+ bundler (~> 1.0)
110
+ railties (= 3.1.3)
111
+ railties (3.1.3)
112
+ actionpack (= 3.1.3)
113
+ activesupport (= 3.1.3)
114
+ rack-ssl (~> 1.3.2)
115
+ rake (>= 0.8.7)
116
+ rdoc (~> 3.4)
117
+ thor (~> 0.14.6)
118
+ rake (0.9.2.2)
119
+ rbx-require-relative (0.0.5)
120
+ rdoc (3.11)
121
+ json (~> 1.4)
122
+ ruby-debug (0.10.4)
123
+ columnize (>= 0.1)
124
+ ruby-debug-base (~> 0.10.4.0)
125
+ ruby-debug-base (0.10.4)
126
+ linecache (>= 0.3)
127
+ ruby-openid (2.1.8)
128
+ sprockets (2.0.3)
129
+ hike (~> 1.2)
130
+ rack (~> 1.0)
131
+ tilt (~> 1.1, != 1.3.0)
132
+ sqlite3 (1.3.5)
133
+ sqlite3-ruby (1.3.3)
134
+ sqlite3 (>= 1.3.3)
135
+ thor (0.14.6)
136
+ tilt (1.3.3)
137
+ treetop (1.4.10)
138
+ polyglot
139
+ polyglot (>= 0.3.1)
140
+ tzinfo (0.3.31)
141
+ warden (1.1.0)
142
+ rack (>= 1.0)
143
+ webrat (0.7.2)
144
+ nokogiri (>= 1.2.0)
145
+ rack (>= 1.0)
146
+ rack-test (>= 0.5.3)
147
+
148
+ PLATFORMS
149
+ ruby
150
+
151
+ DEPENDENCIES
152
+ activerecord-jdbc-adapter
153
+ activerecord-jdbcsqlite3-adapter
154
+ bson_ext (~> 1.3.0)
155
+ devise!
156
+ jruby-openssl
157
+ mocha
158
+ mongo (~> 1.3.0)
159
+ mongoid (~> 2.0)
160
+ omniauth (~> 1.0.0)
161
+ omniauth-facebook
162
+ omniauth-oauth2 (~> 1.0.0)
163
+ omniauth-openid (~> 1.0.1)
164
+ rails (~> 3.1.0)
165
+ rdoc
166
+ ruby-debug (>= 0.10.3)
167
+ sqlite3-ruby
168
+ webrat (= 0.7.2)
@@ -1,3 +1,5 @@
1
+ *IMPORTANT:* Devise 2.0.0.rc is out. If you are upgrading, please read: https://github.com/plataformatec/devise/wiki/How-To:-Upgrade-to-Devise-2.0
2
+
1
3
  == Devise
2
4
 
3
5
  {<img src="https://secure.travis-ci.org/plataformatec/devise.png" />}[http://travis-ci.org/plataformatec/devise]
@@ -41,7 +41,12 @@ class Devise::RegistrationsController < ApplicationController
41
41
  self.resource = resource_class.to_adapter.get!(send(:"current_#{resource_name}").to_key)
42
42
 
43
43
  if resource.update_with_password(params[resource_name])
44
- set_flash_message :notice, :updated if is_navigational_format?
44
+ if is_navigational_format?
45
+ if resource.respond_to?(:pending_reconfirmation?) && resource.pending_reconfirmation?
46
+ flash_key = :update_needs_confirmation
47
+ end
48
+ set_flash_message :notice, flash_key || :updated
49
+ end
45
50
  sign_in resource_name, resource, :bypass => true
46
51
  respond_with resource, :location => after_update_path_for(resource)
47
52
  else
@@ -25,8 +25,7 @@ class Devise::UnlocksController < ApplicationController
25
25
 
26
26
  if resource.errors.empty?
27
27
  set_flash_message :notice, :unlocked if is_navigational_format?
28
- sign_in(resource_name, resource)
29
- respond_with_navigational(resource){ redirect_to after_sign_in_path_for(resource) }
28
+ respond_with_navigational(resource){ redirect_to new_session_path(resource) }
30
29
  else
31
30
  respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render_with_scope :new }
32
31
  end
@@ -1,5 +1,5 @@
1
1
  <p>Welcome <%= @resource.email %>!</p>
2
2
 
3
- <p>You can confirm your account through the link below:</p>
3
+ <p>You can confirm your account email through the link below:</p>
4
4
 
5
5
  <p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %></p>
@@ -37,6 +37,7 @@ en:
37
37
  signed_up: 'Welcome! You have signed up successfully.'
38
38
  inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.'
39
39
  updated: 'You updated your account successfully.'
40
+ update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address."
40
41
  destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
41
42
  reasons:
42
43
  inactive: 'inactive'
@@ -84,7 +84,7 @@ module Devise
84
84
  # False by default for backwards compatibility.
85
85
  mattr_accessor :case_insensitive_keys
86
86
  @@case_insensitive_keys = false
87
-
87
+
88
88
  # Keys that should have whitespace stripped.
89
89
  # False by default for backwards compatibility.
90
90
  mattr_accessor :strip_whitespace_keys
@@ -120,27 +120,23 @@ module Devise
120
120
  mattr_accessor :remember_for
121
121
  @@remember_for = 2.weeks
122
122
 
123
- # If true, a valid remember token can be re-used between multiple browsers.
124
- mattr_accessor :remember_across_browsers
125
- @@remember_across_browsers = true
126
-
127
123
  # If true, extends the user's remember period when remembered via cookie.
128
124
  mattr_accessor :extend_remember_period
129
125
  @@extend_remember_period = false
130
126
 
131
- # If true, uses salt as remember token and does not create it in the database.
132
- # By default is false for backwards compatibility.
133
- mattr_accessor :use_salt_as_remember_token
134
- @@use_salt_as_remember_token = false
135
-
136
127
  # Time interval you can access your account before confirming your account.
137
- mattr_accessor :confirm_within
138
- @@confirm_within = 0.days
128
+ mattr_accessor :allow_unconfirmed_access_for
129
+ @@allow_unconfirmed_access_for = 0.days
139
130
 
140
- # Defines which key will be used when confirming an account
131
+ # Defines which key will be used when confirming an account.
141
132
  mattr_accessor :confirmation_keys
142
133
  @@confirmation_keys = [ :email ]
143
134
 
135
+ # Defines if email should be reconfirmable.
136
+ # False by default for backwards compatibility.
137
+ mattr_accessor :reconfirmable
138
+ @@reconfirmable = false
139
+
144
140
  # Time interval to timeout the user session without activity.
145
141
  mattr_accessor :timeout_in
146
142
  @@timeout_in = 30.minutes
@@ -153,11 +149,6 @@ module Devise
153
149
  mattr_accessor :encryptor
154
150
  @@encryptor = nil
155
151
 
156
- # Tells if devise should apply the schema in ORMs where devise declaration
157
- # and schema belongs to the same class (as Datamapper and Mongoid).
158
- mattr_accessor :apply_schema
159
- @@apply_schema = true
160
-
161
152
  # Scoped views. Since it relies on fallbacks to render default views, it's
162
153
  # turned off by default.
163
154
  mattr_accessor :scoped_views
@@ -190,6 +181,7 @@ module Devise
190
181
  @@reset_password_keys = [ :email ]
191
182
 
192
183
  # Time interval you can reset your password with a reset password key
184
+ # Nil by default for backwards compatibility.
193
185
  mattr_accessor :reset_password_within
194
186
  @@reset_password_within = nil
195
187
 
@@ -205,9 +197,9 @@ module Devise
205
197
  mattr_accessor :token_authentication_key
206
198
  @@token_authentication_key = :auth_token
207
199
 
208
- # If true, authentication through token does not store user in session
209
- mattr_accessor :stateless_token
210
- @@stateless_token = false
200
+ # Skip session storage for the following strategies
201
+ mattr_accessor :skip_session_storage
202
+ @@skip_session_storage = []
211
203
 
212
204
  # Which formats should be treated as navigational.
213
205
  # We need both :"*/*" and "*/*" to work on different Rails versions.
@@ -222,6 +214,33 @@ module Devise
222
214
  mattr_accessor :sign_out_via
223
215
  @@sign_out_via = :get
224
216
 
217
+ # DEPRECATED CONFIG
218
+
219
+ # If true, uses salt as remember token and does not create it in the database.
220
+ # By default is false for backwards compatibility.
221
+ mattr_accessor :use_salt_as_remember_token
222
+ @@use_salt_as_remember_token = false
223
+
224
+ # Tells if devise should apply the schema in ORMs where devise declaration
225
+ # and schema belongs to the same class (as Datamapper and Mongoid).
226
+ mattr_accessor :apply_schema
227
+ @@apply_schema = true
228
+
229
+ def self.remember_across_browsers=(value)
230
+ warn "\n[DEVISE] Devise.remember_across_browsers is deprecated and has no effect. Please remove it.\n"
231
+ end
232
+
233
+ def self.confirm_within=(value)
234
+ warn "\n[DEVISE] Devise.confirm_within= is deprecated. Please set Devise.allow_unconfirmed_access_for= instead.\n"
235
+ Devise.allow_unconfirmed_access_for = value
236
+ end
237
+
238
+ def self.stateless_token=(value)
239
+ warn "\n[DEVISE] Devise.stateless_token= is deprecated. Please append :token_auth to Devise.skip_session_storage " \
240
+ "instead, for example: Devise.skip_session_storage << :token_auth\n"
241
+ Devise.skip_session_storage << :token_auth
242
+ end
243
+
225
244
  # PRIVATE CONFIGURATION
226
245
 
227
246
  # Store scopes mappings.
@@ -361,7 +380,7 @@ module Devise
361
380
  # initialization.
362
381
  #
363
382
  # Devise.initialize do |config|
364
- # config.confirm_within = 2.days
383
+ # config.allow_unconfirmed_access_for = 2.days
365
384
  #
366
385
  # config.warden do |manager|
367
386
  # # Configure warden to use other strategies, like oauth.
@@ -93,8 +93,15 @@ MESSAGE
93
93
  def require_no_authentication
94
94
  return unless is_navigational_format?
95
95
  no_input = devise_mapping.no_input_strategies
96
- args = no_input.dup.push :scope => resource_name
97
- if no_input.present? && warden.authenticate?(*args)
96
+
97
+ authenticated = if no_input.present?
98
+ args = no_input.dup.push :scope => resource_name
99
+ warden.authenticate?(*args)
100
+ else
101
+ warden.authenticated?(resource_name)
102
+ end
103
+
104
+ if authenticated
98
105
  resource = warden.user(resource_name)
99
106
  flash[:alert] = I18n.t("devise.failure.already_authenticated")
100
107
  redirect_to after_sign_in_path_for(resource)
@@ -25,6 +25,11 @@ module Devise
25
25
  # * +params_authenticatable+: if this model allows authentication through request params. By default true.
26
26
  # It also accepts an array specifying the strategies that should allow params authentication.
27
27
  #
28
+ # * +skip_session_storage+: By default Devise will store the user in session.
29
+ # You can skip storage for http and token auth by appending values to array:
30
+ # :skip_session_storage => [:token_auth] or :skip_session_storage => [:http_auth, :token_auth],
31
+ # by default is set to :skip_session_storage => [:http_auth].
32
+ #
28
33
  # == active_for_authentication?
29
34
  #
30
35
  # After authenticating a user and in each request, Devise checks if your model is active by
@@ -52,6 +57,9 @@ module Devise
52
57
  included do
53
58
  class_attribute :devise_modules, :instance_writer => false
54
59
  self.devise_modules ||= []
60
+
61
+ before_validation :downcase_keys
62
+ before_validation :strip_whitespace
55
63
  end
56
64
 
57
65
  # Check if the current object is valid for authentication. This method and
@@ -79,8 +87,21 @@ module Devise
79
87
  Devise.mailer
80
88
  end
81
89
 
90
+ def headers_for(name)
91
+ {}
92
+ end
93
+
94
+ def downcase_keys
95
+ (self.class.case_insensitive_keys || []).each { |k| self[k].try(:downcase!) }
96
+ end
97
+
98
+ def strip_whitespace
99
+ (self.class.strip_whitespace_keys || []).each { |k| self[k].try(:strip!) }
100
+ end
101
+
82
102
  module ClassMethods
83
- Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys, :case_insensitive_keys, :http_authenticatable, :params_authenticatable)
103
+ Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys,
104
+ :case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage)
84
105
 
85
106
  def serialize_into_session(record)
86
107
  [record.to_key, record.authenticatable_salt]
@@ -106,20 +127,17 @@ module Devise
106
127
  # namedscope to filter records while authenticating.
107
128
  # Example:
108
129
  #
109
- # def self.find_for_authentication(tainted_conditions)
110
- # find_first_by_auth_conditions(tainted_conditions, active: true)
130
+ # def self.find_for_authentication(conditions={})
131
+ # conditions[:active] = true
132
+ # super
111
133
  # end
112
134
  #
113
- # Finally, notice that Devise also queries for users in other scenarios
114
- # besides authentication, for example when retrieving an user to send
115
- # an e-mail for password reset. In such cases, find_for_authentication
116
- # is not called.
117
- def find_for_authentication(tainted_conditions)
118
- find_first_by_auth_conditions(tainted_conditions)
135
+ def find_for_authentication(conditions)
136
+ find_first_by_auth_conditions(conditions)
119
137
  end
120
138
 
121
- def find_first_by_auth_conditions(tainted_conditions, opts={})
122
- to_adapter.find_first(devise_param_filter.filter(tainted_conditions).merge(opts))
139
+ def find_first_by_auth_conditions(conditions)
140
+ to_adapter.find_first devise_param_filter.filter(conditions)
123
141
  end
124
142
 
125
143
  # Find an initialize a record setting an error if it can't be found.
@@ -165,4 +183,4 @@ module Devise
165
183
  end
166
184
  end
167
185
  end
168
- end
186
+ end