activesambaldap 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/NEWS.en +10 -1
- data/NEWS.ja +10 -1
- data/README.en +10 -3
- data/README.ja +10 -3
- data/Rakefile +3 -4
- data/data/locale/ja/LC_MESSAGES/active-samba-ldap.mo +0 -0
- data/example/asl-admin/README +243 -0
- data/example/asl-admin/Rakefile +10 -0
- data/example/asl-admin/app/controllers/application_controller.rb +10 -0
- data/example/asl-admin/app/controllers/samba_controller.rb +12 -0
- data/example/asl-admin/app/helpers/application_helper.rb +3 -0
- data/example/asl-admin/app/helpers/samba_helper.rb +2 -0
- data/example/asl-admin/app/models/computer.rb +3 -0
- data/example/asl-admin/app/models/dc.rb +3 -0
- data/example/asl-admin/app/models/group.rb +3 -0
- data/example/asl-admin/app/models/idmap.rb +3 -0
- data/example/asl-admin/app/models/ou.rb +3 -0
- data/example/asl-admin/app/models/unix_id_pool.rb +3 -0
- data/example/asl-admin/app/models/user.rb +3 -0
- data/example/asl-admin/app/views/samba/index.html.erb +17 -0
- data/example/asl-admin/app/views/samba/populate.html.erb +15 -0
- data/example/asl-admin/app/views/samba/purge.html.erb +10 -0
- data/example/asl-admin/config/boot.rb +110 -0
- data/example/asl-admin/config/database.yml +22 -0
- data/example/asl-admin/config/environment.rb +48 -0
- data/example/asl-admin/config/environments/development.rb +17 -0
- data/example/asl-admin/config/environments/production.rb +28 -0
- data/example/asl-admin/config/environments/test.rb +28 -0
- data/example/asl-admin/config/initializers/backtrace_silencers.rb +7 -0
- data/example/asl-admin/config/initializers/inflections.rb +10 -0
- data/example/asl-admin/config/initializers/mime_types.rb +5 -0
- data/example/asl-admin/config/initializers/new_rails_defaults.rb +19 -0
- data/example/asl-admin/config/initializers/session_store.rb +15 -0
- data/example/asl-admin/config/ldap.yml.sample +24 -0
- data/example/asl-admin/config/locales/en.yml +5 -0
- data/example/asl-admin/config/routes.rb +43 -0
- data/example/asl-admin/log/test.log +5 -0
- data/example/asl-admin/public/404.html +30 -0
- data/example/asl-admin/public/422.html +30 -0
- data/example/asl-admin/public/500.html +30 -0
- data/example/asl-admin/public/favicon.ico +0 -0
- data/example/asl-admin/public/images/rails.png +0 -0
- data/example/asl-admin/public/index.html +275 -0
- data/example/asl-admin/public/javascripts/application.js +2 -0
- data/example/asl-admin/public/javascripts/controls.js +963 -0
- data/example/asl-admin/public/javascripts/dragdrop.js +973 -0
- data/example/asl-admin/public/javascripts/effects.js +1128 -0
- data/example/asl-admin/public/javascripts/prototype.js +4320 -0
- data/example/asl-admin/public/robots.txt +5 -0
- data/example/asl-admin/script/about +4 -0
- data/example/asl-admin/script/console +3 -0
- data/example/asl-admin/script/dbconsole +3 -0
- data/example/asl-admin/script/destroy +3 -0
- data/example/asl-admin/script/generate +3 -0
- data/example/asl-admin/script/performance/benchmarker +3 -0
- data/example/asl-admin/script/performance/profiler +3 -0
- data/example/asl-admin/script/plugin +3 -0
- data/example/asl-admin/script/runner +3 -0
- data/example/asl-admin/script/server +3 -0
- data/example/asl-admin/test/performance/browsing_test.rb +9 -0
- data/example/asl-admin/test/test_helper.rb +38 -0
- data/lib/active_samba_ldap.rb +1 -1
- data/lib/active_samba_ldap/account_entry.rb +17 -9
- data/lib/active_samba_ldap/active_directory.rb +66 -0
- data/lib/active_samba_ldap/base.rb +8 -0
- data/lib/active_samba_ldap/computer.rb +1 -0
- data/lib/active_samba_ldap/configuration.rb +32 -4
- data/lib/active_samba_ldap/entry.rb +48 -0
- data/lib/active_samba_ldap/group_entry.rb +8 -8
- data/lib/active_samba_ldap/populate.rb +1 -0
- data/lib/active_samba_ldap/samba_account_entry.rb +31 -14
- data/lib/active_samba_ldap/samba_computer_account_entry.rb +18 -0
- data/lib/active_samba_ldap/samba_entry.rb +6 -5
- data/lib/active_samba_ldap/samba_group_entry.rb +22 -13
- data/lib/active_samba_ldap/version.rb +1 -1
- data/po/active-samba-ldap.pot +463 -0
- data/po/ja/active-samba-ldap.po +15 -11
- data/rails/init.rb +1 -18
- data/rails_generators/scaffold_active_samba_ldap/scaffold_active_samba_ldap_generator.rb +4 -3
- data/rails_generators/scaffold_active_samba_ldap/templates/computer.rb +1 -1
- data/rails_generators/scaffold_active_samba_ldap/templates/group.rb +1 -1
- data/rails_generators/scaffold_active_samba_ldap/templates/{samba_index.rhtml → samba_index.html.erb} +0 -0
- data/rails_generators/scaffold_active_samba_ldap/templates/{samba_populate.rhtml → samba_populate.html.erb} +0 -0
- data/rails_generators/scaffold_active_samba_ldap/templates/{samba_purge.rhtml → samba_purge.html.erb} +0 -0
- data/rails_generators/scaffold_active_samba_ldap/templates/user.rb +1 -1
- data/test-unit/History.txt +1 -1
- data/test-unit/README.txt +1 -1
- data/test-unit/lib/test/unit/assertions.rb +1 -1
- data/test-unit/lib/test/unit/autorunner.rb +19 -4
- data/test-unit/lib/test/unit/collector/load.rb +3 -1
- data/test-unit/lib/test/unit/color-scheme.rb +5 -1
- data/test-unit/lib/test/unit/error.rb +7 -5
- data/test-unit/lib/test/unit/runner/tap.rb +8 -0
- data/test-unit/lib/test/unit/ui/console/testrunner.rb +63 -8
- data/test-unit/lib/test/unit/ui/tap/testrunner.rb +92 -0
- data/test-unit/test/collector/test-load.rb +1 -5
- data/test-unit/test/test-color-scheme.rb +4 -0
- data/test/command.rb +8 -3
- data/test/run-test.rb +4 -1
- data/test/test_asl_useradd.rb +2 -2
- metadata +81 -20
@@ -0,0 +1,38 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
3
|
+
require 'test_help'
|
4
|
+
|
5
|
+
class ActiveSupport::TestCase
|
6
|
+
# Transactional fixtures accelerate your tests by wrapping each test method
|
7
|
+
# in a transaction that's rolled back on completion. This ensures that the
|
8
|
+
# test database remains unchanged so your fixtures don't have to be reloaded
|
9
|
+
# between every test method. Fewer database queries means faster tests.
|
10
|
+
#
|
11
|
+
# Read Mike Clark's excellent walkthrough at
|
12
|
+
# http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
|
13
|
+
#
|
14
|
+
# Every Active Record database supports transactions except MyISAM tables
|
15
|
+
# in MySQL. Turn off transactional fixtures in this case; however, if you
|
16
|
+
# don't care one way or the other, switching from MyISAM to InnoDB tables
|
17
|
+
# is recommended.
|
18
|
+
#
|
19
|
+
# The only drawback to using transactional fixtures is when you actually
|
20
|
+
# need to test transactions. Since your test is bracketed by a transaction,
|
21
|
+
# any transactions started in your code will be automatically rolled back.
|
22
|
+
self.use_transactional_fixtures = true
|
23
|
+
|
24
|
+
# Instantiated fixtures are slow, but give you @david where otherwise you
|
25
|
+
# would need people(:david). If you don't want to migrate your existing
|
26
|
+
# test cases which use the @david style and don't mind the speed hit (each
|
27
|
+
# instantiated fixtures translates to a database query per test method),
|
28
|
+
# then set this back to true.
|
29
|
+
self.use_instantiated_fixtures = false
|
30
|
+
|
31
|
+
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
|
32
|
+
#
|
33
|
+
# Note: You'll currently still have to declare fixtures explicitly in integration tests
|
34
|
+
# -- they do not yet inherit this setting
|
35
|
+
fixtures :all
|
36
|
+
|
37
|
+
# Add more helper methods to be used by all tests here...
|
38
|
+
end
|
data/lib/active_samba_ldap.rb
CHANGED
@@ -8,7 +8,7 @@ require_gem_if_need = Proc.new do |library_name, gem_name, *options|
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
required_active_ldap_version = ">= 1.
|
11
|
+
required_active_ldap_version = ">= 1.2.0"
|
12
12
|
require_gem_if_need.call("active_ldap", "activeldap",
|
13
13
|
required_active_ldap_version)
|
14
14
|
|
@@ -28,10 +28,18 @@ module ActiveSambaLdap
|
|
28
28
|
find(:first, :filter => "(#{attribute}=#{value})")
|
29
29
|
end
|
30
30
|
|
31
|
+
def unix_object_classes
|
32
|
+
if samba4?
|
33
|
+
samba_object_classes
|
34
|
+
else
|
35
|
+
["inetOrgPerson", "posixAccount"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
31
39
|
private
|
32
40
|
def default_options
|
33
41
|
{
|
34
|
-
:dn_attribute =>
|
42
|
+
:dn_attribute => default_dn_attribute,
|
35
43
|
:ldap_scope => :sub,
|
36
44
|
:primary_group_class => default_group_class,
|
37
45
|
:primary_group_foreign_key => "gidNumber",
|
@@ -44,16 +52,16 @@ module ActiveSambaLdap
|
|
44
52
|
}
|
45
53
|
end
|
46
54
|
|
47
|
-
def
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
def default_dn_attribute
|
56
|
+
if samba4?
|
57
|
+
"cn"
|
58
|
+
else
|
59
|
+
"uid"
|
60
|
+
end
|
53
61
|
end
|
54
62
|
|
55
|
-
def
|
56
|
-
|
63
|
+
def default_group_class
|
64
|
+
"Group"
|
57
65
|
end
|
58
66
|
|
59
67
|
def primary_group_options(options)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ActiveSambaLdap
|
2
|
+
module ActiveDirectory
|
3
|
+
module UserAccountControl
|
4
|
+
# http://support.microsoft.com/kb/305144/ja
|
5
|
+
SCRIPT = 0x0001
|
6
|
+
ACCOUNTDISABLE = 0x0002
|
7
|
+
ACCOUNT_DISABLE = ACCOUNTDISABLE
|
8
|
+
HOMEDIR_REQUIRED = 0x0008
|
9
|
+
HOME_DIRECTORY_REQUIRED = HOMEDIR_REQUIRED
|
10
|
+
LOCKOUT = 0x0010
|
11
|
+
PASSWD_NOTREQD = 0x0020
|
12
|
+
PASSWORD_NOT_REQUIRED = PASSWD_NOTREQD
|
13
|
+
|
14
|
+
# To modify this property, see
|
15
|
+
# http://msdn.microsoft.com/en-us/library/aa746398(VS.85).aspx
|
16
|
+
PASSWD_CANT_CHANGE = 0x0040
|
17
|
+
PASSWORD_CANT_CHANGE = PASSWD_CANT_CHANGE
|
18
|
+
|
19
|
+
ENCRYPTED_TEXT_PWD_ALLOWED = 0x0080
|
20
|
+
ENCRYPTED_TEXT_PASSWORD_ALLOWED = ENCRYPTED_TEXT_PWD_ALLOWED
|
21
|
+
TEMP_DUPLICATE_ACCOUNT = 0x0100
|
22
|
+
NORMAL_ACCOUNT = 0x0200
|
23
|
+
INTERDOMAIN_TRUST_ACCOUNT = 0x0800
|
24
|
+
WORKSTATION_TRUST_ACCOUNT = 0x1000
|
25
|
+
SERVER_TRUST_ACCOUNT = 0x2000
|
26
|
+
DONT_EXPIRE_PASSWORD = 0x10000
|
27
|
+
MNS_LOGON_ACCOUNT = 0x20000
|
28
|
+
SMARTCARD_REQUIRED = 0x40000
|
29
|
+
SMART_CARD_REQUIRED = SMARTCARD_REQUIRED
|
30
|
+
TRUSTED_FOR_DELEGATION = 0x80000
|
31
|
+
NOT_DELEGATED = 0x100000
|
32
|
+
USE_DES_KEY_ONLY = 0x200000
|
33
|
+
DONT_REQ_PREAUTH = 0x400000
|
34
|
+
DONT_REQUIRE_PREAUTH = DONT_REQ_PREAUTH
|
35
|
+
PASSWORD_EXPIRED = 0x800000
|
36
|
+
TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000
|
37
|
+
end
|
38
|
+
|
39
|
+
module GroupType
|
40
|
+
GLOBAL_GROUP = 0x2
|
41
|
+
DOMAIN_LOCAL_GROUP = 0x4
|
42
|
+
UNIVERSAL_GROUP = 0x8
|
43
|
+
|
44
|
+
SECURITY_ENABLED = 0x80000000
|
45
|
+
|
46
|
+
module_function
|
47
|
+
def resolve(name, security_enabled=true)
|
48
|
+
type = 0
|
49
|
+
case name.to_s
|
50
|
+
when "global"
|
51
|
+
type = GLOBAL_GROUP
|
52
|
+
when /\Adomain[-_]local\z/
|
53
|
+
type = DOMAIN_LOCAL_GROUP
|
54
|
+
when "universal"
|
55
|
+
type = UNIVERSAL_GROUP
|
56
|
+
else
|
57
|
+
# TODO: I18N
|
58
|
+
raise ArgumentError, "unknown group type: #{name.inspect}: " +
|
59
|
+
"available: [:global, :domain_local, :universal]"
|
60
|
+
end
|
61
|
+
type |= SECURITY_ENABLED if security_enabled
|
62
|
+
[type].pack("L").unpack("l")[0]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -112,6 +112,14 @@ module ActiveSambaLdap
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
|
+
class NotUnixAavialableError < Error
|
116
|
+
attr_reader :object
|
117
|
+
def initialize(object)
|
118
|
+
@object = object
|
119
|
+
super(_("%s is not UNIX available") % [object.inspect])
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
115
123
|
class Base < ActiveLdap::Base
|
116
124
|
include Reloadable
|
117
125
|
|
@@ -99,7 +99,9 @@ module ActiveSambaLdap
|
|
99
99
|
skeleton_directory
|
100
100
|
|
101
101
|
default_user_gid default_computer_gid
|
102
|
-
default_max_password_age
|
102
|
+
default_max_password_age
|
103
|
+
|
104
|
+
samba4)
|
103
105
|
|
104
106
|
class << self
|
105
107
|
def required_variables
|
@@ -206,16 +208,33 @@ module ActiveSambaLdap
|
|
206
208
|
end
|
207
209
|
|
208
210
|
def users_suffix
|
209
|
-
retrieve_value_from_smb_conf(/ldap\s+user\s+suffix/i)
|
211
|
+
suffix = retrieve_value_from_smb_conf(/ldap\s+user\s+suffix/i)
|
212
|
+
return suffix if suffix
|
213
|
+
if self[:samba4]
|
214
|
+
"cn=Users"
|
215
|
+
else
|
216
|
+
"ou=Users"
|
217
|
+
end
|
210
218
|
end
|
211
219
|
|
212
220
|
def groups_suffix
|
213
|
-
retrieve_value_from_smb_conf(/ldap\s+group\s+suffix/i)
|
221
|
+
suffix = retrieve_value_from_smb_conf(/ldap\s+group\s+suffix/i)
|
222
|
+
return suffix if suffix
|
223
|
+
if self[:samba4]
|
224
|
+
"cn=Users"
|
225
|
+
else
|
226
|
+
"ou=Groups"
|
227
|
+
end
|
214
228
|
end
|
215
229
|
|
216
230
|
def computers_suffix
|
217
|
-
retrieve_value_from_smb_conf(/ldap\s+machine\s+suffix/i)
|
231
|
+
suffix = retrieve_value_from_smb_conf(/ldap\s+machine\s+suffix/i)
|
232
|
+
return suffix if suffix
|
233
|
+
if self[:samba4]
|
234
|
+
"cn=Computers"
|
235
|
+
else
|
218
236
|
"ou=Computers"
|
237
|
+
end
|
219
238
|
end
|
220
239
|
|
221
240
|
def idmap_suffix
|
@@ -301,6 +320,15 @@ module ActiveSambaLdap
|
|
301
320
|
type.to_s.downcase.to_sym
|
302
321
|
end
|
303
322
|
|
323
|
+
def samba4
|
324
|
+
smb_conf = self[:smb_conf]
|
325
|
+
if smb_conf and /^\s*server\s*role\s*=/ =~ File.read(smb_conf)
|
326
|
+
true
|
327
|
+
else
|
328
|
+
false
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
304
332
|
AVAILABLE_HASH_TYPES = [:crypt, :md5, :smd5, :sha, :ssha]
|
305
333
|
def validate_password_hash_type(type)
|
306
334
|
unless AVAILABLE_HASH_TYPES.include?(type)
|
@@ -28,7 +28,27 @@ module ActiveSambaLdap
|
|
28
28
|
entry
|
29
29
|
end
|
30
30
|
|
31
|
+
def samba4?
|
32
|
+
configuration[:samba4]
|
33
|
+
end
|
34
|
+
|
31
35
|
private
|
36
|
+
def default_classes
|
37
|
+
if samba4?
|
38
|
+
samba_object_classes
|
39
|
+
else
|
40
|
+
unix_object_classes
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_recommended_classes
|
45
|
+
if samba4?
|
46
|
+
[]
|
47
|
+
else
|
48
|
+
samba_object_classes
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
32
52
|
def ensure_ou(dn)
|
33
53
|
return if dn.nil?
|
34
54
|
dn_value, ou = dn.split(/,/, 2)
|
@@ -77,5 +97,33 @@ module ActiveSambaLdap
|
|
77
97
|
pool
|
78
98
|
end
|
79
99
|
end
|
100
|
+
|
101
|
+
def samba4?
|
102
|
+
self.class.samba4?
|
103
|
+
end
|
104
|
+
|
105
|
+
def unix_available?
|
106
|
+
(unix_object_classes - classes).empty?
|
107
|
+
end
|
108
|
+
|
109
|
+
def remove_unix_availability
|
110
|
+
remove_class(*unix_object_classes)
|
111
|
+
end
|
112
|
+
|
113
|
+
def ensure_unix_availability
|
114
|
+
add_class(*unix_object_classes)
|
115
|
+
end
|
116
|
+
|
117
|
+
def unix_object_classes
|
118
|
+
self.class.unix_object_classes
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
def assert_unix_available
|
123
|
+
return unless samba4?
|
124
|
+
unless unix_available?
|
125
|
+
raise NotUnixAavialableError.new(self)
|
126
|
+
end
|
127
|
+
end
|
80
128
|
end
|
81
129
|
end
|
@@ -33,6 +33,14 @@ module ActiveSambaLdap
|
|
33
33
|
find(:first, :filter => ["gidNumber", Integer(number)])
|
34
34
|
end
|
35
35
|
|
36
|
+
def unix_object_classes
|
37
|
+
if samba4?
|
38
|
+
samba_object_classes
|
39
|
+
else
|
40
|
+
["posixGroup"]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
36
44
|
private
|
37
45
|
def default_options
|
38
46
|
{
|
@@ -52,14 +60,6 @@ module ActiveSambaLdap
|
|
52
60
|
}
|
53
61
|
end
|
54
62
|
|
55
|
-
def default_classes
|
56
|
-
["top", "posixGroup"]
|
57
|
-
end
|
58
|
-
|
59
|
-
def default_recommended_classes
|
60
|
-
[]
|
61
|
-
end
|
62
|
-
|
63
63
|
def default_user_class
|
64
64
|
"User"
|
65
65
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_samba_ldap/active_directory'
|
2
|
+
|
1
3
|
module ActiveSambaLdap
|
2
4
|
module SambaAccountEntry
|
3
5
|
def self.included(base)
|
@@ -29,8 +31,12 @@ module ActiveSambaLdap
|
|
29
31
|
ACCOUNT_FLAGS_RE = /\A\[([NDHTUMWSLXI ]+)\]\z/
|
30
32
|
|
31
33
|
module ClassMethods
|
32
|
-
def
|
33
|
-
|
34
|
+
def samba_object_classes
|
35
|
+
if samba4?
|
36
|
+
["person", "organizationalPerson", "user"]
|
37
|
+
else
|
38
|
+
["sambaSamAccount"]
|
39
|
+
end
|
34
40
|
end
|
35
41
|
|
36
42
|
def uid2rid(uid)
|
@@ -56,10 +62,6 @@ module ActiveSambaLdap
|
|
56
62
|
end
|
57
63
|
|
58
64
|
private
|
59
|
-
def default_recommended_classes
|
60
|
-
super + [samba_object_class]
|
61
|
-
end
|
62
|
-
|
63
65
|
def primary_group_options(options)
|
64
66
|
super.merge(:extend => PrimaryGroupProxy)
|
65
67
|
end
|
@@ -197,19 +199,29 @@ module ActiveSambaLdap
|
|
197
199
|
|
198
200
|
def enable
|
199
201
|
assert_samba_available
|
200
|
-
if
|
201
|
-
self.
|
202
|
+
if samba4?
|
203
|
+
self.user_account_control -=
|
204
|
+
ActiveDirectory::UserAccountControl::ACCOUNT_DISABLE
|
205
|
+
else
|
206
|
+
if /D/ =~ samba_acct_flags.to_s
|
207
|
+
self.samba_acct_flags = samba_acct_flags.gsub(/D/, '')
|
208
|
+
end
|
202
209
|
end
|
203
210
|
end
|
204
211
|
|
205
212
|
def disable
|
206
213
|
assert_samba_available
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
214
|
+
if samba4?
|
215
|
+
self.user_account_control +=
|
216
|
+
ActiveDirectory::UserAccountControl::ACCOUNT_DISABLE
|
217
|
+
else
|
218
|
+
flags = ""
|
219
|
+
if ACCOUNT_FLAGS_RE =~ samba_acct_flags.to_s
|
220
|
+
flags = $1
|
221
|
+
return if /D/ =~ flags
|
222
|
+
end
|
223
|
+
self.samba_acct_flags = "[D#{flags}]"
|
211
224
|
end
|
212
|
-
self.samba_acct_flags = "[D#{flags}]"
|
213
225
|
end
|
214
226
|
|
215
227
|
def enabled?
|
@@ -219,7 +231,12 @@ module ActiveSambaLdap
|
|
219
231
|
|
220
232
|
def disabled?
|
221
233
|
assert_samba_available
|
222
|
-
|
234
|
+
if samba4?
|
235
|
+
not (user_account_control &
|
236
|
+
ActiveDirectory::UserAccountControl::ACCOUNT_DISABLE).zero?
|
237
|
+
else
|
238
|
+
(/D/ =~ samba_acct_flags.to_s) ? true : false
|
239
|
+
end
|
223
240
|
end
|
224
241
|
end
|
225
242
|
end
|