File | /usr/local/lib/perl5/site_perl/5.10.1/Try/Tiny.pm |
Statements Executed | 11487 |
Statement Execution Time | 7.55ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
522 | 5 | 5 | 6.29ms | 655ms | try | Try::Tiny::
521 | 4 | 4 | 1.68ms | 1.68ms | catch | Try::Tiny::
1 | 1 | 1 | 19µs | 27µs | BEGIN@3 | Try::Tiny::
1 | 1 | 1 | 14µs | 14µs | BEGIN@8 | Try::Tiny::
1 | 1 | 1 | 9µs | 80µs | BEGIN@6 | Try::Tiny::
1 | 1 | 1 | 9µs | 51µs | BEGIN@46 | Try::Tiny::
0 | 0 | 0 | 0s | 0s | DESTROY | Try::Tiny::ScopeGuard::
0 | 0 | 0 | 0s | 0s | finally | Try::Tiny::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package Try::Tiny; | ||||
2 | |||||
3 | 3 | 32µs | 2 | 35µs | # spent 27µs (19+8) within Try::Tiny::BEGIN@3 which was called
# once (19µs+8µs) by Class::MOP::BEGIN@13 at line 3 # spent 27µs making 1 call to Try::Tiny::BEGIN@3
# spent 8µs making 1 call to strict::import |
4 | #use warnings; | ||||
5 | |||||
6 | 3 | 44µs | 2 | 152µs | # spent 80µs (9+72) within Try::Tiny::BEGIN@6 which was called
# once (9µs+72µs) by Class::MOP::BEGIN@13 at line 6 # spent 80µs making 1 call to Try::Tiny::BEGIN@6
# spent 72µs making 1 call to vars::import |
7 | |||||
8 | # spent 14µs within Try::Tiny::BEGIN@8 which was called
# once (14µs+0s) by Class::MOP::BEGIN@13 at line 11 | ||||
9 | 1 | 600ns | require Exporter; | ||
10 | 1 | 13µs | @ISA = qw(Exporter); | ||
11 | 1 | 109µs | 1 | 14µs | } # spent 14µs making 1 call to Try::Tiny::BEGIN@8 |
12 | |||||
13 | 1 | 800ns | $VERSION = "0.04"; | ||
14 | |||||
15 | 1 | 22µs | $VERSION = eval $VERSION; | ||
16 | |||||
17 | 1 | 2µs | @EXPORT = @EXPORT_OK = qw(try catch finally); | ||
18 | |||||
19 | 1 | 1µs | $Carp::Internal{+__PACKAGE__}++; | ||
20 | |||||
21 | # Need to prototype as @ not $$ because of the way Perl evaluates the prototype. | ||||
22 | # Keeping it at $$ means you only ever get 1 sub because we need to eval in a list | ||||
23 | # context & not a scalar one | ||||
24 | |||||
25 | # spent 655ms (6.29+649) within Try::Tiny::try which was called 522 times, avg 1.25ms/call:
# 276 times (3.13ms+15.5ms) by Class::MOP::Attribute::_process_accessors at line 343 of Class/MOP/Attribute.pm, avg 67µs/call
# 201 times (2.31ms+35.1ms) by Class::MOP::Class::_post_add_attribute at line 519 of Class/MOP/Class.pm, avg 186µs/call
# 36 times (676µs+748µs) by Moose::Object::DESTROY at line 100 of Moose/Object.pm, avg 40µs/call
# 8 times (143µs+597ms) by Class::MOP::load_first_existing_class at line 110 of Class/MOP.pm, avg 74.7ms/call
# once (26µs+-26µs) by Moose::Meta::Attribute::does at line 35 of Moose/Meta/Attribute.pm | ||||
26 | 522 | 285µs | my ( $try, @code_refs ) = @_; | ||
27 | |||||
28 | # we need to save this here, the eval block will be in scalar context due | ||||
29 | # to $failed | ||||
30 | 522 | 97µs | my $wantarray = wantarray; | ||
31 | |||||
32 | 522 | 107µs | my ( $catch, $finally ); | ||
33 | |||||
34 | # find labeled blocks in the argument list. | ||||
35 | # catch and finally tag the blocks by blessing a scalar reference to them. | ||||
36 | 522 | 333µs | foreach my $code_ref (@code_refs) { | ||
37 | 521 | 54µs | next unless $code_ref; | ||
38 | |||||
39 | 521 | 176µs | my $ref = ref($code_ref); | ||
40 | |||||
41 | 521 | 518µs | if ( $ref eq 'Try::Tiny::Catch' ) { | ||
42 | $catch = ${$code_ref}; | ||||
43 | } elsif ( $ref eq 'Try::Tiny::Finally' ) { | ||||
44 | $finally = ${$code_ref}; | ||||
45 | } else { | ||||
46 | 3 | 297µs | 2 | 93µs | # spent 51µs (9+42) within Try::Tiny::BEGIN@46 which was called
# once (9µs+42µs) by Class::MOP::BEGIN@13 at line 46 # spent 51µs making 1 call to Try::Tiny::BEGIN@46
# spent 42µs making 1 call to Exporter::import |
47 | confess("Unknown code ref type given '${ref}'. Check your usage & try again"); | ||||
48 | } | ||||
49 | } | ||||
50 | |||||
51 | # save the value of $@ so we can set $@ back to it in the beginning of the eval | ||||
52 | 522 | 104µs | my $prev_error = $@; | ||
53 | |||||
54 | 522 | 91µs | my ( @ret, $error, $failed ); | ||
55 | |||||
56 | # FIXME consider using local $SIG{__DIE__} to accumulate all errors. It's | ||||
57 | # not perfect, but we could provide a list of additional errors for | ||||
58 | # $catch->(); | ||||
59 | |||||
60 | { | ||||
61 | # localize $@ to prevent clobbering of previous value by a successful | ||||
62 | # eval. | ||||
63 | 1044 | 147µs | local $@; | ||
64 | |||||
65 | # failed will be true if the eval dies, because 1 will not be returned | ||||
66 | # from the eval body | ||||
67 | 522 | 318µs | $failed = not eval { | ||
68 | 522 | 59µs | $@ = $prev_error; | ||
69 | |||||
70 | # evaluate the try block in the correct context | ||||
71 | 522 | 244µs | 9 | 664ms | if ( $wantarray ) { # spent 664ms making 8 calls to Class::MOP::__ANON__[Class/MOP.pm:103], avg 83.0ms/call
# spent 11µs making 1 call to Moose::Meta::Attribute::__ANON__[Moose/Meta/Attribute.pm:35] |
72 | @ret = $try->(); | ||||
73 | } elsif ( defined $wantarray ) { | ||||
74 | $ret[0] = $try->(); | ||||
75 | } else { | ||||
76 | 513 | 563µs | 513 | 186ms | $try->(); # spent 105ms making 201 calls to Class::MOP::Class::__ANON__[Class/MOP/Class.pm:515], avg 520µs/call
# spent 80.3ms making 276 calls to Class::MOP::Attribute::__ANON__[Class/MOP/Attribute.pm:340], avg 291µs/call
# spent 748µs making 36 calls to Moose::Object::__ANON__[Moose/Object.pm:94], avg 21µs/call |
77 | }; | ||||
78 | |||||
79 | 521 | 174µs | return 1; # properly set $fail to false | ||
80 | }; | ||||
81 | |||||
82 | # copy $@ to $error; when we leave this scope, local $@ will revert $@ | ||||
83 | # back to its previous value | ||||
84 | 522 | 263µs | $error = $@; | ||
85 | } | ||||
86 | |||||
87 | # set up a scope guard to invoke the finally block at the end | ||||
88 | 522 | 116µs | my $guard = $finally && bless \$finally, "Try::Tiny::ScopeGuard"; | ||
89 | |||||
90 | # at this point $failed contains a true value if the eval died, even if some | ||||
91 | # destructor overwrote $@ as the eval was unwinding. | ||||
92 | 522 | 107µs | if ( $failed ) { | ||
93 | # if we got an error, invoke the catch block. | ||||
94 | 1 | 1µs | if ( $catch ) { | ||
95 | # This works like given($error), but is backwards compatible and | ||||
96 | # sets $_ in the dynamic scope for the body of C<$catch> | ||||
97 | for ($error) { | ||||
98 | 1 | 5µs | 1 | 29µs | return $catch->($error); # spent 29µs making 1 call to Class::MOP::__ANON__[Class/MOP.pm:110] |
99 | } | ||||
100 | |||||
101 | # in case when() was used without an explicit return, the C<for> | ||||
102 | # loop will be aborted and there's no useful return value | ||||
103 | } | ||||
104 | |||||
105 | return; | ||||
106 | } else { | ||||
107 | # no failure, $@ is back to what it was, everything is fine | ||||
108 | 521 | 1.21ms | return $wantarray ? @ret : $ret[0]; | ||
109 | } | ||||
110 | } | ||||
111 | |||||
112 | # spent 1.68ms within Try::Tiny::catch which was called 521 times, avg 3µs/call:
# 276 times (733µs+0s) by Class::MOP::Attribute::_process_accessors at line 343 of Class/MOP/Attribute.pm, avg 3µs/call
# 201 times (666µs+0s) by Class::MOP::Class::_post_add_attribute at line 519 of Class/MOP/Class.pm, avg 3µs/call
# 36 times (242µs+0s) by Moose::Object::DESTROY at line 100 of Moose/Object.pm, avg 7µs/call
# 8 times (37µs+0s) by Class::MOP::load_first_existing_class at line 110 of Class/MOP.pm, avg 5µs/call | ||||
113 | 521 | 302µs | my ( $block, @rest ) = @_; | ||
114 | |||||
115 | return ( | ||||
116 | 521 | 1.74ms | bless(\$block, 'Try::Tiny::Catch'), | ||
117 | @rest, | ||||
118 | ); | ||||
119 | } | ||||
120 | |||||
121 | sub finally (&;@) { | ||||
122 | my ( $block, @rest ) = @_; | ||||
123 | |||||
124 | return ( | ||||
125 | bless(\$block, 'Try::Tiny::Finally'), | ||||
126 | @rest, | ||||
127 | ); | ||||
128 | } | ||||
129 | |||||
130 | sub Try::Tiny::ScopeGuard::DESTROY { | ||||
131 | my $self = shift; | ||||
132 | $$self->(); | ||||
133 | } | ||||
134 | |||||
135 | 1 | 13µs | __PACKAGE__ | ||
136 | |||||
137 | __END__ | ||||
138 | |||||
139 | =pod | ||||
140 | |||||
141 | =head1 NAME | ||||
142 | |||||
143 | Try::Tiny - minimal try/catch with proper localization of $@ | ||||
144 | |||||
145 | =head1 SYNOPSIS | ||||
146 | |||||
147 | # handle errors with a catch handler | ||||
148 | try { | ||||
149 | die "foo"; | ||||
150 | } catch { | ||||
151 | warn "caught error: $_"; | ||||
152 | }; | ||||
153 | |||||
154 | # just silence errors | ||||
155 | try { | ||||
156 | die "foo"; | ||||
157 | }; | ||||
158 | |||||
159 | =head1 DESCRIPTION | ||||
160 | |||||
161 | This module provides bare bones C<try>/C<catch>/C<finally> statements that are designed to | ||||
162 | minimize common mistakes with eval blocks, and NOTHING else. | ||||
163 | |||||
164 | This is unlike L<TryCatch> which provides a nice syntax and avoids adding | ||||
165 | another call stack layer, and supports calling C<return> from the try block to | ||||
166 | return from the parent subroutine. These extra features come at a cost of a few | ||||
167 | dependencies, namely L<Devel::Declare> and L<Scope::Upper> which are | ||||
168 | occasionally problematic, and the additional catch filtering uses L<Moose> | ||||
169 | type constraints which may not be desirable either. | ||||
170 | |||||
171 | The main focus of this module is to provide simple and reliable error handling | ||||
172 | for those having a hard time installing L<TryCatch>, but who still want to | ||||
173 | write correct C<eval> blocks without 5 lines of boilerplate each time. | ||||
174 | |||||
175 | It's designed to work as correctly as possible in light of the various | ||||
176 | pathological edge cases (see L<BACKGROUND>) and to be compatible with any style | ||||
177 | of error values (simple strings, references, objects, overloaded objects, etc). | ||||
178 | |||||
179 | If the try block dies, it returns the value of the last statement executed in | ||||
180 | the catch block, if there is one. Otherwise, it returns C<undef> in scalar | ||||
181 | context or the empty list in list context. The following two examples both | ||||
182 | assign C<"bar"> to C<$x>. | ||||
183 | |||||
184 | my $x = try { die "foo" } catch { "bar" }; | ||||
185 | |||||
186 | my $x = eval { die "foo" } || "bar"; | ||||
187 | |||||
188 | You can add finally blocks making the following true. | ||||
189 | |||||
190 | my $x; | ||||
191 | try { die 'foo' } finally { $x = 'bar' }; | ||||
192 | try { die 'foo' } catch { warn "Got a die: $_" } finally { $x = 'bar' }; | ||||
193 | |||||
194 | Finally blocks are always executed making them suitable for cleanup code | ||||
195 | which cannot be handled using local. | ||||
196 | |||||
197 | =head1 EXPORTS | ||||
198 | |||||
199 | All functions are exported by default using L<Exporter>. | ||||
200 | |||||
201 | If you need to rename the C<try>, C<catch> or C<finally> keyword consider using | ||||
202 | L<Sub::Import> to get L<Sub::Exporter>'s flexibility. | ||||
203 | |||||
204 | =over 4 | ||||
205 | |||||
206 | =item try (&;@) | ||||
207 | |||||
208 | Takes one mandatory try subroutine, an optional catch subroutine & finally | ||||
209 | subroutine. | ||||
210 | |||||
211 | The mandatory subroutine is evaluated in the context of an C<eval> block. | ||||
212 | |||||
213 | If no error occurred the value from the first block is returned, preserving | ||||
214 | list/scalar context. | ||||
215 | |||||
216 | If there was an error and the second subroutine was given it will be invoked | ||||
217 | with the error in C<$_> (localized) and as that block's first and only | ||||
218 | argument. | ||||
219 | |||||
220 | Note that the error may be false, but if that happens the C<catch> block will | ||||
221 | still be invoked. | ||||
222 | |||||
223 | Once all execution is finished then the finally block if given will execute. | ||||
224 | |||||
225 | =item catch (&;$) | ||||
226 | |||||
227 | Intended to be used in the second argument position of C<try>. | ||||
228 | |||||
229 | Returns a reference to the subroutine it was given but blessed as | ||||
230 | C<Try::Tiny::Catch> which allows try to decode correctly what to do | ||||
231 | with this code reference. | ||||
232 | |||||
233 | catch { ... } | ||||
234 | |||||
235 | Inside the catch block the previous value of C<$@> is still available for use. | ||||
236 | This value may or may not be meaningful depending on what happened before the | ||||
237 | C<try>, but it might be a good idea to preserve it in an error stack. | ||||
238 | |||||
239 | =item finally (&;$) | ||||
240 | |||||
241 | try { ... } | ||||
242 | catch { ... } | ||||
243 | finally { ... }; | ||||
244 | |||||
245 | Or | ||||
246 | |||||
247 | try { ... } | ||||
248 | finally { ... }; | ||||
249 | |||||
250 | Or even | ||||
251 | |||||
252 | try { ... } | ||||
253 | finally { ... } | ||||
254 | catch { ... }; | ||||
255 | |||||
256 | Intended to be the second or third element of C<try>. Finally blocks are always | ||||
257 | executed in the event of a successful C<try> or if C<catch> is run. This allows | ||||
258 | you to locate cleanup code which cannot be done via C<local()> e.g. closing a file | ||||
259 | handle. | ||||
260 | |||||
261 | B<You must always do your own error handling in the finally block>. C<Try::Tiny> will | ||||
262 | not do anything about handling possible errors coming from code located in these | ||||
263 | blocks. | ||||
264 | |||||
265 | In the same way C<catch()> blesses the code reference this subroutine does the same | ||||
266 | except it bless them as C<Try::Tiny::Finally>. | ||||
267 | |||||
268 | =back | ||||
269 | |||||
270 | =head1 BACKGROUND | ||||
271 | |||||
272 | There are a number of issues with C<eval>. | ||||
273 | |||||
274 | =head2 Clobbering $@ | ||||
275 | |||||
276 | When you run an eval block and it succeeds, C<$@> will be cleared, potentially | ||||
277 | clobbering an error that is currently being caught. | ||||
278 | |||||
279 | This causes action at a distance, clearing previous errors your caller may have | ||||
280 | not yet handled. | ||||
281 | |||||
282 | C<$@> must be properly localized before invoking C<eval> in order to avoid this | ||||
283 | issue. | ||||
284 | |||||
285 | More specifically, C<$@> is clobbered at the begining of the C<eval>, which | ||||
286 | also makes it impossible to capture the previous error before you die (for | ||||
287 | instance when making exception objects with error stacks). | ||||
288 | |||||
289 | For this reason C<try> will actually set C<$@> to its previous value (before | ||||
290 | the localization) in the beginning of the C<eval> block. | ||||
291 | |||||
292 | =head2 Localizing $@ silently masks errors | ||||
293 | |||||
294 | Inside an eval block C<die> behaves sort of like: | ||||
295 | |||||
296 | sub die { | ||||
297 | $@ = $_[0]; | ||||
298 | return_undef_from_eval(); | ||||
299 | } | ||||
300 | |||||
301 | This means that if you were polite and localized C<$@> you can't die in that | ||||
302 | scope, or your error will be discarded (printing "Something's wrong" instead). | ||||
303 | |||||
304 | The workaround is very ugly: | ||||
305 | |||||
306 | my $error = do { | ||||
307 | local $@; | ||||
308 | eval { ... }; | ||||
309 | $@; | ||||
310 | }; | ||||
311 | |||||
312 | ... | ||||
313 | die $error; | ||||
314 | |||||
315 | =head2 $@ might not be a true value | ||||
316 | |||||
317 | This code is wrong: | ||||
318 | |||||
319 | if ( $@ ) { | ||||
320 | ... | ||||
321 | } | ||||
322 | |||||
323 | because due to the previous caveats it may have been unset. | ||||
324 | |||||
325 | C<$@> could also be an overloaded error object that evaluates to false, but | ||||
326 | that's asking for trouble anyway. | ||||
327 | |||||
328 | The classic failure mode is: | ||||
329 | |||||
330 | sub Object::DESTROY { | ||||
331 | eval { ... } | ||||
332 | } | ||||
333 | |||||
334 | eval { | ||||
335 | my $obj = Object->new; | ||||
336 | |||||
337 | die "foo"; | ||||
338 | }; | ||||
339 | |||||
340 | if ( $@ ) { | ||||
341 | |||||
342 | } | ||||
343 | |||||
344 | In this case since C<Object::DESTROY> is not localizing C<$@> but still uses | ||||
345 | C<eval>, it will set C<$@> to C<"">. | ||||
346 | |||||
347 | The destructor is called when the stack is unwound, after C<die> sets C<$@> to | ||||
348 | C<"foo at Foo.pm line 42\n">, so by the time C<if ( $@ )> is evaluated it has | ||||
349 | been cleared by C<eval> in the destructor. | ||||
350 | |||||
351 | The workaround for this is even uglier than the previous ones. Even though we | ||||
352 | can't save the value of C<$@> from code that doesn't localize, we can at least | ||||
353 | be sure the eval was aborted due to an error: | ||||
354 | |||||
355 | my $failed = not eval { | ||||
356 | ... | ||||
357 | |||||
358 | return 1; | ||||
359 | }; | ||||
360 | |||||
361 | This is because an C<eval> that caught a C<die> will always return a false | ||||
362 | value. | ||||
363 | |||||
364 | =head1 SHINY SYNTAX | ||||
365 | |||||
366 | Using Perl 5.10 you can use L<perlsyn/"Switch statements">. | ||||
367 | |||||
368 | The C<catch> block is invoked in a topicalizer context (like a C<given> block), | ||||
369 | but note that you can't return a useful value from C<catch> using the C<when> | ||||
370 | blocks without an explicit C<return>. | ||||
371 | |||||
372 | This is somewhat similar to Perl 6's C<CATCH> blocks. You can use it to | ||||
373 | concisely match errors: | ||||
374 | |||||
375 | try { | ||||
376 | require Foo; | ||||
377 | } catch { | ||||
378 | when (/^Can't locate .*?\.pm in \@INC/) { } # ignore | ||||
379 | default { die $_ } | ||||
380 | }; | ||||
381 | |||||
382 | =head1 CAVEATS | ||||
383 | |||||
384 | =over 4 | ||||
385 | |||||
386 | =item * | ||||
387 | |||||
388 | C<@_> is not available, you need to name your args: | ||||
389 | |||||
390 | sub foo { | ||||
391 | my ( $self, @args ) = @_; | ||||
392 | try { $self->bar(@args) } | ||||
393 | } | ||||
394 | |||||
395 | =item * | ||||
396 | |||||
397 | C<return> returns from the C<try> block, not from the parent sub (note that | ||||
398 | this is also how C<eval> works, but not how L<TryCatch> works): | ||||
399 | |||||
400 | sub bar { | ||||
401 | try { return "foo" }; | ||||
402 | return "baz"; | ||||
403 | } | ||||
404 | |||||
405 | say bar(); # "baz" | ||||
406 | |||||
407 | =item * | ||||
408 | |||||
409 | C<try> introduces another caller stack frame. L<Sub::Uplevel> is not used. L<Carp> | ||||
410 | will report this when using full stack traces. This lack of magic is considered | ||||
411 | a feature. | ||||
412 | |||||
413 | =item * | ||||
414 | |||||
415 | The value of C<$_> in the C<catch> block is not guaranteed to be the value of | ||||
416 | the exception thrown (C<$@>) in the C<try> block. There is no safe way to | ||||
417 | ensure this, since C<eval> may be used unhygenically in destructors. The only | ||||
418 | guarantee is that the C<catch> will be called if an exception is thrown. | ||||
419 | |||||
420 | =item * | ||||
421 | |||||
422 | The return value of the C<catch> block is not ignored, so if testing the result | ||||
423 | of the expression for truth on success, be sure to return a false value from | ||||
424 | the C<catch> block: | ||||
425 | |||||
426 | my $obj = try { | ||||
427 | MightFail->new; | ||||
428 | } catch { | ||||
429 | ... | ||||
430 | |||||
431 | return; # avoid returning a true value; | ||||
432 | }; | ||||
433 | |||||
434 | return unless $obj; | ||||
435 | |||||
436 | =back | ||||
437 | |||||
438 | =head1 SEE ALSO | ||||
439 | |||||
440 | =over 4 | ||||
441 | |||||
442 | =item L<TryCatch> | ||||
443 | |||||
444 | Much more feature complete, more convenient semantics, but at the cost of | ||||
445 | implementation complexity. | ||||
446 | |||||
447 | =item L<autodie> | ||||
448 | |||||
449 | Automatic error throwing for builtin functions and more. Also designed to | ||||
450 | work well with C<given>/C<when>. | ||||
451 | |||||
452 | =item L<Throwable> | ||||
453 | |||||
454 | A lightweight role for rolling your own exception classes. | ||||
455 | |||||
456 | =item L<Error> | ||||
457 | |||||
458 | Exception object implementation with a C<try> statement. Does not localize | ||||
459 | C<$@>. | ||||
460 | |||||
461 | =item L<Exception::Class::TryCatch> | ||||
462 | |||||
463 | Provides a C<catch> statement, but properly calling C<eval> is your | ||||
464 | responsibility. | ||||
465 | |||||
466 | The C<try> keyword pushes C<$@> onto an error stack, avoiding some of the | ||||
467 | issues with C<$@>, but you still need to localize to prevent clobbering. | ||||
468 | |||||
469 | =back | ||||
470 | |||||
471 | =head1 LIGHTNING TALK | ||||
472 | |||||
473 | I gave a lightning talk about this module, you can see the slides (Firefox | ||||
474 | only): | ||||
475 | |||||
476 | L<http://nothingmuch.woobling.org/talks/takahashi.xul?data=try_tiny.txt> | ||||
477 | |||||
478 | Or read the source: | ||||
479 | |||||
480 | L<http://nothingmuch.woobling.org/talks/yapc_asia_2009/try_tiny.yml> | ||||
481 | |||||
482 | =head1 VERSION CONTROL | ||||
483 | |||||
484 | L<http://github.com/nothingmuch/try-tiny/> | ||||
485 | |||||
486 | =head1 AUTHOR | ||||
487 | |||||
488 | Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt> | ||||
489 | |||||
490 | =head1 COPYRIGHT | ||||
491 | |||||
492 | Copyright (c) 2009 Yuval Kogman. All rights reserved. | ||||
493 | This program is free software; you can redistribute | ||||
494 | it and/or modify it under the terms of the MIT license. | ||||
495 | |||||
496 | =cut | ||||
497 |