postfix_admin 0.1.0 → 0.1.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 03fe6501c97e53bf66c3fa2f783e8b2e40cc18da
4
+ data.tar.gz: 0a7c400bee5d1f953ea9f2d03475b8c1e182653f
5
+ SHA512:
6
+ metadata.gz: b976ae17e338b7bd8154a092bb1d9ed91274b3cb1f008fc1d98e0b55b045dd28966e1d912cd35315bd75ce3005d2bad2e286d29d869967038e461c6867ad31e2
7
+ data.tar.gz: 56b944669124660d726addfcd2258543845b61170ea68cae3189d7ff87b45e4d2809ba2a0bfbea274d8338ada8e10e64408e672713531043614c28dd6bc07275
data/README.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  Command Line Tools of Postfix Admin
4
4
 
5
+ ## Description
6
+
7
+ Postfix Admin Web Site http://postfixadmin.sourceforge.net/
8
+
9
+ Sourceforge page http://sourceforge.net/projects/postfixadmin/
10
+
11
+ This software supports only MySQL as database for Postfix Admin.
12
+ PostgreSQL is not supported.
13
+
14
+ Postfix Admin 2.2.0 is supported.
15
+
5
16
  ## Installation
6
17
 
7
18
  Install postfix_admin as:
@@ -10,6 +21,10 @@ Install postfix_admin as:
10
21
 
11
22
  ## Usage
12
23
 
24
+ List the postfix_admin subcommands as:
25
+
26
+ $ postfix_admin
27
+
13
28
  ```
14
29
  postfix_admin account_passwd user@example.com new_password # Change password of account
15
30
  postfix_admin add_account user@example.com password # Add an account
data/bin/postfix_admin CHANGED
@@ -2,8 +2,4 @@
2
2
 
3
3
  require 'postfix_admin/runner'
4
4
 
5
- begin
6
- PostfixAdmin::Runner.start
7
- rescue => e
8
- warn e.message
9
- end
5
+ PostfixAdmin::Runner.start
data/lib/postfix_admin.rb CHANGED
@@ -1,2 +1,6 @@
1
1
  require "postfix_admin/version"
2
2
  require "postfix_admin/base"
3
+
4
+ module PostfixAdmin
5
+ KB_TO_MB = 1024000
6
+ end
@@ -21,7 +21,7 @@ module PostfixAdmin
21
21
  @config[:aliases] = config['aliases'] || 30
22
22
  @config[:mailboxes] = config['mailboxes'] || 30
23
23
  @config[:maxquota] = config['maxquota'] || 100
24
- @config[:mailbox_quota] = @config[:maxquota] * 1024 * 1000
24
+ @config[:mailbox_quota] = @config[:maxquota] * KB_TO_MB
25
25
  end
26
26
 
27
27
  def db_setup(database)
@@ -29,17 +29,12 @@ module PostfixAdmin
29
29
  DataMapper.finalize
30
30
  end
31
31
 
32
- def add_admin_domain(username, domain_name)
33
- unless Admin.exist?(username)
34
- raise Error, "#{username} is not resistered as admin."
35
- end
36
- unless Domain.exist?(domain_name)
37
- raise Error, "Could not find domain #{domain_name}"
38
- end
32
+ def add_admin_domain(user_name, domain_name)
33
+ admin_domain_check(user_name, domain_name)
39
34
 
40
- admin = Admin.find(username)
35
+ admin = Admin.find(user_name)
41
36
  if admin.has_domain?(domain_name)
42
- raise Error, "#{username} is already resistered as admin of #{domain_name}."
37
+ raise Error, "#{user_name} is already resistered as admin of #{domain_name}."
43
38
  end
44
39
 
45
40
  domain = Domain.find(domain_name)
@@ -47,6 +42,19 @@ module PostfixAdmin
47
42
  admin.save or raise "Relation Error: Domain of Admin"
48
43
  end
49
44
 
45
+ def delete_admin_domain(user_name, domain_name)
46
+ admin_domain_check(user_name, domain_name)
47
+
48
+ admin = Admin.find(user_name)
49
+ unless admin.has_domain?(domain_name)
50
+ raise Error, "#{user_name} is not resistered as admin of #{domain_name}."
51
+ end
52
+
53
+ domain = Domain.find(domain_name)
54
+ admin.domains.delete(domain)
55
+ admin.save or "Could not save Admin"
56
+ end
57
+
50
58
  def add_admin(username, password)
51
59
  if Admin.exist?(username)
52
60
  raise Error, "#{username} is already resistered as admin."
@@ -56,7 +64,9 @@ module PostfixAdmin
56
64
  :username => username,
57
65
  :password => password,
58
66
  }
59
- admin.save or raise "Could not save Admin"
67
+ unless admin.save
68
+ raise "Could not save Admin #{admin.errors.map{|e| e.to_s}.join}"
69
+ end
60
70
  end
61
71
 
62
72
  def add_account(address, password)
@@ -75,12 +85,7 @@ module PostfixAdmin
75
85
  end
76
86
 
77
87
  domain = Domain.find(domain_name)
78
- mail_alias = Alias.new
79
- mail_alias.attributes = {
80
- :address => address,
81
- :goto => address,
82
- }
83
- domain.aliases << mail_alias
88
+ domain.aliases << Alias.mailbox(address)
84
89
 
85
90
  mailbox = Mailbox.new
86
91
  mailbox.attributes = {
@@ -92,7 +97,9 @@ module PostfixAdmin
92
97
  # :local_part => user,
93
98
  }
94
99
  domain.mailboxes << mailbox
95
- domain.save or raise "Could not save Domain"
100
+ unless domain.save
101
+ raise "Could not save Mailbox and Domain #{mailbox.errors.map{|e| e.to_s}.join} #{domain.errors.map{|e| e.to_s}.join}"
102
+ end
96
103
  end
97
104
 
98
105
  def add_alias(address, goto)
@@ -128,6 +135,7 @@ module PostfixAdmin
128
135
  end
129
136
 
130
137
  def add_domain(domain_name)
138
+ domain_name = domain_name.downcase
131
139
  if domain_name !~ /.+\..+/
132
140
  raise Error, "Ivalid domain! #{domain_name}"
133
141
  end
@@ -146,6 +154,7 @@ module PostfixAdmin
146
154
  end
147
155
 
148
156
  def delete_domain(domain_name)
157
+ domain_name = domain_name.downcase
149
158
  unless Domain.exist?(domain_name)
150
159
  raise Error, "Could not find domain #{domain_name}"
151
160
  end
@@ -153,9 +162,14 @@ module PostfixAdmin
153
162
  domain = Domain.find(domain_name)
154
163
  domain.mailboxes.destroy or raise "Could not destroy Mailbox"
155
164
  domain.aliases.destroy or raise "Could not destroy Alias"
156
- domain.domain_admins.destroy or raise "Could not destroy DomainAdmin"
157
- delete_unnecessary_admins
165
+ admin_names = domain.admins.map{|a| a.username }
166
+ domain.clear_admins
158
167
 
168
+ admin_names.each do |name|
169
+ next unless Admin.exist?(name)
170
+ admin = Admin.find(name)
171
+ admin.destroy or raise "Could not destroy Admin" if admin.domains.empty?
172
+ end
159
173
  domain.destroy or raise "Could not destroy Domain"
160
174
  end
161
175
 
@@ -164,7 +178,7 @@ module PostfixAdmin
164
178
  raise Error, "Could not find admin #{user_name}"
165
179
  end
166
180
  admin = Admin.find(user_name)
167
- admin.domain_admins.destroy or raise "Could not destroy DomainAdmin"
181
+ admin.clear_domains
168
182
  admin.destroy or raise "Could not destroy Admin"
169
183
  end
170
184
 
@@ -177,12 +191,16 @@ module PostfixAdmin
177
191
  Alias.all(:address => address).destroy or raise "Could not destroy Alias"
178
192
  end
179
193
 
180
- def delete_unnecessary_admins
181
- Admin.unnecessary.destroy or raise "Could not destroy Admin"
182
- end
183
-
184
194
  def address_split(address)
185
195
  address.split('@')
186
196
  end
197
+
198
+ private
199
+
200
+ def admin_domain_check(user_name, domain_name)
201
+ raise Error, "#{user_name} is not resistered as admin." unless Admin.exist?(user_name)
202
+ raise Error, "Could not find domain #{domain_name}" unless Domain.exist?(domain_name)
203
+ end
204
+
187
205
  end
188
206
  end
@@ -3,21 +3,36 @@ require 'postfix_admin'
3
3
 
4
4
  module PostfixAdmin
5
5
  class CLI
6
- CONFIG_FILE = '~/.postfix_admin.conf'
6
+ @config_file = '~/.postfix_admin.conf'
7
7
  MIN_NUM_PASSWORD_CHARACTER = 5
8
8
 
9
9
  def initialize
10
10
  @config = load_config
11
- @base = PostfixAdmin::Base.new(@config)
11
+ @base = Base.new(@config)
12
12
  end
13
13
 
14
- def show(domain)
15
- show_summary(domain)
14
+ def self.config_file
15
+ @config_file
16
+ end
17
+
18
+ def self.config_file=(value)
19
+ @config_file = value
20
+ end
16
21
 
17
- if domain
18
- show_admin(domain)
19
- show_address(domain)
20
- show_alias(domain)
22
+ def show(name)
23
+ name = name.downcase if name
24
+
25
+ if name =~ /@/
26
+ show_account(name)
27
+ return
28
+ end
29
+
30
+ show_summary(name)
31
+
32
+ if name
33
+ show_admin(name)
34
+ show_address(name)
35
+ show_alias(name)
21
36
  else
22
37
  show_domain
23
38
  show_admin
@@ -27,6 +42,7 @@ module PostfixAdmin
27
42
  def show_summary(domain_name=nil)
28
43
  title = "Summary"
29
44
  if domain_name
45
+ domain_name = domain_name.downcase
30
46
  domain_check(domain_name)
31
47
  title = "Summary of #{domain_name}"
32
48
  end
@@ -34,9 +50,9 @@ module PostfixAdmin
34
50
  report(title) do
35
51
  if domain_name
36
52
  domain = Domain.find(domain_name)
37
- puts "Mailboxes : %4d" % domain.mailboxes.count
38
- puts "Aliases : %4d" % domain.num_total_aliases
39
- puts "Quota : %4d MB" % domain.maxquota
53
+ puts "Mailboxes : %4d / %4s" % [domain.mailboxes.count, max_str(domain.maxmailboxes)]
54
+ puts "Aliases : %4d / %4s" % [domain.num_total_aliases, max_str(domain.maxaliases)]
55
+ puts "Max Quota : %4d MB" % domain.maxquota
40
56
  else
41
57
  puts "Domains : %4d" % Domain.all_without_special_domain.count
42
58
  puts "Admins : %4d" % Admin.count
@@ -46,38 +62,50 @@ module PostfixAdmin
46
62
  end
47
63
  end
48
64
 
49
- def setup_domain(domain, password)
50
- admin = "admin@#{domain}"
51
- add_domain(domain)
65
+ def setup_domain(domain_name, password)
66
+ admin = "admin@#{domain_name}"
67
+ add_domain(domain_name)
52
68
  add_admin(admin, password)
53
- add_admin_domain(admin, domain)
69
+ add_admin_domain(admin, domain_name)
70
+ end
71
+
72
+ def show_account(user_name)
73
+ account_check(user_name)
74
+ mailbox = Mailbox.find(user_name)
75
+ mail_alias = Alias.find(user_name)
76
+
77
+ report("Mailbox") do
78
+ puts "Address : %s" % mailbox.username
79
+ puts "Password : %s" % mailbox.password
80
+ puts "Quota : %d MB" % max_str(mailbox.quota / KB_TO_MB)
81
+ puts "Go to : %s" % mail_alias.goto
82
+ end
54
83
  end
55
84
 
56
85
  def show_domain
57
- index = " No. Domain Aliases Mailboxes Quota (MB)"
86
+ index = " No. Domain Aliases Mailboxes Quota (MB)"
58
87
  report('Domains', index) do
59
- if Domain.all_without_special_domain.count == 0
88
+ if Domain.all_without_special_domain.empty?
60
89
  puts " No domains"
61
- else
62
- Domain.all_without_special_domain.each_with_index do |d, i|
63
- puts "%4d %-20s %3d /%3d %3d /%3d %10d" %
64
- [i+1, d.domain_name, d.num_total_aliases, d.maxaliases,
65
- d.mailboxes.count, d.maxmailboxes, d.maxquota]
66
- end
90
+ next
91
+ end
92
+
93
+ Domain.all_without_special_domain.each_with_index do |d, i|
94
+ puts "%4d %-30s %3d /%3s %3d /%3s %10d" %
95
+ [i+1, d.domain_name, d.num_total_aliases, max_str(d.maxaliases),
96
+ d.mailboxes.count, max_str(d.maxmailboxes), d.maxquota]
67
97
  end
68
98
  end
99
+
69
100
  end
70
101
 
71
- def add_domain(domain)
72
- if @base.add_domain(domain)
73
- puts %Q!"#{domain}" was successfully registered.!
74
- end
102
+ def add_domain(domain_name)
103
+ @base.add_domain(domain_name)
104
+ puts_registered(domain_name, "a domain")
75
105
  end
76
106
 
77
107
  def super_admin(user_name, disable)
78
- unless Admin.exist?(user_name)
79
- raise Error, "Could not find admin #{user_name}"
80
- end
108
+ admin_check(user_name)
81
109
 
82
110
  if disable
83
111
  Admin.find(user_name).super_admin = false
@@ -96,124 +124,158 @@ module PostfixAdmin
96
124
  change_password(Mailbox, user_name, password)
97
125
  end
98
126
 
99
- def delete_domain(domain)
100
- if @base.delete_domain(domain)
101
- puts_deleted(domain)
102
- end
127
+ def edit_domain(domain_name, options)
128
+ domain_check(domain_name)
129
+ domain = Domain.find(domain_name)
130
+ domain.maxaliases = options[:aliases] if options[:aliases]
131
+ domain.maxmailboxes = options[:mailboxes] if options[:mailboxes]
132
+ domain.maxquota = options[:maxquota] if options[:maxquota]
133
+ domain.save or raise "Could not save Domain"
134
+
135
+ puts "Successfully updated #{domain_name}"
136
+ show_summary(domain_name)
137
+ end
138
+
139
+ def delete_domain(domain_name)
140
+ @base.delete_domain(domain_name)
141
+ puts_deleted(domain_name)
103
142
  end
104
143
 
105
- def show_admin(domain=nil)
106
- admins = domain ? Admin.select{|a| a.has_domain?(domain)} : Admin.all
107
- index = " No. Admin Domains Password"
144
+ def show_admin(domain_name=nil)
145
+ admins = domain_name ? Admin.select{|a| a.has_domain?(domain_name)} : Admin.all
146
+ index = " No. Admin Domains Password"
108
147
  report("Admins", index) do
109
- if admins.count == 0
148
+ if admins.empty?
110
149
  puts " No admins"
111
- else
112
- admins.each_with_index do |a, i|
113
- domains = a.super_admin? ? 'Super admin' : a.domains.count
114
- puts "%4d %-30s %11s %s" % [i+1, a.username, domains, a.password]
115
- end
150
+ next
151
+ end
152
+
153
+ admins.each_with_index do |a, i|
154
+ domains = a.super_admin? ? 'Super admin' : a.domains.count
155
+ puts "%4d %-40s %11s %s" % [i+1, a.username, domains, a.password]
116
156
  end
117
157
  end
118
158
 
119
159
  end
120
160
 
121
- def show_address(domain)
122
- domain_check(domain)
161
+ def show_address(domain_name)
162
+ domain_check(domain_name)
123
163
 
124
- mailboxes = Domain.find(domain).mailboxes
125
- index = " No. Email Quota (MB) Password"
164
+ mailboxes = Domain.find(domain_name).mailboxes
165
+ index = " No. Email Quota (MB) Password Maildir"
126
166
  report("Addresses", index) do
127
- if mailboxes.count == 0
167
+ if mailboxes.empty?
128
168
  puts " No addresses"
129
- else
130
- mailboxes.each_with_index do |m, i|
131
- quota = m.quota.to_f/1024000.0
132
- puts "%4d %-30s %10.1f %s" % [i+1, m.username, quota, m.password]
133
- end
169
+ next
170
+ end
171
+
172
+ mailboxes.each_with_index do |m, i|
173
+ quota = m.quota.to_f/ KB_TO_MB.to_f
174
+ puts "%4d %-40s %10s %-15s %s" % [i+1, m.username, max_str(quota.to_i), m.password, m.maildir]
134
175
  end
135
176
  end
136
177
 
137
178
  end
138
179
 
139
- def show_alias(domain)
140
- domain_check(domain)
180
+ def show_alias(domain_name)
181
+ domain_check(domain_name)
141
182
 
142
- aliases = Domain.find(domain).aliases.find_all do |mail_alias|
143
- mail_alias.address != mail_alias.goto
144
- end
183
+ forwards, aliases = Domain.find(domain_name).aliases.partition{|a| a.mailbox?}
145
184
 
146
- index = " No. Address Go to"
147
- report("Aliases", index) do
148
- if aliases.count == 0
149
- puts " No aliases"
150
- else
151
- aliases.each_with_index do |a, i|
152
- puts "%4d %-30s %s" % [i+1, a.address, a.goto]
153
- end
154
- end
185
+ forwards.delete_if do |f|
186
+ f.address == f.goto
155
187
  end
156
188
 
189
+ show_alias_base("Forwards", forwards)
190
+ show_alias_base("Aliases", aliases)
157
191
  end
158
192
 
159
193
  def show_admin_domain(user_name)
160
194
  admin = Admin.find(user_name)
161
- if admin.domains.count == 0
195
+ if admin.domains.empty?
162
196
  puts "\nNo domain in database"
163
197
  return
164
198
  end
199
+
165
200
  report("Domains (#{user_name})", " No. Domain") do
166
201
  admin.domains.each_with_index do |d, i|
167
- puts "%4d %-20s" % [i+1, d.domain_name]
202
+ puts "%4d %-30s" % [i+1, d.domain_name]
168
203
  end
169
204
  end
170
205
  end
171
206
 
172
207
  def add_admin(user_name, password, super_admin=false)
173
208
  validate_password(password)
174
- if @base.add_admin(user_name, password)
175
- if super_admin
176
- Admin.find(user_name).super_admin = true
177
- puts_registered(user_name, "a super admin")
178
- else
179
- puts_registered(user_name, "an admin")
180
- end
209
+ @base.add_admin(user_name, password)
210
+ if super_admin
211
+ Admin.find(user_name).super_admin = true
212
+ puts_registered(user_name, "a super admin")
213
+ else
214
+ puts_registered(user_name, "an admin")
181
215
  end
182
216
  end
183
217
 
184
- def add_admin_domain(user_name, domain)
185
- if @base.add_admin_domain(user_name, domain)
186
- puts_registered(domain, "a domain of #{user_name}")
187
- end
218
+ def add_admin_domain(user_name, domain_name)
219
+ @base.add_admin_domain(user_name, domain_name)
220
+ puts_registered(domain_name, "a domain of #{user_name}")
221
+ end
222
+
223
+ def delete_admin_domain(user_name, domain_name)
224
+ @base.delete_admin_domain(user_name, domain_name)
225
+ puts "#{domain_name} was successfully deleted from #{user_name}"
188
226
  end
189
227
 
190
228
  def add_account(address, password)
191
229
  validate_password(password)
192
- if @base.add_account(address, password)
193
- puts_registered(address, "an account")
194
- end
230
+ @base.add_account(address, password)
231
+ puts_registered(address, "an account")
195
232
  end
196
233
 
197
234
  def add_alias(address, goto)
198
- if @base.add_alias(address, goto)
199
- puts_registered("#{address}: #{goto}", "an alias")
200
- end
235
+ @base.add_alias(address, goto)
236
+ puts_registered("#{address}: #{goto}", "an alias")
237
+ end
238
+
239
+ def edit_account(address, options)
240
+ mailbox_check(address)
241
+ mailbox = Mailbox.find(address)
242
+ mailbox.quota = options[:quota] * KB_TO_MB if options[:quota]
243
+ mailbox.save or raise "Could not save Mailbox"
244
+
245
+ puts "Successfully updated #{address}"
246
+ show_account(address)
201
247
  end
202
248
 
203
249
  def delete_alias(address)
204
- puts_deleted(address) if @base.delete_alias(address)
250
+ @base.delete_alias(address)
251
+ puts_deleted(address)
205
252
  end
206
253
 
207
254
  def delete_admin(user_name)
208
- puts_deleted(user_name) if @base.delete_admin(user_name)
255
+ @base.delete_admin(user_name)
256
+ puts_deleted(user_name)
209
257
  end
210
258
 
211
259
  def delete_account(address)
212
- puts_deleted(address) if @base.delete_account(address)
260
+ @base.delete_account(address)
261
+ puts_deleted(address)
213
262
  end
214
263
 
215
264
  private
216
265
 
266
+ def show_alias_base(title, addresses)
267
+ report(title, " No. Address Go to") do
268
+ if addresses.empty?
269
+ puts " No #{title.downcase}"
270
+ next
271
+ end
272
+
273
+ addresses.each_with_index do |a, i|
274
+ puts "%4d %-40s %s" % [i+1, a.address, a.goto]
275
+ end
276
+ end
277
+ end
278
+
217
279
  def puts_registered(name, as_str)
218
280
  puts %Q!"#{name}" was successfully registered as #{as_str}.!
219
281
  end
@@ -223,7 +285,7 @@ module PostfixAdmin
223
285
  end
224
286
 
225
287
  def config_file
226
- config_file = File.expand_path(CONFIG_FILE)
288
+ config_file = File.expand_path(CLI.config_file)
227
289
  end
228
290
 
229
291
  def load_config
@@ -237,15 +299,15 @@ module PostfixAdmin
237
299
  end
238
300
  end
239
301
 
240
- def create_config(config_file)
241
- open(config_file, 'w') do |f|
242
- f.write PostfixAdmin::Base::DEFAULT_CONFIG.to_yaml
302
+ def create_config(file)
303
+ open(file, 'w') do |f|
304
+ f.write Base::DEFAULT_CONFIG.to_yaml
243
305
  end
244
- File.chmod(0600, config_file)
306
+ File.chmod(0600, file)
245
307
  end
246
308
 
247
309
  def print_line
248
- puts "-"*100
310
+ puts "-"*120
249
311
  end
250
312
 
251
313
  def report(title, index=nil)
@@ -257,12 +319,29 @@ module PostfixAdmin
257
319
  print_line
258
320
  end
259
321
 
260
- def domain_check(domain_name)
261
- unless Domain.exist?(domain_name)
262
- raise Error, %Q!Could not find domain "#{domain_name}"!
322
+ def account_check(user_name)
323
+ unless Mailbox.exist?(user_name) && Alias.exist?(user_name)
324
+ raise Error, %Q!Could not find account "#{user_name}"!
263
325
  end
264
326
  end
265
327
 
328
+ def domain_check(domain_name)
329
+ klass_check(Domain, domain_name)
330
+ end
331
+
332
+ def mailbox_check(address)
333
+ klass_check(Mailbox, address)
334
+ end
335
+
336
+ def admin_check(user_name)
337
+ klass_check(Admin, user_name)
338
+ end
339
+
340
+ def klass_check(klass, name)
341
+ object_name = klass.name.gsub(/PostfixAdmin::/, '').downcase
342
+ raise Error, %Q!Could not find #{object_name} "#{name}"! unless klass.exist?(name)
343
+ end
344
+
266
345
  def validate_password(password)
267
346
  if password.size < MIN_NUM_PASSWORD_CHARACTER
268
347
  raise ArgumentError, "Password is too short. It should be larger than #{MIN_NUM_PASSWORD_CHARACTER}"
@@ -270,9 +349,8 @@ module PostfixAdmin
270
349
  end
271
350
 
272
351
  def change_password(klass, user_name, password)
273
- unless klass.exist?(user_name)
274
- raise Error, "Could not find #{user_name}"
275
- end
352
+ raise Error, "Could not find #{user_name}" unless klass.exist?(user_name)
353
+
276
354
  validate_password(password)
277
355
 
278
356
  obj = klass.find(user_name)
@@ -284,5 +362,16 @@ module PostfixAdmin
284
362
  end
285
363
  end
286
364
 
365
+ def max_str(value)
366
+ case value
367
+ when 0
368
+ '--'
369
+ when -1
370
+ '0'
371
+ else
372
+ value.to_s
373
+ end
374
+ end
375
+
287
376
  end
288
377
  end