line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# -*- perl -*- |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
677
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
893
|
use Net::LDAP (); |
|
1
|
|
|
|
|
239261
|
|
|
1
|
|
|
|
|
38
|
|
6
|
1
|
|
|
1
|
|
1543
|
use Net::Netmask (); |
|
1
|
|
|
|
|
15833
|
|
|
1
|
|
|
|
|
88
|
|
7
|
1
|
|
|
1
|
|
15
|
use Socket (); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
19
|
|
8
|
1
|
|
|
1
|
|
718
|
use Wizard (); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use Wizard::State (); |
10
|
|
|
|
|
|
|
use Wizard::SaveAble (); |
11
|
|
|
|
|
|
|
use Wizard::SaveAble::LDAP (); |
12
|
|
|
|
|
|
|
use Wizard::LDAP (); |
13
|
|
|
|
|
|
|
use Wizard::LDAP::Net(); |
14
|
|
|
|
|
|
|
use Wizard::LDAP::Config (); |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
@Wizard::LDAP::Host::ISA = qw(Wizard::LDAP::Net); |
17
|
|
|
|
|
|
|
$Wizard::LDAP::Host::VERSION = '0.01'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
package Wizard::LDAP::Host; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub init { |
22
|
|
|
|
|
|
|
my $self = shift; |
23
|
|
|
|
|
|
|
return ($self->SUPER::init(1)) unless shift; |
24
|
|
|
|
|
|
|
my $item = $self->{'host'} || die "Missing host"; |
25
|
|
|
|
|
|
|
($self->SUPER::init(1), $item); |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub ShowMe { |
30
|
|
|
|
|
|
|
my($self, $wiz, $prefs, $host) = @_; |
31
|
|
|
|
|
|
|
(['Wizard::Elem::Title', |
32
|
|
|
|
|
|
|
'value' => $host->CreateMe() ? |
33
|
|
|
|
|
|
|
'LDAP Wizard: Create a new host' : |
34
|
|
|
|
|
|
|
'LDAP Wizard: Edit an existing host'], |
35
|
|
|
|
|
|
|
['Wizard::Elem::Text', 'name' => 'ldap-host-hostname', |
36
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-hostname'}, |
37
|
|
|
|
|
|
|
'descr' => 'Name of Host'], |
38
|
|
|
|
|
|
|
['Wizard::Elem::Text', 'name' => 'ldap-host-dnsname', |
39
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-dnsname'}, |
40
|
|
|
|
|
|
|
'descr' => 'DNS entry of the host'], |
41
|
|
|
|
|
|
|
['Wizard::Elem::Text', 'name' => 'ldap-host-ip', |
42
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-ip'}, |
43
|
|
|
|
|
|
|
'descr' => 'IP adress of the host'], |
44
|
|
|
|
|
|
|
['Wizard::Elem::Text', 'name' => 'ldap-host-mac', |
45
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-mac'}, |
46
|
|
|
|
|
|
|
'descr' => 'MAC address of host'], |
47
|
|
|
|
|
|
|
['Wizard::Elem::Text', 'name' => 'ldap-host-timezone', |
48
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-timezone'}, |
49
|
|
|
|
|
|
|
'descr' => 'Timezone of host'], |
50
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'name' => 'Action_HostSave', |
51
|
|
|
|
|
|
|
'value' => 'Save these settings', 'id' => 1], |
52
|
|
|
|
|
|
|
['Wizard::Elem::BR'], |
53
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'name' => 'Action_Reset', |
54
|
|
|
|
|
|
|
'value' => 'Return to Host menu', 'id' => 97], |
55
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'name' => 'Wizard::LDAP::Net::Action_Reset', |
56
|
|
|
|
|
|
|
'value' => 'Return to Net menu', 'id' => 98], |
57
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'name' => 'Wizard::LDAP::Action_Reset', |
58
|
|
|
|
|
|
|
'value' => 'Return to top menu', 'id' => 99]); |
59
|
|
|
|
|
|
|
} |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub Action_Enter { |
63
|
|
|
|
|
|
|
my($self, $wiz) = @_; |
64
|
|
|
|
|
|
|
my($prefs, $admin) = $self->SUPER::init(); |
65
|
|
|
|
|
|
|
my $dn = $wiz->param('ldap-net') || die "Missing net name"; |
66
|
|
|
|
|
|
|
$dn = 'network=' . $dn . ', ' . $prefs->{'ldap-prefs-netbase'}; |
67
|
|
|
|
|
|
|
my $net = $self->SUPER::Load($wiz, $prefs, $admin, $dn); |
68
|
|
|
|
|
|
|
$self->Action_Reset($wiz); |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub Action_Reset { |
72
|
|
|
|
|
|
|
my($self, $wiz) = @_; |
73
|
|
|
|
|
|
|
$self->init(); |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
delete $self->{'host'}; |
76
|
|
|
|
|
|
|
$self->Store($wiz); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# Return the initial menu. |
79
|
|
|
|
|
|
|
(['Wizard::Elem::Title', 'value' => 'LDAP Wizard Host Menu'], |
80
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Create a new host', |
81
|
|
|
|
|
|
|
'name' => 'Action_CreateHost', |
82
|
|
|
|
|
|
|
'id' => 1], |
83
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Modify an existing host', |
84
|
|
|
|
|
|
|
'name' => 'Action_ModifyHost', |
85
|
|
|
|
|
|
|
'id' => 3], |
86
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Delete an existing host', |
87
|
|
|
|
|
|
|
'name' => 'Action_DeleteHost', |
88
|
|
|
|
|
|
|
'id' => 4], |
89
|
|
|
|
|
|
|
['Wizard::Elem::BR'], |
90
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Return to Top Menu', |
91
|
|
|
|
|
|
|
'name' => 'Wizard::LDAP::Action_Reset', |
92
|
|
|
|
|
|
|
'id' => 97], |
93
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Return to Net Menu', |
94
|
|
|
|
|
|
|
'name' => 'Wizard::LDAP::Net::Action_Reset', |
95
|
|
|
|
|
|
|
'id' => 98], |
96
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Exit LDAP Wizard', |
97
|
|
|
|
|
|
|
'id' => 99]); |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub Action_CreateHost { |
101
|
|
|
|
|
|
|
my($self, $wiz) = @_; |
102
|
|
|
|
|
|
|
my ($prefs, $admin, $net) = $self->init(); |
103
|
|
|
|
|
|
|
my $host = Wizard::SaveAble::LDAP->new('adminDN' => $admin->{'ldap-admin-dn'}, |
104
|
|
|
|
|
|
|
'adminPassword' => $admin->{'ldap-admin-password'}, |
105
|
|
|
|
|
|
|
'prefix' => 'ldap-host-', |
106
|
|
|
|
|
|
|
'serverip' => $prefs->{'ldap-prefs-serverip'}, |
107
|
|
|
|
|
|
|
'serverport' => $prefs->{'ldap-prefs-serverport'}, |
108
|
|
|
|
|
|
|
); |
109
|
|
|
|
|
|
|
my $base = 'network=' . $net->{'ldap-net-netname'} . ', ' |
110
|
|
|
|
|
|
|
. $prefs->{'ldap-prefs-netbase'}; |
111
|
|
|
|
|
|
|
my $mesg = $self->ItemList($prefs, $admin, $base, 'hostName'); |
112
|
|
|
|
|
|
|
my $ip = {}; my $dns = {}; my $hname; |
113
|
|
|
|
|
|
|
foreach my $entry ($mesg->entries) { |
114
|
|
|
|
|
|
|
my $hname = $entry->get('hostname'); |
115
|
|
|
|
|
|
|
my @ips = $entry->get('ip'); my @dnss = $entry->get('dnsname'); |
116
|
|
|
|
|
|
|
map { $ip->{$_} = $hname; } @ips; |
117
|
|
|
|
|
|
|
map { $dns->{$_} = $hname; } @dnss; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
my $domain = $net->{'ldap-net-domain'}; |
120
|
|
|
|
|
|
|
my $ripb = Socket::inet_aton($net->{'ldap-net-reservedipbegin'}); |
121
|
|
|
|
|
|
|
my $ripe = Socket::inet_aton($net->{'ldap-net-reservedipend'}); |
122
|
|
|
|
|
|
|
my $nm = new Net::Netmask($net->{'ldap-net-mask'}); |
123
|
|
|
|
|
|
|
my ($nip, $nipt); |
124
|
|
|
|
|
|
|
my @allips = $nm->enumerate(); shift @allips; pop @allips; |
125
|
|
|
|
|
|
|
foreach $nip (@allips) { |
126
|
|
|
|
|
|
|
if($ripb && $ripe) { |
127
|
|
|
|
|
|
|
$nipt = Socket::inet_aton($nip); |
128
|
|
|
|
|
|
|
next if (($nipt ge $ripb) && ($nipt le $ripe)); |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
unless(exists($ip->{$nip})) { |
131
|
|
|
|
|
|
|
$host->{'ldap-host-ip'} = $nip; |
132
|
|
|
|
|
|
|
last; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
my $i = 0; |
136
|
|
|
|
|
|
|
while(exists($dns->{"pc" . (++$i) . ".$domain"})) {}; |
137
|
|
|
|
|
|
|
$host->{'ldap-host-dnsname'} = "pc" . $i . ".$domain"; |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
$host->CreateMe(1); |
140
|
|
|
|
|
|
|
$self->{'host'} = $host; |
141
|
|
|
|
|
|
|
$self->Store($wiz); |
142
|
|
|
|
|
|
|
$self->ShowMe($wiz, $prefs, $host); |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub Action_HostSave { |
146
|
|
|
|
|
|
|
my($self, $wiz) = @_; |
147
|
|
|
|
|
|
|
my ($prefs, $admin, $net, $host) = $self->init(1); |
148
|
|
|
|
|
|
|
my $base = "network=" . $net->{'ldap-net-netname'} . ', ' . $prefs->{'ldap-prefs-netbase'}; |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
foreach my $opt ($wiz->param()) { |
151
|
|
|
|
|
|
|
$host->{$opt} = $wiz->param($opt) |
152
|
|
|
|
|
|
|
if (($opt =~ /^ldap\-host/) && (defined($wiz->param($opt)))); |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# Verify settings |
156
|
|
|
|
|
|
|
my $errors = ''; |
157
|
|
|
|
|
|
|
my $name = $host->{'ldap-host-hostname'} |
158
|
|
|
|
|
|
|
or ($errors .= "Missing host name.\n"); |
159
|
|
|
|
|
|
|
my $dns = $host->{'ldap-host-dnsname'} |
160
|
|
|
|
|
|
|
or ($errors .= "Missing host dns name.\n"); |
161
|
|
|
|
|
|
|
my $ip = $host->{'ldap-host-ip'} |
162
|
|
|
|
|
|
|
or ($errors .= "Missing host ip.\n"); |
163
|
|
|
|
|
|
|
my $mac = $host->{'ldap-host-mac'}; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
$errors .= "Invalid dnsname $dns.\n" |
166
|
|
|
|
|
|
|
if($dns !~ /^[\w\-]+(\.[\w\-]+)*(\,\s*[\w\-]+(\.[\w\-]+)*)*$/); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
if($ip) { |
169
|
|
|
|
|
|
|
my $ripb = Socket::inet_aton($net->{'ldap-net-reservedipbegin'}); |
170
|
|
|
|
|
|
|
my $ripe = Socket::inet_aton($net->{'ldap-net-reservedipend'}); |
171
|
|
|
|
|
|
|
foreach my $nip (split(/\,\s*/, $ip)) { |
172
|
|
|
|
|
|
|
if(!(Socket::inet_aton($nip))) { |
173
|
|
|
|
|
|
|
$errors .= "Invalid ip address $nip.\n"; |
174
|
|
|
|
|
|
|
} else { |
175
|
|
|
|
|
|
|
# my $nm = new Net::Netmask($net->{'ldap-net-mask'}); |
176
|
|
|
|
|
|
|
# $errors .= "IP address $nip does not match netmask " |
177
|
|
|
|
|
|
|
# . $net->{'ldap-net-mask'} . ".\n" unless($nm->match($nip)); |
178
|
|
|
|
|
|
|
my $tip = Socket::inet_aton($nip); |
179
|
|
|
|
|
|
|
$errors .= "IP address $nip is in the reserved IP block.\n" |
180
|
|
|
|
|
|
|
if (($ripb && $ripe) && (($tip ge $ripb) && |
181
|
|
|
|
|
|
|
($tip le $ripe))); |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
if($mac) { |
187
|
|
|
|
|
|
|
$errors .= "Invalid MAC address $mac.\n" if ($mac !~ /^([\dA-Fa-f]{2}\:){5}[\dA-Fa-f]{2}$/); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
$host->{'ldap-host-objectClass'} = 'host'; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
die $errors if $errors; |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
$host->AttrScalar2Ref('ip', 'dnsname'); |
195
|
|
|
|
|
|
|
$host->DN('host=' . $name . ', ' . $base); |
196
|
|
|
|
|
|
|
$host->Modified(1); |
197
|
|
|
|
|
|
|
$self->Store($wiz, 1); |
198
|
|
|
|
|
|
|
$self->OnChange('host'); |
199
|
|
|
|
|
|
|
$self->Action_Reset($wiz); |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub Action_ModifyHost { |
204
|
|
|
|
|
|
|
my $self = shift; my $wiz = shift; |
205
|
|
|
|
|
|
|
my $button = shift || 'Modify Host'; |
206
|
|
|
|
|
|
|
my $action = shift || 'Action_EditHost'; |
207
|
|
|
|
|
|
|
my ($prefs, $admin, $net) = $self->init(); |
208
|
|
|
|
|
|
|
my $base = "network=" . $net->{'ldap-net-netname'} . ', ' . $prefs->{'ldap-prefs-netbase'}; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
my @items = $self->ItemList($prefs, $admin, $base, 'hostname'); |
211
|
|
|
|
|
|
|
return $self->Action_Reset($wiz) unless @items; |
212
|
|
|
|
|
|
|
@items = sort @items; |
213
|
|
|
|
|
|
|
if(@items == 1) { |
214
|
|
|
|
|
|
|
$wiz->param('ldap-host', $items[0]); |
215
|
|
|
|
|
|
|
return $self->$action($wiz); |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
# Return the initial menu. |
218
|
|
|
|
|
|
|
(['Wizard::Elem::Title', 'value' => "LDAP Wizard Host Selection"], |
219
|
|
|
|
|
|
|
['Wizard::Elem::Select', 'options' => \@items, 'name' => 'ldap-host', |
220
|
|
|
|
|
|
|
'descr' => 'Select a host'], |
221
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => $button, 'name' => $action, |
222
|
|
|
|
|
|
|
'id' => 1]); |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub Load { |
226
|
|
|
|
|
|
|
my($self, $wiz, $prefs, $admin, $dn) = @_; |
227
|
|
|
|
|
|
|
my $host = Wizard::SaveAble::LDAP->new('adminDN' => $admin->{'ldap-admin-dn'}, |
228
|
|
|
|
|
|
|
'adminPassword' => $admin->{'ldap-admin-password'}, |
229
|
|
|
|
|
|
|
'prefix' => 'ldap-host-', |
230
|
|
|
|
|
|
|
'serverip' => $prefs->{'ldap-prefs-serverip'}, |
231
|
|
|
|
|
|
|
'serverport' => $prefs->{'ldap-prefs-serverport'}, |
232
|
|
|
|
|
|
|
'dn' => $dn, 'load' => 1); |
233
|
|
|
|
|
|
|
$host->AttrRef2Scalar('ip', 'dnsname'); |
234
|
|
|
|
|
|
|
$host->DN($dn); |
235
|
|
|
|
|
|
|
$self->{'host'} = $host; |
236
|
|
|
|
|
|
|
$self->Store($wiz); |
237
|
|
|
|
|
|
|
$host; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub Action_EditHost { |
242
|
|
|
|
|
|
|
my($self, $wiz) = @_; |
243
|
|
|
|
|
|
|
my($prefs, $admin, $net) = $self->init(); |
244
|
|
|
|
|
|
|
my $host = $wiz->param('ldap-host') || die "Missing host name."; |
245
|
|
|
|
|
|
|
my $dn = "host=$host, network=" . $net->{'ldap-net-netname'} . ', ' . $prefs->{'ldap-prefs-netbase'}; |
246
|
|
|
|
|
|
|
$self->ShowMe($wiz, $prefs, $self->Load($wiz, $prefs, $admin, $dn)); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub Action_DeleteHost { |
250
|
|
|
|
|
|
|
shift->Action_ModifyHost(shift, 'Delete Host', 'Action_DeleteHost2'); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub Action_DeleteHost2 { |
254
|
|
|
|
|
|
|
my ($self, $wiz) = @_; |
255
|
|
|
|
|
|
|
my($prefs, $admin, $net) = $self->init(); |
256
|
|
|
|
|
|
|
my $hostname = $wiz->param('ldap-host') || die "Missing host."; |
257
|
|
|
|
|
|
|
my $dn = "host=$hostname, network=" . $net->{'ldap-net-netname'} . ', ' . $prefs->{'ldap-prefs-netbase'}; |
258
|
|
|
|
|
|
|
my $host = $self->Load($wiz, $prefs, $admin, $dn); |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
(['Wizard::Elem::Title', 'value' => 'Deleting an LDAP Host'], |
261
|
|
|
|
|
|
|
['Wizard::Elem::Data', 'descr' => 'Host name', |
262
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-hostname'}], |
263
|
|
|
|
|
|
|
['Wizard::Elem::Data', 'descr' => 'Host dnsname', |
264
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-dnsname'}], |
265
|
|
|
|
|
|
|
['Wizard::Elem::Data', 'descr' => 'Host ip', |
266
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-ip'}], |
267
|
|
|
|
|
|
|
['Wizard::Elem::Data', 'descr' => 'Host MAC address', |
268
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-mac'}], |
269
|
|
|
|
|
|
|
['Wizard::Elem::Data', 'descr' => 'Host timezone', |
270
|
|
|
|
|
|
|
'value' => $host->{'ldap-host-timezone'}], |
271
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Yes, delete it', |
272
|
|
|
|
|
|
|
'id' => 1, 'name' => 'Action_DeleteHost3'], |
273
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Return to Host Menu', |
274
|
|
|
|
|
|
|
'id' => 97, 'name' => 'Action_Reset'], |
275
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Return to Net Menu', |
276
|
|
|
|
|
|
|
'id' => 98, 'name' => 'Wizard::LDAP::Net::Action_Reset'], |
277
|
|
|
|
|
|
|
['Wizard::Elem::Submit', 'value' => 'Return to Top Menu', |
278
|
|
|
|
|
|
|
'id' => 99, 'name' => 'Wizard::LDAP::Action_Reset']); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub Action_DeleteHost3 { |
282
|
|
|
|
|
|
|
my($self, $wiz) = @_; |
283
|
|
|
|
|
|
|
my($prefs, $admin, $net, $host) = $self->init(1); |
284
|
|
|
|
|
|
|
$host->Delete(); |
285
|
|
|
|
|
|
|
$self->OnChange('host'); |
286
|
|
|
|
|
|
|
$self->Action_Reset($wiz); |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|