| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package DBIx::QuickORM::Dialect::PostgreSQL; |
|
2
|
1
|
|
|
1
|
|
7
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
47
|
|
|
3
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
107
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.000019'; |
|
6
|
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
7
|
use Carp qw/croak/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
77
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use DBIx::QuickORM::Util qw/column_key/; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
11
|
|
|
9
|
1
|
|
|
1
|
|
49
|
use DBIx::QuickORM::Affinity qw/affinity_from_type/; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
67
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
886
|
use DBIx::QuickORM::Schema; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
43
|
|
|
12
|
1
|
|
|
1
|
|
914
|
use DBIx::QuickORM::Schema::Table; |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
47
|
|
|
13
|
1
|
|
|
1
|
|
914
|
use DBIx::QuickORM::Schema::Table::Column; |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
40
|
|
|
14
|
1
|
|
|
1
|
|
860
|
use DBIx::QuickORM::Schema::View; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
40
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
1
|
|
|
1
|
|
8
|
use parent 'DBIx::QuickORM::Dialect'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
5
|
|
|
17
|
1
|
|
|
1
|
|
105
|
use DBIx::QuickORM::Util::HashBase; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
7
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
0
|
|
|
0
|
0
|
|
sub dbi_driver { 'DBD::Pg' } |
|
20
|
0
|
|
|
0
|
0
|
|
sub dialect_name { 'PostgreSQL' } |
|
21
|
|
|
|
|
|
|
|
|
22
|
0
|
|
|
0
|
0
|
|
sub quote_binary_data { { pg_type => DBD::Pg::PG_BYTEA() } } |
|
23
|
|
|
|
|
|
|
|
|
24
|
0
|
|
|
0
|
0
|
|
sub supports_returning_update { 1 } |
|
25
|
0
|
|
|
0
|
0
|
|
sub supports_returning_insert { 1 } |
|
26
|
0
|
|
|
0
|
0
|
|
sub supports_returning_delete { 1 } |
|
27
|
|
|
|
|
|
|
|
|
28
|
0
|
|
|
0
|
0
|
|
sub async_supported { 1 } |
|
29
|
0
|
|
|
0
|
0
|
|
sub async_cancel_supported { 1 } |
|
30
|
0
|
|
|
0
|
0
|
|
sub async_prepare_args { pg_async => DBD::Pg::PG_ASYNC() } |
|
31
|
0
|
|
|
0
|
0
|
|
sub async_result { my ($s, %p) = @_; $p{sth}->pg_result() } |
|
|
0
|
|
|
|
|
|
|
|
32
|
0
|
|
0
|
0
|
0
|
|
sub async_ready { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->pg_ready() } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
33
|
0
|
|
0
|
0
|
0
|
|
sub async_cancel { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->pg_cancel() } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
0
|
|
0
|
0
|
0
|
|
sub start_txn { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->begin_work } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
36
|
0
|
|
0
|
0
|
0
|
|
sub commit_txn { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->commit } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
37
|
0
|
|
0
|
0
|
0
|
|
sub rollback_txn { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->rollback } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
38
|
0
|
|
0
|
0
|
0
|
|
sub create_savepoint { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->pg_savepoint($p{savepoint}) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
39
|
0
|
|
0
|
0
|
0
|
|
sub commit_savepoint { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->pg_release($p{savepoint}) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
40
|
0
|
|
0
|
0
|
0
|
|
sub rollback_savepoint { my ($s, %p) = @_; my $dbh = $p{dbh} // $s->dbh; $dbh->pg_rollback_to($p{savepoint}) } |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
my %TYPES = ( |
|
43
|
|
|
|
|
|
|
uuid => 'UUID', |
|
44
|
|
|
|
|
|
|
); |
|
45
|
|
|
|
|
|
|
sub supports_type { |
|
46
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
47
|
0
|
|
|
|
|
|
my ($type) = @_; |
|
48
|
0
|
|
|
|
|
|
return $TYPES{lc($type)}; |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub db_version { |
|
52
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
53
|
|
|
|
|
|
|
|
|
54
|
0
|
|
|
|
|
|
my $dbh = $self->{+DBH}; |
|
55
|
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare("SHOW server_version"); |
|
57
|
0
|
|
|
|
|
|
$sth->execute(); |
|
58
|
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
my ($ver) = $sth->fetchrow_array; |
|
60
|
0
|
|
|
|
|
|
return $ver; |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
############################################################################### |
|
64
|
|
|
|
|
|
|
# {{{ Schema Builder Code |
|
65
|
|
|
|
|
|
|
############################################################################### |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my %TABLE_TYPES = ( |
|
68
|
|
|
|
|
|
|
'BASE TABLE' => 'DBIx::QuickORM::Schema::Table', |
|
69
|
|
|
|
|
|
|
'VIEW' => 'DBIx::QuickORM::Schema::View', |
|
70
|
|
|
|
|
|
|
'LOCAL TEMPORARY' => 'DBIx::QuickORM::Schema::Table', |
|
71
|
|
|
|
|
|
|
); |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
my %TEMP_TYPES = ( |
|
74
|
|
|
|
|
|
|
'BASE TABLE' => 0, |
|
75
|
|
|
|
|
|
|
'VIEW' => 0, |
|
76
|
|
|
|
|
|
|
'LOCAL TEMPORARY' => 1, |
|
77
|
|
|
|
|
|
|
); |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub build_tables_from_db { |
|
80
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
81
|
0
|
|
|
|
|
|
my %params = @_; |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
my $dbh = $self->{+DBH}; |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare(<<" EOT"); |
|
86
|
|
|
|
|
|
|
SELECT table_name, table_type |
|
87
|
|
|
|
|
|
|
FROM information_schema.tables |
|
88
|
|
|
|
|
|
|
WHERE table_catalog = ? |
|
89
|
|
|
|
|
|
|
AND table_schema NOT IN ('pg_catalog', 'information_schema') |
|
90
|
|
|
|
|
|
|
EOT |
|
91
|
|
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
$sth->execute($self->{+DB_NAME}); |
|
93
|
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my %tables; |
|
95
|
|
|
|
|
|
|
|
|
96
|
0
|
|
|
|
|
|
while (my ($tname, $type) = $sth->fetchrow_array) { |
|
97
|
0
|
0
|
|
|
|
|
next if $params{autofill}->skip(table => $tname); |
|
98
|
|
|
|
|
|
|
|
|
99
|
0
|
|
0
|
|
|
|
my $table = {name => $tname, db_name => $tname, is_temp => $TEMP_TYPES{$type} // 0}; |
|
100
|
0
|
|
0
|
|
|
|
my $class = $TABLE_TYPES{$type} // 'DBIx::QuickORM::Schema::Table'; |
|
101
|
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
$params{autofill}->hook(pre_table => {table => $table, class => \$class}); |
|
103
|
|
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
$table->{columns} = $self->build_columns_from_db($tname, %params); |
|
105
|
0
|
|
|
|
|
|
$params{autofill}->hook(columns => {columns => $table->{columns}, table => $table}); |
|
106
|
|
|
|
|
|
|
|
|
107
|
0
|
|
|
|
|
|
$table->{indexes} = $self->build_indexes_from_db($tname, %params); |
|
108
|
0
|
|
|
|
|
|
$params{autofill}->hook(indexes => {indexes => $table->{indexes}, table => $table}); |
|
109
|
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
|
@{$table}{qw/primary_key unique _links/} = $self->build_table_keys_from_db($tname, %params); |
|
|
0
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
$params{autofill}->hook(post_table => {table => $table, class => \$class}); |
|
113
|
|
|
|
|
|
|
|
|
114
|
0
|
|
|
|
|
|
$tables{$table->{name}} = $class->new($table); |
|
115
|
0
|
|
|
|
|
|
$params{autofill}->hook(table => {table => $tables{$tname}}); |
|
116
|
|
|
|
|
|
|
} |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
|
return \%tables; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub build_table_keys_from_db { |
|
122
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
123
|
0
|
|
|
|
|
|
my ($table, %params) = @_; |
|
124
|
|
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
my $dbh = $self->{+DBH}; |
|
126
|
|
|
|
|
|
|
|
|
127
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare(<<" EOT"); |
|
128
|
|
|
|
|
|
|
SELECT pg_get_constraintdef(oid) |
|
129
|
|
|
|
|
|
|
FROM pg_constraint |
|
130
|
|
|
|
|
|
|
WHERE connamespace = 'public'::regnamespace AND conrelid::regclass::text = ? |
|
131
|
|
|
|
|
|
|
EOT |
|
132
|
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
|
$sth->execute($table); |
|
134
|
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my ($pk, %unique, @links); |
|
136
|
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
|
while (my ($spec) = $sth->fetchrow_array) { |
|
138
|
0
|
0
|
|
|
|
|
if (my ($type, $columns) = $spec =~ m/^(UNIQUE|PRIMARY KEY) \(([^\)]+)\)$/gi) { |
|
139
|
0
|
|
|
|
|
|
my @columns = split /,\s+/, $columns; |
|
140
|
|
|
|
|
|
|
|
|
141
|
0
|
0
|
|
|
|
|
$pk = \@columns if $type eq 'PRIMARY KEY'; |
|
142
|
|
|
|
|
|
|
|
|
143
|
0
|
|
|
|
|
|
my $key = column_key(@columns); |
|
144
|
0
|
|
|
|
|
|
$unique{$key} = \@columns; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
0
|
0
|
|
|
|
|
if (my ($type, $columns, $ftable, $fcolumns) = $spec =~ m/(FOREIGN KEY) \(([^\)]+)\) REFERENCES\s+(\S+)\(([^\)]+)\)/gi) { |
|
148
|
0
|
|
|
|
|
|
my @columns = split /,\s+/, $columns; |
|
149
|
0
|
|
|
|
|
|
my @fcolumns = split /,\s+/, $fcolumns; |
|
150
|
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
push @links => [[$table, \@columns], [$ftable, \@fcolumns]]; |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
$params{autofill}->hook(links => {links => \@links, table_name => $table}); |
|
156
|
0
|
|
|
|
|
|
$params{autofill}->hook(primary_key => {primary_key => $pk, table_name => $table}); |
|
157
|
0
|
|
|
|
|
|
$params{autofill}->hook(unique_keys => {unique_keys => \%unique, table_name => $table}); |
|
158
|
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
return ($pk, \%unique, \@links); |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub build_columns_from_db { |
|
163
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
164
|
0
|
|
|
|
|
|
my ($table, %params) = @_; |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
0
|
|
|
|
|
croak "A table name is required" unless $table; |
|
167
|
0
|
|
|
|
|
|
my $dbh = $self->{+DBH}; |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare(<<" EOT"); |
|
170
|
|
|
|
|
|
|
SELECT * |
|
171
|
|
|
|
|
|
|
FROM information_schema.columns |
|
172
|
|
|
|
|
|
|
WHERE table_catalog = ? |
|
173
|
|
|
|
|
|
|
AND table_name = ? |
|
174
|
|
|
|
|
|
|
AND table_schema NOT IN ('pg_catalog', 'information_schema') |
|
175
|
|
|
|
|
|
|
EOT |
|
176
|
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
|
$sth->execute($self->{+DB_NAME}, $table); |
|
178
|
|
|
|
|
|
|
|
|
179
|
0
|
|
|
|
|
|
my (%columns, @links); |
|
180
|
0
|
|
|
|
|
|
while (my $res = $sth->fetchrow_hashref) { |
|
181
|
0
|
0
|
|
|
|
|
next if $params{autofill}->skip(column => ($table, $res->{column_name})); |
|
182
|
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
my $col = {}; |
|
184
|
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
$params{autofill}->hook(pre_column => {column => $col, table_name => $table, column_info => $res}); |
|
186
|
|
|
|
|
|
|
|
|
187
|
0
|
|
|
|
|
|
$col->{name} = $res->{column_name}; |
|
188
|
0
|
|
|
|
|
|
$col->{db_name} = $res->{column_name}; |
|
189
|
0
|
|
|
|
|
|
$col->{order} = $res->{ordinal_position}; |
|
190
|
0
|
|
|
|
|
|
$col->{type} = \"$res->{udt_name}"; |
|
191
|
0
|
|
|
|
|
|
$col->{nullable} = $self->_col_field_to_bool($res->{is_nullable}); |
|
192
|
|
|
|
|
|
|
|
|
193
|
0
|
0
|
0
|
|
|
|
$col->{identity} //= 1 if grep { $self->_col_field_to_bool($res->{$_}) } grep { m/identity/ } keys %$res; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
194
|
0
|
0
|
0
|
|
|
|
$col->{identity} //= 1 if $res->{column_default} && $res->{column_default} =~ m/^nextval\(/; |
|
|
|
|
0
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
|
196
|
0
|
|
0
|
|
|
|
$col->{affinity} //= affinity_from_type($res->{udt_name}) // affinity_from_type($res->{data_type}); |
|
|
|
|
0
|
|
|
|
|
|
197
|
0
|
0
|
0
|
|
|
|
$col->{affinity} //= 'string' if grep { $self->_col_field_to_bool($res->{$_}) } grep { m/character/ } keys %$res; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
198
|
0
|
0
|
0
|
|
|
|
$col->{affinity} //= 'numeric' if grep { $self->_col_field_to_bool($res->{$_}) } grep { m/numeric/ } keys %$res; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
199
|
0
|
|
0
|
|
|
|
$col->{affinity} //= 'string'; |
|
200
|
|
|
|
|
|
|
|
|
201
|
0
|
|
|
|
|
|
$params{autofill}->process_column($col); |
|
202
|
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
$params{autofill}->hook(post_column => {column => $col, table_name => $table, column_info => $res}); |
|
204
|
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
|
$columns{$col->{name}} = DBIx::QuickORM::Schema::Table::Column->new($col); |
|
206
|
0
|
|
|
|
|
|
$params{autofill}->hook(column => {column => $columns{$col->{name}}, table_name => $table, column_info => $res}); |
|
207
|
|
|
|
|
|
|
} |
|
208
|
|
|
|
|
|
|
|
|
209
|
0
|
|
|
|
|
|
return \%columns; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub _col_field_to_bool { |
|
213
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
214
|
0
|
|
|
|
|
|
my ($val) = @_; |
|
215
|
|
|
|
|
|
|
|
|
216
|
0
|
0
|
|
|
|
|
return 0 unless defined $val; |
|
217
|
0
|
0
|
|
|
|
|
return 0 unless $val; |
|
218
|
0
|
|
|
|
|
|
$val = lc($val); |
|
219
|
0
|
0
|
|
|
|
|
return 0 if $val eq 'no'; |
|
220
|
0
|
0
|
|
|
|
|
return 0 if $val eq 'undef'; |
|
221
|
0
|
0
|
|
|
|
|
return 0 if $val eq 'never'; |
|
222
|
0
|
|
|
|
|
|
return 1; |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub build_indexes_from_db { |
|
226
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
227
|
0
|
|
|
|
|
|
my ($table, %params) = @_; |
|
228
|
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
my $dbh = $self->dbh; |
|
230
|
|
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
my $sth = $dbh->prepare(<<" EOT"); |
|
232
|
|
|
|
|
|
|
SELECT indexname AS name, |
|
233
|
|
|
|
|
|
|
indexdef AS def |
|
234
|
|
|
|
|
|
|
FROM pg_indexes |
|
235
|
|
|
|
|
|
|
WHERE tablename = ? |
|
236
|
|
|
|
|
|
|
ORDER BY name |
|
237
|
|
|
|
|
|
|
EOT |
|
238
|
|
|
|
|
|
|
|
|
239
|
0
|
|
|
|
|
|
$sth->execute($table); |
|
240
|
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
my @out; |
|
242
|
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
while (my ($name, $def) = $sth->fetchrow_array) { |
|
244
|
0
|
0
|
0
|
|
|
|
$def =~ m/CREATE(?: (UNIQUE))? INDEX \Q$name\E ON \S+ USING ([^\(]+) \((.+)\)$/ or warn "Could not parse index: $def" and next; |
|
245
|
0
|
|
|
|
|
|
my ($unique, $type, $col_list) = ($1, $2, $3); |
|
246
|
0
|
|
|
|
|
|
my @cols = split /,\s*/, $col_list; |
|
247
|
0
|
0
|
|
|
|
|
push @out => {name => $name, type => $type, columns => \@cols, unique => $unique ? 1 : 0}; |
|
248
|
0
|
|
|
|
|
|
$params{autofill}->hook(index => {index => $out[-1], table_name => $table, definition => $def}); |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
return \@out; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
############################################################################### |
|
255
|
|
|
|
|
|
|
# }}} Schema Builder Code |
|
256
|
|
|
|
|
|
|
############################################################################### |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
1; |