1 |
3 |
ahitrov@rambler.ru |
package Contenido::Section; |
2 |
|
|
|
3 |
|
|
# ---------------------------------------------------------------------------- |
4 |
|
|
# ����� ������. |
5 |
|
|
# ������ ��� ����� �� - ������� �����, ������ � ���� �������������� |
6 |
|
|
# ����������������. |
7 |
|
|
# ---------------------------------------------------------------------------- |
8 |
|
|
|
9 |
|
|
use strict; |
10 |
|
|
use warnings; |
11 |
|
|
use locale; |
12 |
|
|
|
13 |
|
|
use vars qw($VERSION $ROOT); |
14 |
|
|
$VERSION = '6.0'; |
15 |
|
|
|
16 |
|
|
use base 'Contenido::Object'; |
17 |
|
|
use Contenido::Globals; |
18 |
|
|
|
19 |
|
|
$ROOT = 1; # �������� ������ |
20 |
|
|
|
21 |
|
|
sub class_name { |
22 |
|
|
return '������'; |
23 |
|
|
} |
24 |
|
|
|
25 |
|
|
sub class_description { |
26 |
|
|
return '������ �� ���������'; |
27 |
|
|
} |
28 |
|
|
|
29 |
|
|
# DEFAULT ���� ���������� ������� |
30 |
|
|
sub class_table { |
31 |
|
|
return 'SQL::SectionTable'; |
32 |
|
|
} |
33 |
|
|
|
34 |
|
|
# ---------------------------------------------------------------------------- |
35 |
|
|
# �����������. ������� ����� ������ ������. |
36 |
|
|
# |
37 |
|
|
# ������ �������������: |
38 |
|
|
# Contenido::Section->new() |
39 |
|
|
# Contenido::Section->new($keeper) |
40 |
|
|
# Contenido::Section->new($keeper,$id) |
41 |
|
|
# Contenido::Section->new($keeper,$id,$pid) |
42 |
|
|
# ---------------------------------------------------------------------------- |
43 |
|
|
sub new { |
44 |
|
|
my ($proto, $keeper, $id, $pid) = @_; |
45 |
|
|
my $class = ref($proto) || $proto; |
46 |
|
|
my $self; |
47 |
|
|
|
48 |
|
|
if (defined($id) && ($id>0) && defined($keeper)) { |
49 |
|
|
$self=$keeper->get_section_by_id($id, class=>$class); |
50 |
|
|
} else { |
51 |
|
|
$self = {}; |
52 |
|
|
bless($self, $class); |
53 |
|
|
$self->init(); |
54 |
|
|
$self->keeper($keeper) if (defined($keeper)); |
55 |
|
|
$self->{class} = $class; |
56 |
|
|
$self->id($id) if (defined($id) && ($id > 0)); |
57 |
|
|
$self->pid($pid) if (defined($pid) && ($pid > 0)); |
58 |
|
|
} |
59 |
|
|
|
60 |
|
|
return $self; |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
sub _get_table { |
64 |
|
|
class_table()->new(); |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
#��������� ������ store |
68 |
|
|
sub store { |
69 |
|
|
my $self=shift; |
70 |
|
|
|
71 |
|
|
#��� ������������� ������ ������ ����� sorder |
72 |
|
|
unless ($self->{id}) { |
73 |
|
|
my ($sorder) = $self->keeper->SQL->selectrow_array("select max(sorder) from ".$self->class_table->db_table(), {}); |
74 |
|
|
$self->{sorder} = $sorder + 1; |
75 |
|
|
} |
76 |
|
|
|
77 |
|
|
return $self->SUPER::store(); |
78 |
|
|
} |
79 |
|
|
|
80 |
|
|
|
81 |
|
|
## ����������� �������� ��� ������ � ���������� ����������� ���������� |
82 |
|
|
sub add_properties { |
83 |
|
|
return ( |
84 |
|
|
{ # ������� "������ � �����������" |
85 |
|
|
'attr' => '_sorted', |
86 |
|
|
'type' => 'checkbox', |
87 |
|
|
'rusname' => '������ ���������� ����������', |
88 |
|
|
}, |
89 |
|
|
{ # ������� ���������� (������ id) |
90 |
|
|
'attr' => '_sorted_order', |
91 |
|
|
'type' => 'string', |
92 |
|
|
'rusname' => '������� ���������� � ������', |
93 |
|
|
'hidden' => 1 |
94 |
|
|
}, |
95 |
|
|
{ |
96 |
|
|
'attr' => 'default_document_class', |
97 |
|
|
'type' => 'string', |
98 |
|
|
'rusname' => '����� ���������� � ������, ������������ �� ���������', |
99 |
|
|
}, |
100 |
|
|
{ |
101 |
|
|
'attr' => 'default_table_class', |
102 |
|
|
'type' => 'string', |
103 |
|
|
'rusname' => '����� �������, ��������� ������� ����� �������� �� ���������', |
104 |
|
|
}, |
105 |
|
|
{ |
106 |
|
|
'attr' => 'order_by', |
107 |
|
|
'type' => 'string', |
108 |
|
|
'rusname' => '���������� ����������', |
109 |
|
|
}, |
110 |
|
|
{ |
111 |
|
|
'attr' => 'no_count', |
112 |
|
|
'type' => 'checkbox', |
113 |
|
|
'rusname' => '�� ������������� ��������� � ������� �������', |
114 |
|
|
}, |
115 |
|
|
{ |
116 |
|
|
'attr' => 'filters', |
117 |
|
|
'type' => 'struct', |
118 |
|
|
'rusname' => '�������������� ������� �������', |
119 |
|
|
}, |
120 |
|
|
); |
121 |
|
|
} |
122 |
|
|
|
123 |
|
|
# ����������� ��� �������� ��������� ������ |
124 |
|
|
sub root { |
125 |
|
|
return new(shift, shift, $ROOT); |
126 |
|
|
} |
127 |
|
|
|
128 |
|
|
|
129 |
|
|
# �������� ��� ������ parent |
130 |
|
|
sub parent { |
131 |
|
|
return shift->pid(@_); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
# ---------------------------------------------------------------------------- |
135 |
|
|
# �������� ������. ����� ��������� ���������� �������� - � ����� |
136 |
|
|
# �� �� ����� ������� (����� ���� �������). ���� ���� �������, �� ������ |
137 |
|
|
# �� ���������. �������� �� ������� �������� � ���� ������ �� ������������, |
138 |
|
|
# �� ������ ���������� �� ���� ���������. |
139 |
|
|
# ---------------------------------------------------------------------------- |
140 |
|
|
sub delete |
141 |
|
|
{ |
142 |
|
|
my $self = shift; |
143 |
|
|
do { $log->error("����� ->delete() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
144 |
|
|
do { $log->warning("����� ������ ->delete() ��� �������� �������������� ��� ��������"); return undef } unless ($self->{id}); |
145 |
|
|
|
146 |
|
|
# �������� ������� �����... |
147 |
|
|
my ($one_id) = $self->keeper->SQL->selectrow_array('select id from '.$self->class_table->db_table.' where pid = ?', {}, $self->id); |
148 |
|
|
if (defined($one_id) && ($one_id > 0)) { return "������ ������� ������, � ������� ���� ��������� ������\n"; }; |
149 |
|
|
|
150 |
|
|
$self->SUPER::delete(); |
151 |
|
|
|
152 |
|
|
return 1; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
|
156 |
|
|
|
157 |
|
|
# ---------------------------------------------------------------------------- |
158 |
|
|
# �����, ������������ ������ ������� (� ������� sorder ��� |
159 |
|
|
# ������� ������). � ��������� ���������� �������. |
160 |
|
|
# |
161 |
|
|
# ������ ������: |
162 |
|
|
# $section->childs([�������]); |
163 |
|
|
# ---------------------------------------------------------------------------- |
164 |
|
|
sub childs { |
165 |
|
|
my ($self, $depth) = @_; |
166 |
|
|
do { $log->error("����� ->childs() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
167 |
|
|
|
168 |
|
|
# ������� �� ��������� - 1 |
169 |
|
|
$depth ||= 1; |
170 |
|
|
|
171 |
|
|
my $SIDS = []; |
172 |
|
|
my $NEW_SIDS = [$self->id]; |
173 |
|
|
|
174 |
|
|
#���� �� ���������� ������ ������� � ���� ������� ����� ���� |
175 |
|
|
while ($depth>0) { |
176 |
|
|
$NEW_SIDS = $self->keeper->get_sections(s=>$NEW_SIDS, ids=>1, return_mode=>'array_ref', order_by=>'pid, sorder'); |
177 |
|
|
if (ref($NEW_SIDS) and @$NEW_SIDS) { |
178 |
|
|
push (@$SIDS, @$NEW_SIDS); |
179 |
|
|
} else { |
180 |
|
|
last; |
181 |
|
|
} |
182 |
|
|
$depth--; |
183 |
|
|
} |
184 |
|
|
return @$SIDS; |
185 |
|
|
} |
186 |
|
|
|
187 |
|
|
|
188 |
|
|
|
189 |
|
|
# ---------------------------------------------------------------------------- |
190 |
|
|
# ����� ��� ����������� ������ �����/���� �� ����������� (��������� |
191 |
|
|
# sorder)... |
192 |
|
|
# |
193 |
|
|
# ������ ������: |
194 |
|
|
# $section->move($direction); ����������� �������� ������� 'up'/'down' |
195 |
|
|
# ---------------------------------------------------------------------------- |
196 |
|
|
sub move { |
197 |
|
|
my ($self, $direction) = @_; |
198 |
|
|
do { $log->error("����� ->move() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
199 |
|
|
|
200 |
|
|
return undef if ($self->keeper->state->readonly()); |
201 |
|
|
|
202 |
|
|
my $keeper = $self->keeper; |
203 |
|
|
do { $log->error("� ������� ������ �� ���������� ������ �� ���� ������"); die } unless ref($keeper); |
204 |
|
|
do { $log->warning("����� ������ ->move() ��� �������� �������������� ������"); return undef } |
205 |
|
|
unless (exists($self->{id}) && ($self->{id} > 0)); |
206 |
|
|
do { $log->warning("����� ������ ->move() ��� �������� ������� ���������� (sorder)"); return undef } |
207 |
|
|
unless (exists($self->{sorder}) && ($self->{sorder} >= 0)); |
208 |
|
|
do { $log->warning("����� ������ ->childs() ��� �������� ��������"); return undef } unless (exists($self->{pid}) && ($self->{pid} >= 0)); |
209 |
|
|
|
210 |
|
|
$direction = lc($direction); |
211 |
|
|
if ( ($direction ne 'up') && ($direction ne 'down') ) { $log->warning("����������� ����������� ������ ������ ��������"); return undef }; |
212 |
|
|
|
213 |
|
|
|
214 |
|
|
$keeper->t_connect() || do { $keeper->error(); return undef; }; |
215 |
|
|
$keeper->TSQL->begin_work(); |
216 |
|
|
|
217 |
|
|
|
218 |
|
|
# ��������� �������� ������ ��� ������... |
219 |
|
|
my ($id_, $sorder_); |
220 |
|
|
if ($direction eq 'up') |
221 |
|
|
{ |
222 |
|
|
($id_, $sorder_) = $keeper->TSQL->selectrow_array("select id, sorder from ".$self->class_table->db_table." where sorder < ? and pid = ? order by sorder desc limit 1", {}, $self->{sorder}, $self->{pid}); |
223 |
|
|
} else { |
224 |
|
|
($id_, $sorder_) = $keeper->TSQL->selectrow_array("select id, sorder from ".$self->class_table->db_table." where sorder > ? and pid = ? order by sorder asc limit 1", {}, $self->{sorder}, $self->{pid}); |
225 |
|
|
} |
226 |
|
|
|
227 |
|
|
|
228 |
|
|
# ���������� �����... |
229 |
|
|
if ( defined($id_) && ($id_ > 0) && defined($sorder_) && ($sorder_ > 0) ) |
230 |
|
|
{ |
231 |
|
|
$keeper->TSQL->do("update ".$self->class_table->db_table." set sorder = ? where id = ?", {}, $sorder_, $self->{id}) |
232 |
|
|
|| return $keeper->t_abort(); |
233 |
|
|
$keeper->TSQL->do("update ".$self->class_table->db_table." set sorder = ? where id = ?", {}, $self->{sorder}, $id_) |
234 |
|
|
|| return $keeper->t_abort(); |
235 |
|
|
} else { |
236 |
|
|
$log->warning("�� ���� ���������� � ��������� (�� ������� �������� ��� ��� ���)"); return 2; |
237 |
|
|
} |
238 |
|
|
|
239 |
|
|
$keeper->t_finish(); |
240 |
|
|
$self->{sorder} = $sorder_; |
241 |
|
|
return 1; |
242 |
|
|
} |
243 |
|
|
|
244 |
|
|
|
245 |
|
|
|
246 |
|
|
# ---------------------------------------------------------------------------- |
247 |
|
|
# ����� ��� ����������� ��������� � id = $doc_id �����/���� |
248 |
|
|
# �� ������� ���������� (� �������� ������� ������)... |
249 |
|
|
# |
250 |
|
|
# ������ ������: |
251 |
|
|
# $doc->dmove($doc_id, $direction); ����������� �������� ������� 'up'/'down' |
252 |
|
|
# ---------------------------------------------------------------------------- |
253 |
|
|
sub dmove { |
254 |
|
|
my ($self, $doc_id, $direction) = @_; |
255 |
|
|
do { $log->error("����� ->dmove() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
256 |
|
|
|
257 |
|
|
return undef if ($self->keeper->state->readonly()); |
258 |
|
|
|
259 |
|
|
my $keeper = $self->keeper; |
260 |
|
|
do { $log->error("� ������� �� ���������� ������ �� ���� ������"); die } unless ref($keeper); |
261 |
|
|
do { $log->warning("����� ������ ->dmove() ��� �������� �������������� ������"); return undef } |
262 |
|
|
unless (exists($self->{id}) && ($self->{id} > 0)); |
263 |
|
|
|
264 |
|
|
$direction = lc($direction); |
265 |
|
|
if ( ($direction ne 'up') && ($direction ne 'down') ) { $log->warning("����������� ����������� ��������� ������ �������"); return undef }; |
266 |
|
|
|
267 |
|
|
my $sorder_; |
268 |
|
|
if ($self->_sorted()) { |
269 |
|
|
my @ids = $keeper->get_documents( ids =>1, s => $self->id(), ($self->default_document_class ? (class => $self->default_document_class) : ()), order => ['date', undef], light => 1); |
270 |
|
|
my %ids = map { $_ => 1 } @ids; |
271 |
|
|
unless ($self->{_sorted_order}) { |
272 |
|
|
$self->{_sorted_order} = join ',', @ids; |
273 |
|
|
} |
274 |
|
|
|
275 |
|
|
my @order = split(/,/, $self->{_sorted_order}); |
276 |
|
|
@order = grep { |
277 |
|
|
my $res; |
278 |
|
|
if (exists $ids{$_}) { |
279 |
|
|
$res = 1; |
280 |
|
|
delete $ids{$_}; |
281 |
|
|
} |
282 |
|
|
$res |
283 |
|
|
} @order; |
284 |
|
|
|
285 |
|
|
push @order, keys %ids; |
286 |
|
|
|
287 |
|
|
foreach my $i (0 .. $#order) { |
288 |
|
|
if ($order[$i] == $doc_id) { |
289 |
|
|
my $t; |
290 |
|
|
if ($direction eq 'up') { |
291 |
|
|
last if $i == 0; |
292 |
|
|
$t = $order[$i-1]; |
293 |
|
|
$order[$i-1] = $order[$i]; |
294 |
|
|
$order[$i] = $t; |
295 |
|
|
$sorder_ = $i - 1; |
296 |
|
|
last; |
297 |
|
|
} elsif ($direction eq 'down') { |
298 |
|
|
last if $i == $#order; |
299 |
|
|
$t = $order[$i+1]; |
300 |
|
|
$order[$i+1] = $order[$i]; |
301 |
|
|
$order[$i] = $t; |
302 |
|
|
$sorder_ = $i + 1; |
303 |
|
|
last; |
304 |
|
|
} |
305 |
|
|
} |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
$self->{_sorted_order} = join ',', @order; |
309 |
|
|
$self->store(); |
310 |
|
|
} else { |
311 |
|
|
$log->warning("dmove called for section without enabled sorted feature... $self->{id}/$self->{class}"); |
312 |
|
|
} |
313 |
|
|
|
314 |
|
|
$self->{sorder} = $sorder_; |
315 |
|
|
return 1; |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
|
319 |
|
|
|
320 |
|
|
|
321 |
|
|
# ---------------------------------------------------------------------------- |
322 |
|
|
# ����� ��� ���������� ���� ����� ����� ���������... ���������� |
323 |
|
|
# ������ ��������������� ������ �� ������� ������ �� $root_id ����� |
324 |
|
|
# �����. $root_id ����������� ������ ���� ���� �� �����������. � ��������� |
325 |
|
|
# ���������� ��� �������. ���� ������� �����, �� ������������ ������ �� |
326 |
|
|
# ������ ��������, ���� ���� ��� - �� ������ ������. |
327 |
|
|
# |
328 |
|
|
# ������ ������: |
329 |
|
|
# $section->trace($root_id) |
330 |
|
|
# ---------------------------------------------------------------------------- |
331 |
|
|
sub trace { |
332 |
|
|
my ($self, $root_id) = @_; |
333 |
|
|
do { $log->error("����� ->trace() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
334 |
|
|
|
335 |
|
|
do { $log->warning("����� ������ ->trace() ��� �������� �������������� ������"); return () } |
336 |
|
|
unless (exists($self->{id}) && ($self->{id} > 0)); |
337 |
|
|
$root_id ||= $ROOT; |
338 |
|
|
|
339 |
|
|
my $id_ = $self->{id}; |
340 |
|
|
my @SIDS = ($id_); |
341 |
|
|
my $sth = $self->keeper->SQL->prepare_cached("select pid from ".$self->class_table->db_table." where id = ?"); |
342 |
|
|
|
343 |
|
|
while ($id_ != $root_id) |
344 |
|
|
{ |
345 |
|
|
$sth->execute($id_); |
346 |
|
|
($id_) = $sth->fetchrow_array(); |
347 |
|
|
if (defined($id_) && ($id_ > 0)) |
348 |
|
|
{ |
349 |
|
|
unshift (@SIDS, $id_); |
350 |
|
|
} else { |
351 |
|
|
# �� �������� ����������� ����� �� ��������, � �� ����� �� �����... |
352 |
|
|
$sth->finish; |
353 |
|
|
return (); |
354 |
|
|
} |
355 |
|
|
} |
356 |
|
|
$sth->finish; |
357 |
|
|
return @SIDS; |
358 |
|
|
} |
359 |
|
|
|
360 |
|
|
|
361 |
|
|
# ---------------------------------------------------------------------------- |
362 |
|
|
# ������ |
363 |
|
|
# ���������� ������ ��������������� ���� ������� (��������� �� ���� �������) ������ ������ |
364 |
|
|
# ---------------------------------------------------------------------------- |
365 |
|
|
sub ancestors |
366 |
|
|
{ |
367 |
|
|
my $self = shift; |
368 |
|
|
do { $log->error("����� ->ancestors() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
369 |
|
|
|
370 |
|
|
my $keeper = $self->keeper; |
371 |
|
|
do { $log->error("� ������� ������ �� ���������� ������ �� ���� ������"); die } unless ref($keeper); |
372 |
|
|
|
373 |
|
|
do { $log->warning("����� ������ ->ancestors() ��� �������� �������������� ������"); return () } unless (exists($self->{id}) && ($self->{id} > 0)); |
374 |
|
|
|
375 |
|
|
my @ancestors = (); |
376 |
|
|
my $sectionid = $self->{id}; |
377 |
|
|
while ($sectionid) |
378 |
|
|
{ |
379 |
|
|
$sectionid = $keeper->SQL->selectrow_array("select pid from ".$self->class_table->db_table." where id = ?", {}, $sectionid); |
380 |
|
|
push @ancestors, $sectionid if defined $sectionid && $sectionid; |
381 |
|
|
} |
382 |
|
|
return @ancestors; |
383 |
|
|
} |
384 |
|
|
|
385 |
|
|
# ---------------------------------------------------------------------------- |
386 |
|
|
# ������� |
387 |
|
|
# ���������� ������ ��������������� ���� �������� (����� �� ���� �������) ������ ������ |
388 |
|
|
# ---------------------------------------------------------------------------- |
389 |
|
|
sub descendants |
390 |
|
|
{ |
391 |
|
|
my $self = shift; |
392 |
|
|
do { $log->error("����� ->descendants() ����� �������� ������ � ��������, �� �� �������"); die } unless ref($self); |
393 |
|
|
|
394 |
|
|
my $keeper = $self->keeper; |
395 |
|
|
do { $log->error("� ������� ������ �� ���������� ������ �� ���� ������"); die } unless ref($keeper); |
396 |
|
|
|
397 |
|
|
do { $log->warning("����� ������ ->descendants() ��� �������� �������������� ������"); return () } unless (exists($self->{id}) && ($self->{id} > 0)); |
398 |
|
|
|
399 |
|
|
my @descendants = (); |
400 |
|
|
my @ids = ($self->{id}); |
401 |
|
|
while (scalar @ids) |
402 |
|
|
{ |
403 |
|
|
my $sth = $keeper->SQL->prepare("select id from ".$self->class_table->db_table." where pid in (" . (join ", ", @ids) . ")"); |
404 |
|
|
$sth->execute; |
405 |
|
|
@ids = (); |
406 |
|
|
while (my ($id) = $sth->fetchrow_array) |
407 |
|
|
{ |
408 |
|
|
push @ids, $id; |
409 |
|
|
} |
410 |
|
|
$sth->finish(); |
411 |
|
|
push @descendants, @ids; |
412 |
|
|
last if !$sth->rows; |
413 |
|
|
} |
414 |
|
|
return @descendants; |
415 |
|
|
} |
416 |
|
|
|
417 |
|
|
# ------------------------------------------------------------------------------------------------- |
418 |
|
|
# ��������� �������... |
419 |
|
|
# ���������: |
420 |
|
|
# light => ����������� ������ |
421 |
|
|
# root => ������ ������ (�� ��������� - 1) |
422 |
|
|
# ------------------------------------------------------------------------------------------------- |
423 |
|
|
sub get_tree { |
424 |
|
|
my ($self, %opts) = @_; |
425 |
|
|
do { $log->warning("����� ->get_tree() ����� �������� ������ � ��������, �� �� �������"); return undef } unless ref($self); |
426 |
|
|
|
427 |
|
|
my $root = $opts{root} || $ROOT; |
428 |
|
|
|
429 |
|
|
|
430 |
|
|
# ---------------------------------------------------------------------------------------- |
431 |
|
|
# �������� ��� ������ |
432 |
|
|
$opts{no_limit} = 1; |
433 |
|
|
delete $opts{root}; |
434 |
|
|
my @sections = $self->keeper->get_sections(%opts); |
435 |
|
|
|
436 |
|
|
my $CACHE = {}; |
437 |
|
|
foreach my $section (@sections) { |
438 |
|
|
if (ref($section)) { |
439 |
|
|
$CACHE->{$section->id()} = $section; |
440 |
|
|
} |
441 |
|
|
} |
442 |
|
|
|
443 |
|
|
for my $id (sort { $CACHE->{$a}->sorder() <=> $CACHE->{$b}->sorder() } (keys(%{ $CACHE }))) { |
444 |
|
|
my $pid = $CACHE->{$id}->pid() || ''; |
445 |
|
|
$CACHE->{$pid}->{childs} = [] if (! exists($CACHE->{$pid}->{childs})); |
446 |
|
|
$CACHE->{$id}->{parent} = $CACHE->{$pid}; |
447 |
|
|
push (@{ $CACHE->{$pid}->{childs} }, $CACHE->{$id} ); |
448 |
|
|
} |
449 |
|
|
|
450 |
|
|
return $CACHE->{$root}; |
451 |
|
|
} |
452 |
|
|
|
453 |
|
|
1; |
454 |
|
|
|