| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#=============================================== |
|
2
|
|
|
|
|
|
|
package Banal::Utils::Data; |
|
3
|
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
11369
|
use 5.006; |
|
|
1
|
|
|
|
|
9
|
|
|
|
1
|
|
|
|
|
109
|
|
|
5
|
1
|
|
|
1
|
|
7
|
use utf8; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
25
|
|
|
6
|
1
|
|
|
1
|
|
103
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
56
|
|
|
7
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
43
|
|
|
8
|
1
|
|
|
1
|
|
4
|
no warnings qw(uninitialized); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
116
|
|
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
require Exporter; |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
13
|
|
|
|
|
|
|
our @EXPORT_OK = qw( banal_get_data |
|
14
|
|
|
|
|
|
|
flatten_complex_data_to_list |
|
15
|
|
|
|
|
|
|
flatten_complex_data_to_list_with_options |
|
16
|
|
|
|
|
|
|
); |
|
17
|
1
|
|
|
1
|
|
7
|
use Carp; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
115
|
|
|
18
|
1
|
|
|
1
|
|
3483
|
use Data::Dumper; |
|
|
1
|
|
|
|
|
13060
|
|
|
|
1
|
|
|
|
|
88
|
|
|
19
|
1
|
|
|
1
|
|
9
|
use Banal::Utils::String qw(trim); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
67
|
|
|
20
|
1
|
|
|
1
|
|
6
|
use Banal::Utils::Array qw(array1_starts_with_array2); |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
931
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
##############################################################################" |
|
26
|
|
|
|
|
|
|
# PUBLIC (exportable) FUNCTIONS |
|
27
|
|
|
|
|
|
|
##############################################################################" |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
#---------------------------------- |
|
31
|
|
|
|
|
|
|
# Function, not a method! |
|
32
|
|
|
|
|
|
|
#---------------------------------- |
|
33
|
|
|
|
|
|
|
sub banal_get_data { |
|
34
|
0
|
|
|
0
|
1
|
|
my $args = {@_}; |
|
35
|
0
|
|
0
|
|
|
|
my $opts = $args->{options} || {}; |
|
36
|
0
|
|
|
|
|
|
my $search_upwards_while_not_defined = $opts->{search_upwards_while_not_defined}; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
# This is where the MAGIC happens. For a full list of options, see the function "normalize_data_root_and_keys()". |
|
41
|
0
|
|
|
|
|
|
my ($root, @keys) = _normalize_data_root_and_keys (@_); |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# The data root should have been defined by now. |
|
44
|
0
|
0
|
|
|
|
|
return unless ($root); |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# All this for nothing? |
|
47
|
0
|
0
|
|
|
|
|
return $root if (scalar(@keys) < 1); |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# The reason for the below loop is to allow outer level 'variables' to be used when the variable is not defined at the proper (inner) level. |
|
50
|
|
|
|
|
|
|
# Very handy for CONFIGURATION handling scenarios. |
|
51
|
0
|
|
|
|
|
|
my $key = pop @keys; |
|
52
|
0
|
|
|
|
|
|
while (scalar(@keys) >= 0) { |
|
53
|
0
|
|
|
|
|
|
my $value= _banal_basic_get_data_via_key_list(data=>$root, keys=>[@keys, $key]); |
|
54
|
0
|
0
|
|
|
|
|
return $value if defined($value); |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Continue searching upwards if we are allowed to do so. Return otherwise. |
|
57
|
0
|
0
|
|
|
|
|
return unless $search_upwards_while_not_defined; |
|
58
|
|
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
pop @keys; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
0
|
|
|
|
|
|
return; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
#----------------------------------------------- |
|
67
|
|
|
|
|
|
|
# FUNCTION (not a method). |
|
68
|
|
|
|
|
|
|
#----------------------------------------------- |
|
69
|
|
|
|
|
|
|
sub flatten_complex_data_to_list { |
|
70
|
0
|
|
|
0
|
1
|
|
return flatten_complex_data_to_list_with_options (data=>[@_], on_ArrayRef=>'flatten', on_HashRef=>'flatten', on_ScalarRef=>'flatten'); |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
#----------------------------------------------- |
|
75
|
|
|
|
|
|
|
# FUNCTION (not a method). |
|
76
|
|
|
|
|
|
|
#----------------------------------------------- |
|
77
|
|
|
|
|
|
|
sub flatten_complex_data_to_list_with_options { |
|
78
|
0
|
|
|
0
|
1
|
|
my $opts = {@_}; |
|
79
|
0
|
|
|
|
|
|
my $data = $opts->{data}; |
|
80
|
0
|
|
0
|
|
|
|
my $on_ArrayRef = $opts->{on_ArrayRef} || 'flatten'; |
|
81
|
0
|
|
0
|
|
|
|
my $on_HashRef = $opts->{on_HashRef} || 'flatten'; |
|
82
|
0
|
|
0
|
|
|
|
my $on_ScalarRef = $opts->{on_ScalarRef} || 'flatten'; |
|
83
|
0
|
|
|
|
|
|
my @list = (); |
|
84
|
|
|
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
foreach my $datum (@$data) { |
|
86
|
0
|
0
|
0
|
|
|
|
if ((reftype($datum) eq 'ARRAY') && ($on_ArrayRef =~ /^flatten|dereference$/io)){ |
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
87
|
0
|
|
|
|
|
|
push @list, flatten_complex_data_to_list_with_options(data=>$datum); |
|
88
|
0
|
|
|
|
|
|
next; |
|
89
|
|
|
|
|
|
|
}elsif ((reftype($datum) eq 'HASH') && ($on_HashRef =~ /^flatten|dereference$/io)){ |
|
90
|
0
|
|
|
|
|
|
push @list, flatten_complex_data_to_list_with_options(data=>[%$datum]); |
|
91
|
0
|
|
|
|
|
|
next; |
|
92
|
|
|
|
|
|
|
}elsif ((reftype($datum) eq 'SCALAR') && ($on_ScalarRef =~ /^flatten|dereference$/io)){ |
|
93
|
0
|
|
|
|
|
|
push @list, flatten_complex_data_to_list_with_options(data=>[$$datum]);; |
|
94
|
0
|
|
|
|
|
|
next; |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
}else { |
|
97
|
0
|
|
|
|
|
|
push @list, $datum; |
|
98
|
0
|
|
|
|
|
|
next; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
} |
|
102
|
0
|
|
|
|
|
|
return @list; |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
#******************************************************************* |
|
107
|
|
|
|
|
|
|
# PRIVATE (non-exported) FUNCTIONS |
|
108
|
|
|
|
|
|
|
#******************************************************************* |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
#---------------------------------- |
|
111
|
|
|
|
|
|
|
sub _is_absolute_data_key_reference { |
|
112
|
0
|
|
0
|
0
|
|
|
return ((scalar(@_) > 0) && !$_[0]); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
#---------------------------------- |
|
116
|
|
|
|
|
|
|
sub _normalize_data_root_and_keys { |
|
117
|
0
|
|
|
0
|
|
|
my $args = {@_}; |
|
118
|
0
|
|
0
|
|
|
|
my $keys = $args->{keys} || $args->{key} || $args->{path} || []; |
|
119
|
0
|
|
|
|
|
|
my $data = $args->{data}; |
|
120
|
0
|
|
0
|
|
|
|
my $context = $args->{context} || []; |
|
121
|
0
|
|
0
|
|
|
|
my $opts = $args->{options} || {}; |
|
122
|
0
|
|
0
|
|
|
|
my $separator = $opts->{path_separator} || $opts->{separator} || '/'; |
|
123
|
0
|
0
|
|
|
|
|
my $remove_extra_separators = defined($opts->{remove_extra_separators}) ? $opts->{remove_extra_separators} : 1; |
|
124
|
0
|
0
|
|
|
|
|
my $remove_leading_separator = defined($opts->{remove_leading_separator}) ? $opts->{remove_leading_separator} : 0; |
|
125
|
0
|
0
|
|
|
|
|
my $remove_trailing_separator = defined($opts->{remove_trailing_separator}) ? $opts->{remove_trailing_separator} : $remove_extra_separators; |
|
126
|
0
|
0
|
|
|
|
|
my $remove_empty_segments = defined($opts->{remove_empty_segments}) ? $opts->{remove_empty_segments} : 0; |
|
127
|
0
|
0
|
|
|
|
|
my $try_avoiding_repeated_segments = defined($opts->{try_avoiding_repeated_segments}) ? $opts->{try_avoiding_repeated_segments} : 0; |
|
128
|
0
|
|
0
|
|
|
|
my $lc = $opts->{lower_case} || $opts->{lc} || 0; |
|
129
|
0
|
|
0
|
|
|
|
my $trim = $opts->{trim} || 0; |
|
130
|
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
my $mroot = undef; # Yeah, 'undef' by default. |
|
132
|
0
|
|
|
|
|
|
my $relevant_keys = []; |
|
133
|
0
|
|
|
|
|
|
my @accumulated_segs = (); |
|
134
|
0
|
|
|
|
|
|
my $use_path_semantics; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
{ |
|
137
|
1
|
|
|
1
|
|
7
|
no warnings; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
1129
|
|
|
|
0
|
|
|
|
|
|
|
|
138
|
0
|
0
|
0
|
|
|
|
$use_path_semantics = (defined($opts->{path}) && (($keys eq $opts->{path}) || ($keys == $opts->{path}))) ? 1 : $opts->{use_path_semantics}; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Flatten all context and key segments (which are potentially a mix of path segment strings) |
|
142
|
0
|
|
|
|
|
|
$keys = flatten_complex_data_to_list_with_options(data=>[$data, $context, $keys], on_HashRef=>'keep'); |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# If we've got a HASH reference given as a key (or context) segment, that's our root. Otherwise, build the relevant thingy (relative to the root). |
|
145
|
0
|
|
|
|
|
|
foreach my $key (reverse @$keys) { |
|
146
|
0
|
0
|
|
|
|
|
if (reftype($key) eq 'HASH') { |
|
147
|
0
|
|
|
|
|
|
$mroot = $key; |
|
148
|
0
|
|
|
|
|
|
last; |
|
149
|
|
|
|
|
|
|
}else { |
|
150
|
0
|
|
|
|
|
|
unshift @$relevant_keys, $key; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Flatten all context and key segments (which are potentially a mix of path segment strings) |
|
155
|
0
|
|
|
|
|
|
while ( scalar(@$relevant_keys)) { |
|
156
|
0
|
|
|
|
|
|
my $key = pop @$relevant_keys; |
|
157
|
0
|
|
|
|
|
|
my @segs = flatten_complex_data_to_list_with_options(data=>[$key], on_HashRef=>'keep'); |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# If it's an empty ARRAY, just ignore, and pass on to the next one. |
|
160
|
0
|
0
|
|
|
|
|
next unless (scalar(@segs)); |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# Do we have much to do, anyway? |
|
163
|
0
|
0
|
|
|
|
|
if ($use_path_semantics) { |
|
164
|
0
|
|
|
|
|
|
my $path = join($separator, @segs); |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
0
|
|
|
|
|
$path =~ s/${separator}+/${separator}/ if ($remove_extra_separators); |
|
167
|
0
|
0
|
|
|
|
|
$path =~ s/^${separator}// if ($remove_leading_separator); # If you ask for this, you won't be able to detect absolute paths. |
|
168
|
0
|
0
|
|
|
|
|
$path =~ s/${separator}$// if ($remove_trailing_separator); |
|
169
|
|
|
|
|
|
|
|
|
170
|
0
|
|
|
|
|
|
@segs = split /$separator/, $path; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Lowercase and trim if required. |
|
174
|
0
|
0
|
|
|
|
|
@segs = [map {lc($_)} @segs] if ($lc); # Segments are all automatically lowercased, if asked for it. |
|
|
0
|
|
|
|
|
|
|
|
175
|
0
|
0
|
|
|
|
|
@segs = [map {trim($_)} @segs] if ($trim); # Segments are all automatically trimmed, if asked for. |
|
|
0
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
|
177
|
0
|
|
|
|
|
|
my @prepend_segs = @segs; |
|
178
|
0
|
0
|
|
|
|
|
if($try_avoiding_repeated_segments) { |
|
179
|
0
|
|
|
|
|
|
@prepend_segs = (); |
|
180
|
0
|
|
|
|
|
|
while (scalar(@segs)) { |
|
181
|
0
|
0
|
|
|
|
|
if (array1_starts_with_array2([@accumulated_segs], [@segs])) { |
|
182
|
0
|
|
|
|
|
|
last; |
|
183
|
|
|
|
|
|
|
} |
|
184
|
|
|
|
|
|
|
|
|
185
|
0
|
|
|
|
|
|
my $s = shift @segs; |
|
186
|
0
|
|
|
|
|
|
push @prepend_segs, $s; |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
@accumulated_segs = (@prepend_segs, @accumulated_segs); |
|
191
|
|
|
|
|
|
|
|
|
192
|
0
|
0
|
|
|
|
|
last if (_is_absolute_data_key_reference(@accumulated_segs)); |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
# Remove empty segments if we are asked for it. |
|
197
|
|
|
|
|
|
|
# If you ask for this, you won't be able to detect absolute paths later on (normally, we have already done the detection for you, though) |
|
198
|
0
|
0
|
|
|
|
|
@accumulated_segs = grep (/^\s*$/i, @accumulated_segs) if ($remove_empty_segments); |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Here's a little something: We insert the root to the begining of the array. |
|
201
|
0
|
|
|
|
|
|
unshift @accumulated_segs, $mroot; |
|
202
|
|
|
|
|
|
|
|
|
203
|
0
|
0
|
|
|
|
|
return wantarray ? @accumulated_segs : [@accumulated_segs]; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
#---------------------------------- |
|
207
|
|
|
|
|
|
|
# Function, not a method! |
|
208
|
|
|
|
|
|
|
# Allows to get a data element within a deep structure composed of possibly complex data types (HASH, ARRAY, ...) |
|
209
|
|
|
|
|
|
|
# Example: |
|
210
|
|
|
|
|
|
|
# _banal_basic_get_data_via_key_list (data=>$h, keys=>["employee[23]", "department", "name"]) |
|
211
|
|
|
|
|
|
|
# |
|
212
|
|
|
|
|
|
|
# In this example, we are assuming that the initial data ($h) is a HASH that has a key called 'employee' which refers to an ARRAY of hashes, .... |
|
213
|
|
|
|
|
|
|
#---------------------------------- |
|
214
|
|
|
|
|
|
|
sub _banal_basic_get_data_via_key_list { |
|
215
|
0
|
|
|
0
|
|
|
my $args = {@_}; |
|
216
|
0
|
|
|
|
|
|
my $data = $args->{data}; |
|
217
|
0
|
|
|
|
|
|
my $keys = $args->{keys}; |
|
218
|
0
|
|
|
|
|
|
my @segments = @$keys; |
|
219
|
|
|
|
|
|
|
|
|
220
|
0
|
|
|
|
|
|
foreach my $segment (@segments) { |
|
221
|
0
|
0
|
|
|
|
|
next unless $segment; |
|
222
|
|
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
|
my $element = $segment; |
|
224
|
0
|
|
|
|
|
|
my $index; |
|
225
|
|
|
|
|
|
|
|
|
226
|
0
|
0
|
|
|
|
|
if($element =~ /^([^\[]*)\[(\d+)\]$/) { |
|
227
|
0
|
|
|
|
|
|
$element = $1; |
|
228
|
0
|
|
|
|
|
|
$index = $2; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
else { |
|
231
|
0
|
|
|
|
|
|
$index = undef; |
|
232
|
|
|
|
|
|
|
} |
|
233
|
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# We're on a SCALAR. Fishy, since we have got a key segment, too. |
|
235
|
0
|
0
|
|
|
|
|
unless(reftype($data)) { |
|
236
|
0
|
|
|
|
|
|
return; |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# We're on a SCALAR Reference. Fishy, since we have got a key segment, too. |
|
240
|
0
|
0
|
|
|
|
|
if(reftype($data) eq "SCALAR") { |
|
241
|
0
|
|
|
|
|
|
return; |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# We're on an ARRAY. |
|
246
|
0
|
0
|
|
|
|
|
if(reftype($data) eq "ARRAY") { |
|
247
|
0
|
0
|
0
|
|
|
|
if (defined ($index) && !defined($element)) { |
|
|
|
0
|
|
|
|
|
|
|
248
|
0
|
0
|
|
|
|
|
if(exists $data->[$index]) { |
|
249
|
0
|
|
|
|
|
|
$data = $data->[$index]; |
|
250
|
0
|
|
|
|
|
|
next; |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
else { |
|
253
|
0
|
|
|
|
|
|
croak "No element with index $index!\n"; |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
}elsif (!defined($element)) { |
|
256
|
0
|
|
|
|
|
|
return $data |
|
257
|
|
|
|
|
|
|
} |
|
258
|
0
|
|
|
|
|
|
return; |
|
259
|
|
|
|
|
|
|
} |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# We're on a HASH. |
|
263
|
0
|
0
|
|
|
|
|
if(reftype($data) eq "HASH") { |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# the entire segment (even if it matches the array indexing pattern!) |
|
266
|
0
|
0
|
|
|
|
|
if (exists $data->{$segment}) { |
|
267
|
0
|
|
|
|
|
|
$data = $data->{$segment}; # this way, we are able to retreive weird hash values with keys that actually match our array indexing. |
|
268
|
0
|
|
|
|
|
|
next; |
|
269
|
|
|
|
|
|
|
} |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# Now, we are on the normal route. |
|
272
|
0
|
0
|
|
|
|
|
if (! exists $data->{$element}) { |
|
273
|
0
|
|
|
|
|
|
return; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
0
|
0
|
|
|
|
|
if(reftype($data->{$element}) eq "ARRAY") { |
|
276
|
0
|
0
|
|
|
|
|
if(! defined($index) ) { |
|
277
|
|
|
|
|
|
|
#croak "$element is an array but you didn't specify an index to access it!\n"; |
|
278
|
0
|
|
|
|
|
|
$data = $data->{$element}; |
|
279
|
0
|
|
|
|
|
|
next; |
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
else { |
|
282
|
0
|
0
|
|
|
|
|
if(exists $data->{$element}->[$index]) { |
|
283
|
0
|
|
|
|
|
|
$data = $data->{$element}->[$index]; |
|
284
|
0
|
|
|
|
|
|
next; |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
else { |
|
287
|
0
|
|
|
|
|
|
croak "$element doesn't have an element with index $index!\n"; |
|
288
|
0
|
|
|
|
|
|
return; |
|
289
|
|
|
|
|
|
|
} |
|
290
|
|
|
|
|
|
|
} |
|
291
|
|
|
|
|
|
|
} |
|
292
|
|
|
|
|
|
|
else { |
|
293
|
0
|
|
|
|
|
|
$data = $data->{$element}; |
|
294
|
|
|
|
|
|
|
} |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
} |
|
297
|
|
|
|
|
|
|
|
|
298
|
0
|
|
|
|
|
|
return $data; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
1; |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
__END__ |