strongbolt 0.3.6

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 (145) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +33 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +1 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +130 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +182 -0
  11. data/Rakefile +1 -0
  12. data/app/assets/javascripts/strongbolt.js +1 -0
  13. data/app/assets/javascripts/strongbolt/role-capabilities.js +80 -0
  14. data/app/controllers/strongbolt/capabilities_controller.rb +77 -0
  15. data/app/controllers/strongbolt/roles_controller.rb +92 -0
  16. data/app/controllers/strongbolt/security_controller.rb +8 -0
  17. data/app/controllers/strongbolt/user_groups_controller.rb +76 -0
  18. data/app/controllers/strongbolt/user_groups_users_controller.rb +35 -0
  19. data/app/controllers/strongbolt_controller.rb +2 -0
  20. data/app/views/strongbolt/_menu.html.erb +13 -0
  21. data/app/views/strongbolt/capabilities/index.html.erb +53 -0
  22. data/app/views/strongbolt/capabilities/show.html.erb +53 -0
  23. data/app/views/strongbolt/roles/_capabilities.html.erb +47 -0
  24. data/app/views/strongbolt/roles/_capability.html.erb +21 -0
  25. data/app/views/strongbolt/roles/_form.html.erb +12 -0
  26. data/app/views/strongbolt/roles/edit.html.erb +14 -0
  27. data/app/views/strongbolt/roles/index.html.erb +54 -0
  28. data/app/views/strongbolt/roles/new.html.erb +11 -0
  29. data/app/views/strongbolt/roles/show.html.erb +52 -0
  30. data/app/views/strongbolt/user_groups/_form.html.erb +12 -0
  31. data/app/views/strongbolt/user_groups/edit.html.erb +14 -0
  32. data/app/views/strongbolt/user_groups/index.html.erb +46 -0
  33. data/app/views/strongbolt/user_groups/new.html.erb +13 -0
  34. data/app/views/strongbolt/user_groups/show.html.erb +88 -0
  35. data/lib/generators/strongbolt/fix_generator.rb +23 -0
  36. data/lib/generators/strongbolt/indexes_generator.rb +19 -0
  37. data/lib/generators/strongbolt/install_generator.rb +29 -0
  38. data/lib/generators/strongbolt/templates/fix.rb +5 -0
  39. data/lib/generators/strongbolt/templates/indexes.rb +21 -0
  40. data/lib/generators/strongbolt/templates/migration.rb +73 -0
  41. data/lib/generators/strongbolt/templates/strongbolt.rb +45 -0
  42. data/lib/generators/strongbolt/views_generator.rb +26 -0
  43. data/lib/strongbolt.rb +219 -0
  44. data/lib/strongbolt/base.rb +7 -0
  45. data/lib/strongbolt/bolted.rb +125 -0
  46. data/lib/strongbolt/bolted_controller.rb +297 -0
  47. data/lib/strongbolt/capabilities_role.rb +15 -0
  48. data/lib/strongbolt/capability.rb +165 -0
  49. data/lib/strongbolt/configuration.rb +111 -0
  50. data/lib/strongbolt/controllers/url_helpers.rb +37 -0
  51. data/lib/strongbolt/engine.rb +44 -0
  52. data/lib/strongbolt/errors.rb +38 -0
  53. data/lib/strongbolt/generators/migration.rb +35 -0
  54. data/lib/strongbolt/helpers.rb +18 -0
  55. data/lib/strongbolt/rails/routes.rb +20 -0
  56. data/lib/strongbolt/role.rb +46 -0
  57. data/lib/strongbolt/roles_user_group.rb +15 -0
  58. data/lib/strongbolt/rspec.rb +29 -0
  59. data/lib/strongbolt/rspec/user.rb +90 -0
  60. data/lib/strongbolt/tenantable.rb +304 -0
  61. data/lib/strongbolt/user_abilities.rb +292 -0
  62. data/lib/strongbolt/user_group.rb +24 -0
  63. data/lib/strongbolt/user_groups_user.rb +16 -0
  64. data/lib/strongbolt/users_tenant.rb +12 -0
  65. data/lib/strongbolt/version.rb +3 -0
  66. data/lib/tasks/strongbolt_tasks.rake +29 -0
  67. data/spec/controllers/strongbolt/capabilities_controller_spec.rb +254 -0
  68. data/spec/controllers/strongbolt/roles_controller_spec.rb +228 -0
  69. data/spec/controllers/strongbolt/user_groups_controller_spec.rb +216 -0
  70. data/spec/controllers/strongbolt/user_groups_users_controller_spec.rb +69 -0
  71. data/spec/controllers/without_authorization_controller_spec.rb +20 -0
  72. data/spec/dummy/.rspec +2 -0
  73. data/spec/dummy/README.rdoc +28 -0
  74. data/spec/dummy/Rakefile +6 -0
  75. data/spec/dummy/app/assets/images/.keep +0 -0
  76. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  77. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  78. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  79. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  80. data/spec/dummy/app/controllers/posts_controller.rb +18 -0
  81. data/spec/dummy/app/controllers/test_controller.rb +3 -0
  82. data/spec/dummy/app/controllers/without_authorization_controller.rb +5 -0
  83. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  84. data/spec/dummy/app/mailers/.keep +0 -0
  85. data/spec/dummy/app/models/.keep +0 -0
  86. data/spec/dummy/app/models/concerns/.keep +0 -0
  87. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  88. data/spec/dummy/bin/bundle +3 -0
  89. data/spec/dummy/bin/rails +4 -0
  90. data/spec/dummy/bin/rake +4 -0
  91. data/spec/dummy/config.ru +4 -0
  92. data/spec/dummy/config/application.rb +29 -0
  93. data/spec/dummy/config/boot.rb +5 -0
  94. data/spec/dummy/config/database.yml +25 -0
  95. data/spec/dummy/config/environment.rb +5 -0
  96. data/spec/dummy/config/environments/development.rb +37 -0
  97. data/spec/dummy/config/environments/production.rb +78 -0
  98. data/spec/dummy/config/environments/test.rb +39 -0
  99. data/spec/dummy/config/initializers/assets.rb +8 -0
  100. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  101. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  102. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  103. data/spec/dummy/config/initializers/inflections.rb +16 -0
  104. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  105. data/spec/dummy/config/initializers/session_store.rb +3 -0
  106. data/spec/dummy/config/initializers/strongbolt.rb +32 -0
  107. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  108. data/spec/dummy/config/locales/en.yml +23 -0
  109. data/spec/dummy/config/routes.rb +12 -0
  110. data/spec/dummy/config/secrets.yml +22 -0
  111. data/spec/dummy/db/development.sqlite3 +0 -0
  112. data/spec/dummy/db/migrate/20150630212236_create_strongbolt_tables.rb +54 -0
  113. data/spec/dummy/db/migrate/20150630212251_create_strongbolt_tables_indexes.rb +21 -0
  114. data/spec/dummy/db/schema.rb +84 -0
  115. data/spec/dummy/db/test.sqlite3 +0 -0
  116. data/spec/dummy/lib/assets/.keep +0 -0
  117. data/spec/dummy/public/404.html +67 -0
  118. data/spec/dummy/public/422.html +67 -0
  119. data/spec/dummy/public/500.html +66 -0
  120. data/spec/dummy/public/favicon.ico +0 -0
  121. data/spec/fabricators/capability_fabricator.rb +4 -0
  122. data/spec/fabricators/role_fabricator.rb +9 -0
  123. data/spec/fabricators/user_fabricator.rb +3 -0
  124. data/spec/fabricators/user_group_fabricator.rb +9 -0
  125. data/spec/fixtures/application.rb +28 -0
  126. data/spec/fixtures/controllers.rb +5 -0
  127. data/spec/spec_helper.rb +89 -0
  128. data/spec/strongbolt/bolted_controller_spec.rb +706 -0
  129. data/spec/strongbolt/bolted_spec.rb +136 -0
  130. data/spec/strongbolt/capability_spec.rb +251 -0
  131. data/spec/strongbolt/configuration_spec.rb +119 -0
  132. data/spec/strongbolt/controllers/url_helpers_spec.rb +34 -0
  133. data/spec/strongbolt/helpers_spec.rb +43 -0
  134. data/spec/strongbolt/role_spec.rb +90 -0
  135. data/spec/strongbolt/tenantable_spec.rb +281 -0
  136. data/spec/strongbolt/user_abilities_spec.rb +509 -0
  137. data/spec/strongbolt/user_group_spec.rb +37 -0
  138. data/spec/strongbolt/users_tenant_spec.rb +36 -0
  139. data/spec/strongbolt_spec.rb +274 -0
  140. data/spec/support/controller_macros.rb +11 -0
  141. data/spec/support/db_setup.rb +134 -0
  142. data/spec/support/helpers.rb +62 -0
  143. data/spec/support/transactional_specs.rb +17 -0
  144. data/strongbolt.gemspec +32 -0
  145. metadata +407 -0
@@ -0,0 +1,24 @@
1
+ module Strongbolt
2
+ class UserGroup < Base
3
+
4
+ has_many :user_groups_users,
5
+ :class_name => "Strongbolt::UserGroupsUser",
6
+ :dependent => :restrict_with_exception,
7
+ :inverse_of => :user_group
8
+ has_many :users, :through => :user_groups_users
9
+
10
+ has_many :roles_user_groups,
11
+ :class_name => "Strongbolt::RolesUserGroup",
12
+ :dependent => :delete_all,
13
+ :inverse_of => :user_group
14
+
15
+ has_many :roles, :through => :roles_user_groups
16
+
17
+ has_many :capabilities, through: :roles
18
+
19
+ validates_presence_of :name
20
+
21
+ end
22
+ end
23
+
24
+ UserGroup = Strongbolt::UserGroup unless defined? UserGroup
@@ -0,0 +1,16 @@
1
+ module Strongbolt
2
+ class UserGroupsUser < Base
3
+ authorize_as "Strongbolt::UserGroup"
4
+
5
+ belongs_to :user_group,
6
+ :class_name => "Strongbolt::UserGroup",
7
+ :inverse_of => :user_groups_users
8
+
9
+ belongs_to :user,
10
+ :class_name => Configuration.user_class,
11
+ :foreign_key => :user_id,
12
+ :inverse_of => :user_groups_users
13
+
14
+ validates_presence_of :user_group, :user
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module Strongbolt
2
+ #
3
+ # This is a STI model that will have subclasses making links
4
+ # from users to tenants (if one or more tenants are defined)
5
+ #
6
+ class UsersTenant < Base
7
+ # Required validation for every subclass
8
+ validates :user, presence: true
9
+ end
10
+ end
11
+
12
+ UsersTenant = Strongbolt::UsersTenant unless defined? UsersTenant
@@ -0,0 +1,3 @@
1
+ module Strongbolt
2
+ VERSION = "0.3.6"
3
+ end
@@ -0,0 +1,29 @@
1
+ namespace :strongbolt do
2
+ #
3
+ # Create full authorization roles that allows to get started using StrongBolt
4
+ #
5
+ task :seed => :environment do
6
+ ActiveRecord::Base.transaction do
7
+ #
8
+ # Creates capabilities for all models/actions
9
+ #
10
+ Capability.models.each do |model|
11
+ Capability::Actions.each do |action|
12
+ Capability.where(model: model, action: action,
13
+ require_tenant_access: false).first_or_create
14
+ end
15
+ end
16
+
17
+ # The role
18
+ role = Role.create! name: "FULL ACCESS (TEMPORARY)"
19
+ role.capabilities = Capability.all
20
+
21
+ # The user group
22
+ ug = UserGroup.create! name: "FULL ACCESS USERS (TEMPORARY)"
23
+ ug.roles << role
24
+
25
+ # Assign to all users
26
+ User.all.each { |user| user.user_groups << ug }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,254 @@
1
+ require "spec_helper"
2
+
3
+ module Strongbolt
4
+
5
+ describe CapabilitiesController do
6
+
7
+ subject { response }
8
+
9
+ # #
10
+ # # GET #index
11
+ # #
12
+ # describe "GET #index" do
13
+
14
+ # before do
15
+ # Fabricate :capability
16
+ # get :index
17
+ # end
18
+
19
+ # it { should be_success }
20
+
21
+ # it { should render_template :index }
22
+
23
+ # it "should assign capabilities" do
24
+ # expect(assigns :capabilities).to be_present
25
+ # expect(assigns(:capabilities).size).to be > 0
26
+ # end
27
+
28
+ # end # End GET #index
29
+
30
+
31
+ # #
32
+ # # GET #show
33
+ # #
34
+ # describe "GET #show" do
35
+ # let(:capability) { Fabricate :capability }
36
+
37
+ # before { get :show, id: capability.id }
38
+
39
+ # it { should be_success }
40
+
41
+ # it { should render_template :show }
42
+
43
+ # it "should assign capability" do
44
+ # expect(assigns :capability).to be_present
45
+ # end
46
+ # end
47
+
48
+ #
49
+ # POST #create
50
+ #
51
+ describe "POST #create" do
52
+
53
+ let(:create) { post :create, capability: attributes }
54
+
55
+ # context "when valid attributes" do
56
+ # let(:attributes) { Fabricate.attributes_for :capability }
57
+
58
+ # it "should redirect to capabilities list" do
59
+ # create
60
+ # expect(response).to redirect_to capabilities_path
61
+ # end
62
+
63
+ # it "should create a capability" do
64
+ # expect do
65
+ # create
66
+ # end.to change(Capability, :count).by 1
67
+ # end
68
+ # end
69
+
70
+ context "when valid attributes and role id present" do
71
+
72
+ let(:role) { Fabricate :role }
73
+ let(:attributes) { Fabricate.attributes_for :capability }
74
+
75
+ context "html" do
76
+ let(:create) { post :create, capability: attributes, role_id: role.id }
77
+
78
+ it "should redirect to role" do
79
+ create
80
+ expect(response).to redirect_to role_path(role)
81
+ end
82
+
83
+ it "should add a capability to the role" do
84
+ expect do
85
+ create
86
+ end.to change(role.capabilities, :count).by 1
87
+ end
88
+ end
89
+
90
+ context "json" do |variable|
91
+ let(:create) { post :create, capability: attributes, role_id: role.id, format: :json }
92
+
93
+ it "should redirect to role" do
94
+ create
95
+ expect(response.code).to eq "200"
96
+ end
97
+
98
+ it "should add a capability to the role" do
99
+ expect do
100
+ create
101
+ end.to change(role.capabilities, :count).by 1
102
+ end
103
+ end
104
+ end
105
+
106
+ # context "when same capability already exist" do
107
+ # let(:attributes) { Fabricate.attributes_for :capability }
108
+
109
+ # before do
110
+ # Fabricate :capability, attributes
111
+ # end
112
+
113
+ # it "should redirect to index" do
114
+ # create
115
+ # expect(response).to redirect_to capabilities_path
116
+ # end
117
+ # end
118
+
119
+ # context "when invalid attributes" do
120
+ # let(:attributes) { {} }
121
+
122
+ # it "should set flash danger" do
123
+ # create
124
+ # expect(flash[:danger]).to be_present
125
+ # end
126
+
127
+ # it "should redirect to index" do
128
+ # create
129
+ # expect(response).to redirect_to capabilities_path
130
+ # end
131
+ # end
132
+
133
+ end # END POST #create
134
+
135
+
136
+
137
+ #
138
+ # DELETE #destroy
139
+ #
140
+ describe "DELETE #destroy" do
141
+
142
+ before do
143
+ @capability = Fabricate :capability
144
+ end
145
+
146
+ let(:capability) { @capability }
147
+
148
+ let(:destroy) { delete :destroy, id: capability.id }
149
+
150
+ # context "when no roles" do
151
+
152
+ # it "should redirect to capabilities list" do
153
+ # destroy
154
+ # expect(response).to redirect_to capabilities_path
155
+ # end
156
+
157
+ # it "should delete a capability" do
158
+ # expect do
159
+ # destroy
160
+ # end.to change(Capability, :count).by -1
161
+ # end
162
+
163
+ # end
164
+
165
+ # context "when roles linked" do
166
+
167
+ # before do
168
+ # capability.roles << Fabricate(:role)
169
+ # end
170
+
171
+ # it "should redirect to capabilities list" do
172
+ # destroy
173
+ # expect(response).to redirect_to capability_path(capability)
174
+ # end
175
+
176
+ # it "should not delete a capability" do
177
+ # expect do
178
+ # destroy
179
+ # end.not_to change(Capability, :count)
180
+ # end
181
+
182
+ # it "should set flash danger" do
183
+ # destroy
184
+ # expect(flash[:danger]).to be_present
185
+ # end
186
+
187
+ # end
188
+
189
+ context "when role_id given" do
190
+ let(:role) { Fabricate :role }
191
+
192
+ before do
193
+ role.capabilities << capability
194
+ end
195
+
196
+ context "when capability id given" do
197
+
198
+ let(:destroy) { delete :destroy, id: capability.id, role_id: role.id }
199
+
200
+
201
+ it "should not delete a capability" do
202
+ expect do
203
+ destroy
204
+ end.not_to change(Capability, :count)
205
+ end
206
+
207
+ it "should remove the capability from role" do
208
+ destroy
209
+ role.reload
210
+ expect(role.capabilities).not_to include capability
211
+ end
212
+
213
+ it "should redirect to role" do
214
+ destroy
215
+ expect(response).to redirect_to role_path(role)
216
+ end
217
+
218
+ end
219
+
220
+ context "when capability data given and format json" do
221
+ let(:attributes) do
222
+ {model: capability.model, require_ownership: capability.require_ownership,
223
+ require_tenant_access: capability.require_tenant_access,
224
+ action: capability.action}
225
+ end
226
+
227
+ let(:destroy) { delete :destroy, role_id: role.id, capability: capability.attributes, format: :json }
228
+
229
+ it "should not delete a capability" do
230
+ expect do
231
+ destroy
232
+ end.not_to change(Capability, :count)
233
+ end
234
+
235
+ it "should remove the capability from role" do
236
+ destroy
237
+ role.reload
238
+ expect(role.capabilities).not_to include capability
239
+ end
240
+
241
+ it "should render 200" do
242
+ destroy
243
+ expect(response.code).to eq "200"
244
+ end
245
+ end
246
+ end
247
+
248
+
249
+ end
250
+
251
+
252
+ end
253
+
254
+ end
@@ -0,0 +1,228 @@
1
+ require "spec_helper"
2
+
3
+ module Strongbolt
4
+
5
+ describe RolesController do
6
+
7
+ let!(:role) { Fabricate :role }
8
+
9
+ let(:valid_attributes) { Fabricate.attributes_for :role }
10
+
11
+ # login_user
12
+
13
+ subject { response }
14
+
15
+ #
16
+ # GET #index
17
+ #
18
+ describe "GET #index" do
19
+
20
+ before { get :index }
21
+
22
+ it { should be_success }
23
+
24
+ it { should render_template :index }
25
+
26
+ it "should assign roles" do
27
+ expect(assigns :roles).to eq [role]
28
+ end
29
+
30
+ end
31
+
32
+ #
33
+ # GET #new
34
+ #
35
+ describe "GET #new" do
36
+
37
+ before { get :new }
38
+
39
+ it { should be_success }
40
+
41
+ it { should render_template :new }
42
+
43
+ end
44
+
45
+
46
+ #
47
+ # GET #show
48
+ #
49
+ describe "GET #show" do
50
+
51
+ # Some children
52
+ let(:role2) { Fabricate :role, parent: role }
53
+ let!(:role3) { Fabricate :role, parent: role2 }
54
+
55
+ before { get :show, id: role.id }
56
+
57
+ it { should be_success }
58
+
59
+ it "should assign role" do
60
+ expect(assigns :role).to eq role
61
+ end
62
+
63
+ it "should assign children" do
64
+ expect(assigns :descendants).to eq [role2, role3]
65
+ end
66
+
67
+ it { should render_template :show }
68
+
69
+ end
70
+
71
+ #
72
+ # GET #edit
73
+ #
74
+ describe "GET #edit" do
75
+
76
+ before { get :edit, id: role.id }
77
+
78
+ it { should be_success }
79
+
80
+ it "should assign role" do
81
+ expect(assigns :role).to eq role
82
+ end
83
+
84
+ it { should render_template :edit }
85
+
86
+ end
87
+
88
+ #
89
+ # POST #create
90
+ #
91
+ describe "POST #create" do
92
+
93
+ let(:create) { post :create, role: attributes }
94
+
95
+ context 'when valid attributes' do
96
+
97
+ let(:attributes) { valid_attributes }
98
+
99
+ it "should redirect to show" do
100
+ create
101
+ expect(response).to redirect_to role_path(Role.last)
102
+ end
103
+
104
+ it "should create an role" do
105
+ expect do
106
+ create
107
+ end.to change(Role, :count).by 1
108
+ end
109
+
110
+ end
111
+
112
+ context "when invalid attributes" do
113
+
114
+ let(:attributes) { {} }
115
+
116
+ it "should redirect_to new" do
117
+ create
118
+ expect(response).to redirect_to new_role_path
119
+ end
120
+
121
+ it "should not create a role" do
122
+ expect do
123
+ create
124
+ end.not_to change(Role, :count)
125
+ end
126
+
127
+ it "should set flash danger" do
128
+ create
129
+ expect(flash[:danger]).to be_present
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+
136
+
137
+ #
138
+ # PUT #update
139
+ #
140
+ describe "PUT #update" do
141
+
142
+ before { put :update, id: role.id, role: attributes }
143
+
144
+ context 'when valid attributes' do
145
+
146
+ let(:attributes) { valid_attributes }
147
+
148
+ it { should redirect_to role_path(role) }
149
+
150
+ it "should update attributes" do
151
+ expect(role.reload.name).to eq valid_attributes[:name]
152
+ end
153
+
154
+ end
155
+
156
+ context 'when invalid attributes' do
157
+
158
+ let(:attributes) { {name: ""} }
159
+
160
+ it { should redirect_to edit_role_path(role) }
161
+
162
+ it "should not update attributes" do
163
+ expect(role.reload.name).not_to eq ""
164
+ end
165
+
166
+ it "should set flash danger" do
167
+ expect(flash[:danger]).to be_present
168
+ end
169
+
170
+ end
171
+
172
+ end
173
+
174
+
175
+ #
176
+ # DELETE #destroy
177
+ #
178
+ describe "DELETE #destroy" do
179
+
180
+ let(:destroy) { delete :destroy, id: role.id }
181
+
182
+ context "when no user" do
183
+
184
+ it "should redirect to index" do
185
+ destroy
186
+ expect(response).to redirect_to roles_path
187
+ end
188
+
189
+ it "should set flash success" do
190
+ destroy
191
+ expect(flash[:success]).to be_present
192
+ end
193
+
194
+ it "should delete a role" do
195
+ expect do
196
+ destroy
197
+ end.to change(Role, :count).by -1
198
+ end
199
+
200
+ end
201
+
202
+ context "when has user groups" do
203
+
204
+ let(:role) { Fabricate :role_with_user_groups }
205
+
206
+ it "should redirect to show" do
207
+ destroy
208
+ expect(response).to redirect_to role_path(role)
209
+ end
210
+
211
+ it "should set flash danger" do
212
+ destroy
213
+ expect(flash[:danger]).to be_present
214
+ end
215
+
216
+ it "should not delete a role" do
217
+ expect do
218
+ destroy
219
+ end.not_to change(Role, :count)
220
+ end
221
+
222
+ end
223
+
224
+ end
225
+
226
+ end
227
+
228
+ end