File Coverage

blib/lib/Grep/Query.pm
Criterion Covered Total %
statement 68 68 100.0
branch 20 24 83.3
condition 7 11 63.6
subroutine 13 13 100.0
pod 3 3 100.0
total 111 119 93.2


line stmt bran cond sub pod time code
1             package Grep::Query;
2              
3 10     10   98521 use 5.010;
  10         85  
4              
5 10     10   49 use strict;
  10         19  
  10         188  
6 10     10   44 use warnings;
  10         16  
  10         900  
7              
8             our $VERSION = '1.011';
9             $VERSION = eval $VERSION;
10              
11 10     10   4621 use Grep::Query::Parser;
  10         28  
  10         378  
12 10     10   5350 use Grep::Query::FieldAccessor;
  10         25  
  10         341  
13              
14 10     10   62 use Scalar::Util qw(blessed);
  10         19  
  10         442  
15 10     10   54 use Carp;
  10         21  
  10         433  
16 10     10   56 use Digest::MD5;
  10         17  
  10         367  
17              
18             # allow importing the qgrep function/method
19             # to enable non-OO use
20             #
21 10     10   53 use Exporter qw(import);
  10         18  
  10         6430  
22             our @EXPORT_OK = qw(qgrep);
23              
24             ## CTOR
25             ##
26             sub new
27             {
28 440     440 1 507345 my $class = shift;
29 440         717 my $query = shift;
30            
31 440 50       1055 croak("No query provided") unless defined($query);
32            
33             # parse the query right now
34             #
35 440         1282 my ($parsedQuery, $fieldRefs) = Grep::Query::Parser::parsequery($query);
36 423         7460 my $self =
37             {
38             _query => $query,
39             _parsedquery => $parsedQuery,
40             _fieldrefs => $fieldRefs
41             };
42 423         1359 bless($self, $class);
43            
44 423         1345 return $self;
45             }
46              
47             ## METHODS
48             ##
49              
50             sub qgrep
51             {
52 327 50   327 1 827277 croak("missing parameters") unless @_;
53              
54 327         643 my $arg = shift;
55            
56 327 100 100     2143 my $obj =
57             (blessed($arg) // '') eq __PACKAGE__
58             ? $arg
59             : __PACKAGE__->new($arg);
60            
61 327         908 return $obj->__qgrep(@_);
62             }
63              
64             sub getQuery
65             {
66 1     1 1 7 my $self = shift;
67            
68 1         6 return $self->{_query};
69             }
70              
71             # don't call this directly, use the above
72             #
73             sub __qgrep
74             {
75             # why even bother if you're not interested in the result?
76             #
77 327 100   327   798 return undef unless defined(wantarray());
78            
79 325         561 my $self = shift(@_);
80              
81             # make a note of if any query value is a ref
82             #
83 325         539 my $refCount = scalar(grep { ref($_) } @_);
  6912         9362  
84            
85             # first check if the first argument is/should be a field accessor
86             #
87 325         492 my $fieldAccessor;
88 325 100 66     420 if (@{$self->{_fieldrefs}} || (@_ && !defined($_[0]) && $refCount))
  325   33     1634  
      66        
89             {
90             # the query uses fields, or there's an undef and at least one ref, there must be a field accessor first
91             #
92 174         610 $fieldAccessor = shift(@_);
93            
94 174 100       354 if (defined($fieldAccessor))
95             {
96             # verify that the field accessor is of the right sort and has the known fields
97             #
98 120 100       299 croak("field names used in query; the argument before the list must be a field accessor") unless ref($fieldAccessor) eq 'Grep::Query::FieldAccessor';
99 119         167 $fieldAccessor->assertField($_) foreach (@{$self->{_fieldrefs}});
  119         536  
100             }
101             else
102             {
103             # for laziness, the caller passed undef; if there's any fields mentioned in the query, make a field accessor
104             #
105 54 50       83 $fieldAccessor = Grep::Query::FieldAccessor->newDefault(@{$self->{_fieldrefs}}) if @{$self->{_fieldrefs}};
  54         393  
  54         146  
106             }
107             }
108             else
109             {
110             # it's weird if a field accessor is present, but the query uses no fields - flag that mistake
111             #
112 151 100       381 croak("no fields used in query, yet the first list argument is a field accessor?") if ref($_[0]) eq 'Grep::Query::FieldAccessor';
113             }
114              
115             # nothing to see here
116             #
117 323 50       868 return(wantarray() ? () : 0) unless @_;
    100          
118            
119             # the list we were given needs to be made into a hash with unique keys so we
120             # identify 'rows' while evaluating the query
121             #
122             # that means we can return multiple identical hits and that we can sort the return list
123             # in the same order we got it
124             #
125             # keys are simply a number, and values are refs to the individual scalars/objects to avoid copying them
126             #
127 315         445 my $id = 0;
128 315         538 my %data = map { $id++ => \$_ } @_;
  6732         12321  
129            
130             # kick off the query
131             #
132 315         908 %data = %{ $self->{_parsedquery}->xeq($fieldAccessor, \%data) };
  315         1095  
133              
134             # only return the number of matches if the full list isn't desired
135             #
136 315 100       1252 return scalar(keys(%data)) unless wantarray();
137              
138             # fix up an array with the matches
139             #
140 312         459 my @matched;
141              
142             # keep the (relative) order they we're given to us by sorting on the artificial
143             # key index we gave them
144             #
145 312         1470 foreach my $k (sort { $a <=> $b } (keys(%data)))
  7140         9208  
146             {
147 2641         3091 push(@matched, ${$data{$k}});
  2641         4190  
148             }
149            
150             # now return the result list
151             #
152 312         5850 return @matched;
153             }
154              
155             1;
156              
157             =head1 NAME
158              
159             Grep::Query - Query logic for lists of scalars/objects
160              
161             =head1 VERSION
162              
163             Version 1.011
164              
165             =head1 SYNOPSIS
166              
167             use Grep::Query qw(qgrep);
168            
169             my @data = ( 'a' .. 'z' );
170             my @result;
171              
172             # very simple query equal to a standard "grep(/[dkob]/, @data)"
173             #
174             @result = qgrep('REGEXP([dkob])', @data);
175             #
176             # @result contains ( 'd', 'k', 'o', 'b' )
177            
178             # go more wild
179             #
180             @result = qgrep('REGEXP([dkob]) AND ( REGEXP([yaxkz]) OR REGEXP([almn]) )', @data);
181             #
182             # @result contains ( 'k' )
183              
184             # or use it in OO fashion
185             #
186             my $gq = Grep::Query->new('REGEXP([dkob]) AND ( REGEXP([yaxkz]) OR REGEXP([almn]) )');
187             @result = $gq->qgrep(@data);
188            
189             # also query a list of objects, and use numerical comparisons too
190             #
191             my @persons = ...; # assume person objects can respond to '->getName()' and '->calculateAge()'
192            
193             # create a query object - note that the syntax now references 'field' names of name/age in the query
194             #
195             my $personQuery = Grep::Query->new('name.REGEXP(^A) AND age.>=(42)');
196            
197             # set up a field accessor to teach G::Q how to match field names to whatever's needed to get data from the objects
198             #
199             my $fieldAccessor = Grep::Query::FieldAccessor->new();
200             $fieldAccessor->add('name', sub { $_[0]->getName() });
201             $fieldAccessor->add('age', sub { $_[0]->calculateAge() });
202            
203             # now execute the query by passing the field accessor before the person list
204             #
205             @result = $personQuery->qgrep($fieldAccessor, @persons);
206             #
207             # @result contains a list of person objects that has a name starting with 'A' and an age greater than or equal to 42
208            
209             =head1 BACKGROUND
210              
211             Why use this module when you could easily write a grep BLOCK or plain regexp
212             EXPR to select things in a list using whatever criteria you desired?
213              
214             =head2 The original use-case was this:
215              
216             Given a number of commandline tools I provide to users in my workplace, quite
217             frequently I wanted the user to be able to express, with some flag(s), a
218             selection among a list of 'somethings' computed at runtime - the most common
219             probably a list of file/directory names. It was also common to have this type
220             of filtering defined in various configuration files and persistently apply them
221             every time a command was run.
222              
223             Example: the user gives the command:
224              
225             SomeCommand /some/path
226              
227             The 'SomeCommand' may, for example, scan the given path and for all files it finds it will
228             do something useful. So, I also wanted to provide flags for the command such
229             that they can say...
230              
231             SomeCommand -exclude 'some_regexp' /some/path
232              
233             ...in order to filter the list of files that should be worked on.
234              
235             Obviously not a problem, and I also provided the reverse if that was more
236             convenient:
237              
238             SomeCommand -include 'another_regexp' /some/path
239              
240             And the idea was extended so flags could be given multiple times and
241             interweaved:
242              
243             SomeCommand -include 'rx1' -exclude 'rx2' -include 'rx3' ... /some/path
244              
245             Thus, the original set was shrunk by first selecting only those matching the
246             regexp C and then shrink that by excluding those matching C etc. - I
247             think you get the idea.
248              
249             What I found however is that it becomes hard to string together regexps to find
250             the exact subset you want when the rules are a bit more complex. In fact, while
251             regexps are powerful, they're not that suited to easily mix multiple of them
252             (and some expressions are basically impossible, e.g. 'I want this but not this'),
253             especially when you try to provide a commandline interface to them...
254              
255             Thus, instead I'd wanted to provide a more capable way for a user to give a
256             more complex query, i.e. where it'd be possible to use AND/OR/NOT as well as
257             parenthesized groups, e.g. something like this (very contrived and structured
258             on several lines for readability):
259              
260             (
261             REGEXP/some_rx_1/ AND REGEXP/some_rx_2/
262             )
263             OR
264             (
265             REGEXP/some_rx_3/ AND NOT REGEXP/some_rx_4/
266             )
267             OR
268             NOT
269             (
270             REGEXP/some_rx_5/ OR NOT REGEXP/some_rx_6/
271             )
272              
273             Basically, feed 'something' the query and a list of scalars and get back a list
274             of the subset of scalars that fulfills the query. In short, behaving like a
275             grep, you might say, but where the normal BLOCK or EXPR is a query decided by
276             the user
277              
278             As it turned out, once the basics above was functioning I added some other
279             features, such as realizing that lists were not always just simple scalars, but
280             could just as well be "objects" and also that it then was useful to use
281             numerical comparisons rather than just regular expressions.
282              
283             Hence, this module to encapsulate the mechanism.
284              
285             =head3 Is it for you?
286              
287             It may be comparatively slow and very memory-intensive depending on the
288             complexity of the query and the size of the original data set.
289              
290             If your needs can be met by a regular grep call, utilizing a regular expression
291             directly, or using a block of code you can write beforehand, this module
292             probably isn't necessary, although it might be convenient if your block is
293             complex enough.
294              
295             =head1 DESCRIPTION
296              
297             The visible API is made to be simple but also compact - the single method/function
298             C, actually. For the slightly more complex scenarios a helper class is
299             required, but generally a very simple one giving high flexibility in how to structure
300             the query itself regardless of how the list itself is laid out.
301              
302             It has a behavior similar to C - give it a list and get back a list (or
303             in scalar context, the number of matches). The main difference is that the
304             matching stuff is a query expressed in a fairly simple language.
305              
306             It can be used in both non-OO and OO styles. The latter obviously useful when
307             the query will be used multiple times so as to avoid parsing the query every
308             time.
309              
310             The basic intent is to make it easy to do the easy stuff while still making it
311             easy to move up to something more complex, without having a wide or wordy API.
312             This is a two-edged sword - I hope this will not be confusing.
313              
314             =head2 QUERY LANGUAGE
315              
316             A query effectively have two slightly different "modes", depending on if the
317             query is aimed at a list of ordinary scalars or if the list consists of objects
318             (or plain hashes, which is regarded as a special case of objects). There is
319             also a special case when you pass only a single hash ref - it can be treated
320             as a list, and a new hash ref with matching key/value pairs passed back.
321              
322             =over
323              
324             =item Scalars
325              
326             In the first case, the query doesn't use "field" names - it is implicit that
327             the comparison should be made directly on scalars in the list.
328              
329             Note that is possible to use field names if desired - just make the accessors
330             so that it properly extracts parts of each scalar.
331              
332             =item Hashes/Objects
333              
334             In the second case, the query uses field names for the comparisons and
335             therefore a "field accessor" object is required when executing the query so as
336             to provide the query engine with the mapping between a field name and the data.
337              
338             A special case occurs when the list consists of hashes with keys being exactly
339             the field names - if so, the query engine can transparently create the
340             necessary field accessor if one is not passed in.
341              
342             The default field accessor also understands 'navigation paths', i.e. handling
343             a deep structure with lists-in-lists/hashes etc. This will work to any depth.
344              
345             =back
346              
347             It's important to note that either the query uses field names everywhere, or
348             not at all. Mixing comparisons with field names and others without is illegal.
349              
350             For hashes/objects it's necessary to use field names - otherwise you will match
351             against scalar representations of hashref values for example, e.g. 'HASH(0x12345678)'.
352             Hardly useful.
353              
354             =head3 SYNTAX
355              
356             The query language syntax is fairly straightforward and can be divided in two main
357             parts: the logical connectors and the comparison atoms.
358              
359             In the tables below, note that case is irrelevant, i.e. 'AND' is equal to 'and' which is
360             equal to 'And' and so on.
361              
362             =over
363              
364             =item Comments
365              
366             Comments can be used in the query using the begin/end style like '/* some comment */'.
367              
368             =item Logical connectors
369              
370             In this category we find the basic logic operators used to tie comparisons
371             together, i.e AND/OR/NOT and parentheses to enforce order.
372              
373             =over
374              
375             =item * B or B
376              
377             Used to negate the list generated by an expression.
378              
379             =item * B or B<&&>
380              
381             Used to select the intersection of two lists formed by expressions before and
382             after.
383              
384             =item * B or B<||>
385              
386             Used to select the union of two lists formed by expressions before and
387             after.
388              
389             =item * B<()>
390              
391             Used to enforce a grouping order.
392              
393             =back
394              
395             =item Comparison atoms
396              
397             A comparison atom is how to describe a match. It can be divided in string and
398             numeric matches. A complete atom can contain the following:
399              
400             IB<.>IBIB
401              
402             The I is optional. If given, it is terminated with a period (B<.>).
403             It cannot contain a period or a space, but otherwise it can be any text that
404             can be used as a hash key.
405              
406             The rest of the expression consists of an I and a I to be used
407             by that operator delimited by B and B. To
408             accommodate values happening to use characters normally used in a delimiter,
409             choice of character(s) is very flexible. The delimiters can be of two different
410             kinds. Either common start/stop pairs like parentheses: I<()>, braces: I<{}>,
411             brackets: I<[]> or angles: IE>. Or, it can be an arbitrary character except
412             space, and the same character again after the value, e.g. I.
413              
414             The Is are:
415              
416             =over
417              
418             =item * B or B
419              
420             These operators always evaluate to true and false respectively. They take no argument.
421              
422             =item * B
423              
424             This matches if the value is defined (i.e. not 'undef'). It takes no argument.
425              
426             =item * B
427              
428             This is different from the others. It is intended for searching through datastructures,
429             not just strings. As such the use of it B a field name (you can not give a field name
430             to it so it is not relevant as such, but if you use other operators, they need to be prefixed
431             with a field name). Also, it implies that the search is done through field accessor (the default
432             is ok).
433              
434             Ordinarily, the 'value' to compare with is a static value, but for the C operator, it should
435             be a L expression, typically a query expression (e.g. using a 'filter', C.
436             If the expression generates a result, it is considered to match.
437             Use this with care - know your data, and try to craft your queries well as performance may suffer a lot
438             if the queries are very 'wide'.
439              
440             =item * BopE>
441              
442             This matches if the value has the given 'size' argument, where the size depends on the
443             data type - a scalar is simply the (text) length, an array is the array size, and a hash
444             is the number of pairs.
445              
446             This is slightly different from the others in that an C must be given, i.e. how to
447             compare the value - B<==>, B, B>, B=>, B>, B=>
448              
449             =item * B
450              
451             This matches if the value has the given 'type' argument, where the type can be 'scalar',
452             'array' or 'hash'.
453              
454             =item * B
455              
456             This matches if the value is a hash, and has a key with the given argument.
457              
458             =item * B or B<=~>
459              
460             This operator expects to use the I as a regular expression for use in
461             matching.
462              
463             =item * B, B, B, B, B, B
464              
465             These are B based matches, i.e. I, I, I,
466             I, I and I.
467              
468             Don't confuse these with the B comparisons - results will likely
469             be unexpected since using these means that "2" is greater than "19"...
470              
471             =item * B<==>, B, B>, B=>, B>, B=>
472              
473             These are B matches.
474              
475             =back
476              
477             =back
478              
479             =head3 EXAMPLES
480              
481             # in normal Perl code, we would for example write:
482             #
483             my $v = "abcdefgh";
484             if ($v =~ /abc/)
485             {
486             ...
487             }
488            
489             # equivalent ways to write the regexp in a query would be:
490             #
491             REGEXP(abc)
492             regexp(abc) # case doesn't matter
493             =~(abc) # in case you're more comfortable with the Perl operator
494             =~{abc} # braces as delimiters
495             =~[abc] # brackets as delimiters
496             =~ # angles as delimiters
497             =~/abc/ # Perlish
498             =~dabcd # works, but quite confusing
499            
500             # a compound query with fields
501             #
502             name.REGEXP(^A) AND age.>=(42) # field names before the operators
503              
504             =head1 METHODS/FUNCTIONS
505              
506             =head2 new( $query )
507              
508             Constructor for a Grep::Query object if using the OO interface.
509              
510             The argument query string is required.
511              
512             Croaks if a problem is discovered.
513              
514             =head3 EXAMPLE
515              
516             # create a G::Q object
517             #
518             my $gq = Grep::Query->new('==(42) OR >(100)');
519              
520             =head2 getQuery()
521              
522             Returns the original query text.
523              
524             =head2 qgrep
525              
526             Execute a query.
527              
528             This method can be called in a few different ways, depending on if it's used in
529             an OO fashion or not, or if the query contains field names or not.
530              
531             Croaks if something is wrong.
532              
533             Return value: Number of matches in the given data list if called in scalar
534             context, the matching list otherwise. The return list will keep the relative order as the
535             original data list. A notable exception: if called in void context, the query
536             is skipped altogether - seems to be no point in spending a lot of work when no
537             one's interested in the results, right?
538              
539             =over
540              
541             =item * Non-OO, no fields: qgrep( $query, @data )
542              
543             The given C<$query> string will be parsed on the fly and executed against the
544             C<@data>.
545              
546             =item * Non-OO, with fields: qgrep( $query, $fieldAccessor, @data )
547              
548             The given C<$query> string will be parsed on the fly and executed against the
549             data, using the C<$fieldAccessor> object to get values from C<@data> objects.
550              
551             Note: In a certain case, the C<$fieldAccessor> argument can be passed as
552             C and it will be auto-generated. See below for details.
553            
554              
555             =item * OO, no fields: $obj->qgrep( @data )
556              
557             The C<$obj> must first have been created using L and then it can be
558             executed against the C<@data>.
559              
560             =item * OO, with fields: $obj->qgrep( $fieldAccessor, @data )
561              
562             The C<$obj> must first have been created using L and then it can be
563             executed, using the C<$fieldAccessor> object to get values from C<@data>
564             objects.
565              
566             Note: In a certain case, the C<$fieldAccessor> argument can be passed as
567             C and it will be auto-generated. See below for details.
568              
569             =item * Passing a single hashref: qgrep($fieldAccessor, \%hash)
570              
571             In this case, the field accessor methods will be called with two-item
572             arrayrefs, e.g. the key is in the first (0) slot, and the value is in the
573             second (1) slot.
574              
575             =back
576              
577             =head3 Autogenerated field accessor
578              
579             If the C<@data> holds plain hashes with keys exactly corresponding to the field
580             names used in the query, the query engine can autogenerate a field accessor.
581              
582             This is only a convenience, a manually constructed field accessor will be used
583             if given. To take advantage of the convenience, simply pass C as the
584             C<$fieldAccessor> argument.
585              
586             If you have a deep structure, you may use 'field' names connected by '->' linkages,
587             where raw text are used as regular hash keys and array indexes are denoted using
588             []. When the end of the navigation path has been reached the object at that
589             location is returned.
590              
591             =head3 EXAMPLES
592              
593             # sample data
594             my @scalarData = ( 105, 3, 98, 100, 42, 101, 42 );
595              
596             # make sure to import the qgrep function
597             #
598             use Grep::Query qw(qgrep);
599            
600             # now call it directly
601             #
602             my $matches = qgrep('==(42) OR >(100)', @scalarData);
603             #
604             # $matches is now 4 (matching 105, 42, 101, 42)
605            
606             # or equivalently, create a G::E object and call the method on it
607             #
608             my $gq = Grep::Query->new('==(42) OR >(100)');
609             $matches = $gq->qgrep(@scalarData);
610             #
611             # $matches again 4
612            
613             # some sample fielded data in a hash
614             #
615             my @hashData =
616             (
617             { x => 52, y => 38 },
618             { x => 94, y => 42 },
619             { x => 25, y => 77 }
620             );
621            
622             # autogenerate a field accessor since the query matches the fields
623             #
624             $matches = qgrep('x.>(20) AND y.>(40)', undef, @hashData);
625             #
626             # $matches is now 2 (matching last two entries)
627            
628             # but using different field names (or if it was opaque objects used)
629             # we must provide an explicit field accessor
630             #
631             my $fieldAccessor = Grep::Query::FieldAccessor->new
632             (
633             {
634             fieldY => sub { $_[0]->{y} },
635             fieldX => sub { $_[0]->{x} },
636             }
637             );
638             $matches = qgrep('fieldX.>(20) AND fieldY.>(40)', $fieldAccessor, @hashData);
639             #
640             # $matches again 2
641            
642             # a hash with depth
643             #
644             my @hashData =
645             (
646             { x => { fee => 1, fie => 2, foo => 3 }, y => [ 2, 4, 6 ] },
647             { x => { fee => 10, fie => 20, foo => 30 }, y => [ 12, 14, 16 ] },
648             { x => { fee => 100, fie => 200, foo => 300 }, y => [ 22, 24, 26 ] },
649             );
650             $matches = qgrep('x->fie.>(30) AND y->[2].>(20)', undef, @hashData);
651             #
652             # $matches is now 1 (matching last entry)
653            
654             =head1 AUTHOR
655              
656             Kenneth Olwing, C<< >>
657              
658             =head1 BUGS
659              
660             Please report any bugs or feature requests to C,
661             or through the web interface at
662             L. I will be
663             notified, and then you'll automatically be notified of progress on your bug as
664             I make changes.
665              
666             =head1 SUPPORT
667              
668             You can find documentation for this module with the perldoc command.
669              
670             perldoc Grep::Query
671              
672             You can also look for information at:
673              
674             =over 4
675              
676             =item * RT: CPAN's request tracker (report bugs here)
677              
678             L
679              
680             =item * AnnoCPAN: Annotated CPAN documentation
681              
682             L
683              
684             =item * CPAN Ratings
685              
686             L
687              
688             =item * Search CPAN
689              
690             L
691              
692             =back
693              
694             =head1 ACKNOWLEDGEMENTS
695              
696             First and foremost, I thank my family for putting up with me!
697              
698             =over
699              
700             =item David Mertens, C<< >> for the name.
701              
702             =item Ron Savage, C<< >> for helping follow current best
703             practices for modules.
704              
705             =back
706              
707             =head1 REPOSITORY
708              
709             L.
710              
711             =head1 LICENSE AND COPYRIGHT
712              
713             Copyright 2016 Kenneth Olwing.
714              
715             This program is free software; you can redistribute it and/or modify it
716             under the terms of the the Artistic License (2.0). You may obtain a
717             copy of the full license at:
718              
719             L
720              
721             Any use, modification, and distribution of the Standard or Modified
722             Versions is governed by this Artistic License. By using, modifying or
723             distributing the Package, you accept this license. Do not use, modify,
724             or distribute the Package, if you do not accept this license.
725              
726             If your Modified Version has been derived from a Modified Version made
727             by someone other than you, you are nevertheless required to ensure that
728             your Modified Version complies with the requirements of this license.
729              
730             This license does not grant you the right to use any trademark, service
731             mark, tradename, or logo of the Copyright Holder.
732              
733             This license includes the non-exclusive, worldwide, free-of-charge
734             patent license to make, have made, use, offer to sell, sell, import and
735             otherwise transfer the Package with respect to any patent claims
736             licensable by the Copyright Holder that are necessarily infringed by the
737             Package. If you institute patent litigation (including a cross-claim or
738             counterclaim) against any party alleging that the Package constitutes
739             direct or contributory patent infringement, then this Artistic License
740             to you shall terminate on the date that such litigation is filed.
741              
742             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
743             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
744             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
745             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
746             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
747             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
748             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
749             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
750              
751             =cut