File Coverage

blib/lib/Newtype.pm
Criterion Covered Total %
statement 163 184 88.5
branch 53 74 71.6
condition 21 54 38.8
subroutine 38 48 79.1
pod 3 3 100.0
total 278 363 76.5


line stmt bran cond sub pod time code
1 7     7   2211471 use 5.014;
  7         67  
2 7     7   77 use strict;
  6         17  
  6         130  
3 6     7   38 use warnings;
  7         30  
  7         380  
4              
5             package Newtype;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.001';
9              
10 7     7   3000 use Type::Tiny::Class 2.000000;
  6         115081  
  6         55  
11 6     7   3503 use parent 'Type::Tiny::Class';
  7         1799  
  7         38  
12              
13 7     6   472 use B qw( perlstring );
  6         17  
  6         307  
14 6     6   1560 use Eval::TypeTiny qw( eval_closure set_subname );
  7         7581  
  7         43  
15 7     6   4250 use Types::Common qw( -types -is );
  6         599829  
  6         48  
16 6     6   145530 use namespace::autoclean;
  6         108454  
  7         59  
17              
18             sub _exporter_fail {
19 5     5   20859 my ( $class, $name, $opts, $globals ) = @_;
20 5         16 my $caller = $globals->{into};
21              
22 5         11 $opts->{caller} = $caller;
23 5         13 $opts->{name} = $name;
24              
25 5         17 my $type = $class->new( $opts );
26              
27             $INC{'Type/Registry.pm'}
28             ? 'Type::Registry'->for_class( $caller )->add_type( $type )
29             : ( $Type::Registry::DELAYED{$caller}{$type->name} = $type )
30 5 100 33     140 unless( ref($caller) or $caller eq '-lexical' or $globals->{'lexical'} );
    50 33        
31              
32 5         96 return map +( $_->{name} => $_->{code} ), @{ $type->_newtype_exportables };
  5         51  
33             }
34              
35             sub new {
36 14     14 1 149967 my $class = shift;
37              
38 14 100       88 if ( is_Object $class ) {
39 2         16 my $real_class = $class->class;
40 2         17 return $real_class->new( $class->inner_type->( shift ) );
41             }
42              
43 12 100 66     97 my %opts = ( @_ == 1 and is_HashRef $_[0] ) ? %{ $_[0] } : @_;
  6         31  
44              
45 12 100       93 if ( is_Undef $opts{inner} ) {
    100          
46 1         10 die "Expected option: inner";
47             }
48             elsif ( is_Str $opts{inner} ) {
49 2         14 $opts{inner} = 'Type::Tiny::Class'->new( class => $opts{inner} );
50             }
51              
52 11         576 $opts{class} = $class->_make_newclass_name( \%opts );
53              
54 11         84 return $class
55             ->SUPER::new( %opts )
56             ->_make_newclass()
57             ->_make_coercions();
58             }
59              
60             # Attributes
61 52     52 1 7096 sub inner_type { $_[0]{inner} }
62 37   66 37 1 778 sub kind { $_[0]{kind} ||= $_[0]->_build_kind }
63              
64             sub _build_kind {
65 10     10   21 my $self = shift;
66 10         28 my $inner_type = $self->inner_type;
67              
68 10 100       62 return 'Array' if $inner_type->is_a_type_of( ArrayRef );
69 9 50       13795 return 'Bool' if $inner_type->is_a_type_of( Bool );
70 9 50       9515 return 'Code' if $inner_type->is_a_type_of( CodeRef );
71 9 100       11715 return 'Counter' if $inner_type->is_a_type_of( Int );
72 7 100       11906 return 'Hash' if $inner_type->is_a_type_of( HashRef );
73 3 100 66     4409 return 'Number' if $inner_type->is_a_type_of( StrictNum )
74             || $inner_type->is_a_type_of( LaxNum ); ##WS
75 2 50       6073 return 'Object' if $inner_type->is_a_type_of( Object );
76 0 0       0 return 'String' if $inner_type->is_a_type_of( Str );
77              
78 0         0 die "Could not determine kind of inner type. Specify 'kind' option";
79             }
80              
81             sub _newtype_exportables {
82 5     5   17 my $self = shift;
83 5         23 my $inner_type = $self->inner_type;
84 5         17 my @exportables = @{ $self->exportables( @_ ) };
  5         51  
85 5         5283 for my $e ( @exportables ) {
86 20 100       64 if ( $e->{tags}[0] eq 'types' ) {
87             $e->{code} = sub (;$) {
88 12 100   12   14521 my ( $inner_value, @rest ) = @_
89             or return $self;
90 7         84 $inner_type->( $inner_value );
91 7         1150 my $wrapped_value = bless( \$inner_value, $self->{class} );
92 7 100       74 wantarray ? ( $wrapped_value, @rest ) : $wrapped_value;
93 5         86 };
94             }
95             }
96 5         105 \@exportables;
97             }
98              
99             sub _make_newclass_name {
100 11     11   29 my ( $class, $opts ) = @_;
101 11         78 return sprintf '%s::Newtype::%s', $opts->{caller}, $opts->{name};
102             }
103              
104             sub _make_newclass {
105 11     11   2360 my ( $self ) = @_;
106              
107 11         53 my $class = $self->class;
108 11         72 $self
109             ->_make_newclass_basics( $class )
110             ->_make_newclass_overloading( $class )
111             ->_make_newclass_metamethods( $class )
112             ->_make_newclass_native_methods( $class )
113             ->_make_newclass_custom_methods( $class );
114              
115 11         63 return $self;
116             }
117              
118             sub _make_newclass_basics {
119 11     11   28 my ( $self, $class ) = @_;
120              
121 11         33 my $inner_name = sprintf( '%s::INNER', $class );
122 11         61 my $inner_code = eval_closure(
123             environment => {},
124             source => q{
125             sub {
126             my $self = shift;
127             $$self;
128             }
129             },
130             );
131              
132 11         2189 my $constructor_name = sprintf( '%s::new', $class );
133 11         40 my $constructor_code = eval_closure(
134             environment => {},
135             source => q{
136             sub {
137             my ( $class, $inner_value ) = @_;
138             bless( \$inner_value, $class );
139             }
140             },
141             );
142              
143             {
144 7     6   6327 no strict 'refs';
  7         59  
  6         6757  
  11         1879  
145 11         46 *{$inner_name} = set_subname( $inner_name, $inner_code );
  11         234  
146 11         54 *{$constructor_name} = set_subname( $constructor_name, $constructor_code );
  11         202  
147             }
148              
149 11         55 return $self;
150             }
151              
152             sub _make_newclass_overloading {
153 11     11   36 my ( $self, $class ) = @_;
154              
155             my $overloading = {
156             Array => '( q[@{}] => sub { ${+shift} }, bool => sub { !!1 }, fallback => 1 )',
157             Bool => '( bool => sub { !!${+shift} }, fallback => 1 )',
158             Code => '( q[&{}] => sub { ${+shift} }, bool => sub { !!1 }, fallback => 1 )',
159             Counter => '( q[0+] => sub { ${+shift} }, bool => sub { ${+shift} }, fallback => 1 )',
160             Hash => '( q[%{}] => sub { ${+shift} }, bool => sub { !!1 }, fallback => 1 )',
161             Number => '( q[0+] => sub { ${+shift} }, bool => sub { ${+shift} }, fallback => 1 )',
162             String => '( q[""] => sub { ${+shift} }, bool => sub { ${+shift} }, fallback => 1 )',
163 11 100       121 }->{ $self->kind } or return $self;
164              
165 9         3594 local $@;
166 9 50       1125 eval "package $class; use overload $overloading; 1" or die( $@ );
167              
168 9         42 return $self;
169             }
170              
171             sub _make_newclass_metamethods {
172 11     15   621 my ( $self, $class ) = @_;
173              
174 11         64 my $kind = $self->kind;
175             my $known_class = $self->inner_type->find_parent( sub {
176 63     63   1103 $_->isa( 'Type::Tiny::Class' );
177 11         33 } );
178              
179 11 100 66     227 if ( $kind eq 'Object' and is_Defined $known_class ) {
    50          
180 2         9 return $self->_make_newclass_metamethods_for_known_class( $class, $known_class->class );
181             }
182             elsif ( $kind eq 'Object' ) {
183 0         0 return $self->_make_newclass_metamethods_for_generic_object( $class );
184             }
185             else {
186 9         31 return $self->_make_newclass_metamethods_for_kind( $class, $kind );
187             }
188             }
189              
190             sub _make_newclass_metamethods_for_known_class {
191 2     2   14 my ( $self, $class, $parent_class ) = @_;
192              
193 2         4 local $@;
194 2 50 0 13   846 eval q|
  13 50 0 0   1039  
  13 100 0 0   76  
  13 50 0 8   94  
  16 50 0     78319  
  13 50 0     262  
  0 0 33     0  
  3 50 66     35  
  0 100 66     0  
  0   66     0  
  0         0  
  0         0  
  0         0  
  0         0  
  8         6541  
  8         37  
  8         176  
195             package | . $class . q|;
196             sub AUTOLOAD {
197             my $self = shift;
198             my ( $method ) = ( our $AUTOLOAD =~ /::(\w+)$/ );
199             if ( ref($self) ) {
200             if ( $method eq 'DESTROY' ) {
201             my $found = $$self->can( 'DESTROY' ) or return;
202             return $$self->$found( @_ );
203             }
204             return $$self->$method( @_ );
205             }
206             else {
207             return "| . $parent_class . q|"->$method( @_ );
208             }
209             }
210             sub isa {
211             my ( $self, $c ) = @_;
212             $c = $c->class if Scalar::Util::blessed($c) && $c->can('class');
213             ref($self) && $$self->isa( $c ) or
214             "| . $parent_class . q|"->isa( $c ) or
215             $self->UNIVERSAL::isa( $c );
216             }
217             sub DOES {
218             my ( $self, $r ) = @_;
219             $r = $r->class if Scalar::Util::blessed($r) && $r->can('class');
220             $r eq 'Newtype' or
221             $r eq 'Object' or
222             ref($self) && $$self->DOES( $r ) or
223             "| . $parent_class . q|"->DOES( $r ) or
224             $self->UNIVERSAL::DOES( $r );
225             }
226             sub can {
227             my ( $self, $m ) = @_;
228             ref($self) && $$self->can( $m ) or
229             "| . $parent_class . q|"->can( $m ) or
230             $self->UNIVERSAL::can( $m );
231             }
232             1;
233             | or die( $@ );
234              
235 2         13 return $self;
236             }
237              
238             sub _make_newclass_metamethods_for_generic_object {
239 0     0   0 my ( $self, $class ) = @_;
240              
241 0         0 local $@;
242 0 0       0 eval q|
243             package | . $class . q|;
244             sub AUTOLOAD {
245             my $self = shift;
246             ref($self) or return;
247             my ( $method ) = ( our $AUTOLOAD =~ /::(\w+)$/ );
248             if ( $method eq 'DESTROY' ) {
249             my $found = $$self->can( 'DESTROY' ) or return;
250             return $$self->$found( @_ );
251             }
252             $$self->$method( @_ );
253             }
254             sub isa {
255             my ( $self, $c ) = @_;
256             $c = $c->class if Scalar::Util::blessed($c) && $c->can('class');
257             ref($self) && $$self->isa( $c ) or
258             $self->UNIVERSAL::isa( $c );
259             }
260             sub DOES {
261             my ( $self, $r ) = @_;
262             $r = $r->class if Scalar::Util::blessed($r) && $r->can('class');
263             $r eq 'Newtype' or
264             $r eq 'Object' or
265             ref($self) && $$self->DOES( $r ) or
266             $self->UNIVERSAL::DOES( $r );
267             }
268             sub can {
269             my ( $self, $m ) = @_;
270             ref($self) && $$self->can( $m ) or
271             $self->UNIVERSAL::can( $m );
272             }
273             1;
274             | or die( $@ );
275              
276 0         0 return $self;
277             }
278              
279             sub _make_newclass_metamethods_for_kind {
280 9     9   25 my ( $self, $class, $kind ) = @_;
281              
282 9         16 local $@;
283 9 50       1178 eval q|
284             package | . $class . q|;
285             sub DOES {
286             my ( $self, $r ) = @_;
287             $r = $r->class if Scalar::Util::blessed($r) && $r->can('class');
288             $r eq 'Newtype' or
289             $r eq '| . $kind . q|' or
290             $self->UNIVERSAL::DOES( $r );
291             }
292             1;
293             | or die( $@ );
294              
295 9         57 return $self;
296             }
297              
298             sub _make_newclass_native_methods {
299 11     11   42 my ( $self, $class ) = @_;
300              
301 11         28 my $kind = $self->kind;
302 11 100       57 return $self if $kind eq 'Object';
303              
304 9         29 my $inner_type = $self->inner_type;
305 9   66     47 my $type_default = $inner_type->type_default // $self->_kind_default;
306              
307 9         2647 require Sub::HandlesVia::CodeGenerator;
308             my $gen = 'Sub::HandlesVia::CodeGenerator'->new(
309             env => { '$type_default' => \$type_default },
310             target => $class,
311             attribute => 'Newtype',
312             isa => $inner_type,
313             coerce => $inner_type->has_coercion(),
314 272     272   5833 generator_for_self => sub { '$_[0]' },
315 290     290   2644 generator_for_slot => sub { my ( $g ) = @_; sprintf '${%s}', $g->generate_self },
  290         667  
316 224     224   16214 generator_for_get => sub { my ( $g ) = @_; $g->generate_slot },
  224         519  
317 67     67   85975 generator_for_set => sub { my ( $g, $v ) = @_; sprintf '(%s=%s)', $g->generate_slot, $v },
  67         182  
318 9     8   330 generator_for_default => sub { sprintf('$type_default->()') },
319 9         94184 get_is_lvalue => !!1,
320             set_checks_isa => !!0,
321             );
322              
323 9         2537 my $shv_lib = "Sub::HandlesVia::HandlerLibrary::$kind";
324 9 50       679 eval "require $shv_lib; 1" or die( $@ );
325              
326 9         43 my %already;
327 9         72 for my $h_name ( $shv_lib->handler_names ) {
328 207 100       128600 next if $already{$h_name}++;
329 206         1093 my $h = $shv_lib->get_handler( $h_name );
330 206         48688 $gen->generate_and_install_method( $h_name, $h );
331             }
332              
333 9         5276 return $self;
334             }
335              
336             sub _kind_default {
337 1     1   30 my ( $self ) = @_;
338              
339             return {
340 0     0   0 Array => sub { [] },
341 0     0   0 Bool => sub { !!0 },
342 0     0   0 Code => sub { sub {} },
343 0     0   0 Counter => sub { 0 },
344 0     0   0 Hash => sub { {} },
345 0     0   0 Number => sub { 0 },
346 0     0   0 String => sub { '' },
347 1         13 }->{ $self->kind };
348             }
349              
350             sub _make_newclass_custom_methods {
351 11     11   430 my ( $self, $class ) = @_;
352              
353 6     6   61 no strict 'refs';
  6         18  
  6         1779  
354              
355 11   66     21 my %methods = %{ $self->{methods} // {} };
  11         571  
356 11         56 for my $name ( keys %methods ) {
357 2         7 my $fq_name = "$class\::$name";
358 2         9 *{$fq_name} = set_subname( $fq_name, $methods{$name} );
  2         36  
359             }
360             }
361              
362             sub _make_coercions {
363 11     11   28 my $self = shift;
364 11         48 my $class = $self->class;
365              
366 11         71 my $inner_type = $self->inner_type;
367 11         103 my $coercion_from_inner_type = sprintf(
368             q{do { my $x = $_; bless( \$x, %s ) }},
369             perlstring( $class ),
370             );
371 11         58 $self->coercion->add_type_coercions(
372             $inner_type,
373             $coercion_from_inner_type,
374             );
375              
376 11 100       2631 if ( $inner_type->has_coercion ) {
377             $self->coercion->add_type_coercions(
378             $inner_type->coercibles(),
379             sub {
380 1     1   1646 my $coerced_inner_value = $inner_type->coerce( $_ );
381 1 50       859 $inner_type->check( $coerced_inner_value ) or return $_;
382 1         20 return bless( \$coerced_inner_value, $class );
383             },
384 1         20 );
385             }
386              
387 11         11870 return $self;
388             }
389              
390             1;
391              
392             __END__
393              
394             =pod
395              
396             =encoding utf-8
397              
398             =head1 NAME
399              
400             Newtype - Perl implementation of an approximation for Haskell's newtype
401              
402             =head1 SYNOPSIS
403              
404             package MyClass;
405            
406             use HTTP::Tiny ();
407             use Newtype HttpTiny => { inner => 'HTTP::Tiny' };
408            
409             use Moo;
410            
411             has ua => (
412             is => 'ro',
413             isa => HttpTiny(),
414             coerce => 1,
415             );
416              
417             =head1 DESCRIPTION
418              
419             This module allows you to create a new type which is a subclass of an existing
420             type.
421              
422             Why?
423              
424             Well maybe you want to add some new methods to the new type:
425              
426             use HTTP::Tiny ();
427             use Newtype HttpTiny => {
428             inner => 'HTTP::Tiny',
429             methods => {
430             'post_or_get' => sub {
431             my $self = shift;
432             my $res = $self->post( @_ );
433             return $res if $res->{success};
434             return $self->get( @_ );
435             },
436             };
437              
438             Or maybe you need to differentiate between two different kinds of things
439             which are otherwise the same class.
440              
441             use Newtype (
442             SecureUA => { inner => 'HTTP::Tiny' },
443             InsecureUA => { inner => 'HTTP::Tiny' },
444             );
445            
446             ...;
447            
448             my $ua = InsecureUA( HTTP::Tiny->new );
449            
450             ...;
451            
452             if ( $ua->isa(SecureUA) ) {
453             ...;
454             }
455              
456             Newtype can also create new types which "inherit" from Perl builtins.
457              
458             use Types::Common qw( ArrayRef PositiveInt );
459             use Newtype Numbers => { inner => ArrayRef[PositiveInt] };
460            
461             my $nums = Numbers( [] );
462             $nums->push( 1 );
463             $nums->push( 2 );
464             $nums->push( -1 ); # dies
465              
466             See L<Hydrogen> for the list of available methods for builtins.
467              
468             Newtypes which inherit from builtins use overloading to attempt to provide
469             transparency.
470              
471             Although there will be exceptions to this general rule of thumb (especially
472             if your newtype is inheriting from a Perl builtin), you can think of things
473             like this: if you create a type B<NewFoo> from existing type B<Foo>, then
474             instances of B<NewFoo> should be accepted everywhere instances of B<Foo> are.
475             But instances of B<Foo> will not be automatically accepted where instances of
476             B<NewFoo> are.
477              
478             =head2 Creating a newtype
479              
480             The general form for creating newtypes is:
481              
482             use Newtype $typename => {
483             inner => $inner_type,
484             %other_options,
485             };
486              
487             The inner type is required, and must be either a string class name or
488             a L<Type::Tiny> type constraint indicating what type of thing you want
489             to wrap.
490              
491             Other supported options are:
492              
493             =over
494              
495             =item C<methods>
496              
497             A hashref of methods to add to the newtype. Keys are the method names.
498             Values are coderefs.
499              
500             =item C<kind>
501              
502             This allows you to give Newtype a hint for how to delegate to the inner
503             value. Supported kinds (case-sensitive) are: Array, Bool, Code, Counter,
504             Hash, Number, Object, and String. Usually Newtype will be able to guess
505             based on C<inner> though.
506              
507             =back
508              
509             =head2 Creating values belonging to the newtype
510              
511             When you import a newtype B<Foo>, you import a function C<< Foo() >>
512             into your namespace. You can create instances of the newtype using:
513              
514             Foo( $inner_value )
515              
516             Where C<< $inner_value >> is an instance of the type you're wrapping.
517              
518             For example:
519              
520             use HTTP::Tiny;
521             use Newtype UA => { inner => 'HTTP::Tiny' };
522            
523             my $ua = UA( HTTP::Tiny->new );
524              
525             I<< Note: >> you also get C<is_Foo>, C<assert_Foo>, and C<to_Foo>
526             functions imported! C<< is_Foo( $x ) >> checks if C<< $x >> is a B<Foo>
527             object and returns a boolean. C<< assert_Foo( $x ) >> does the same,
528             but dies if it fails. C<< to_Foo( $x ) >> attempts to coerce C<< $x >>
529             to a B<Foo> object.
530              
531             =head2 Integration with Moose, Mouse, and Moo
532              
533             If your imported newtype is B<Foo>, then calling C<< Foo() >> with no
534             arguments will return a L<Type::Tiny> type constraint for the newtype.
535              
536             use HTTP::Tiny;
537             use Newtype UA => { inner => 'HTTP::Tiny' };
538            
539             use Moo;
540             has my_ua => ( is => 'ro', isa => UA() );
541              
542             Now people instantiating your class will need to pass you a wrapped
543             HTTP::Tiny object instead of passing a normal HTTP::Tiny object. You may
544             wish to allow them to pass you a normal HTTP::Tiny object though.
545             That should be easy with coercions:
546              
547             has my_ua => ( is => 'ro', isa => UA(), coerce => 1 );
548              
549             =head2 Accessing the inner value
550              
551             You can access the original wrapped value using the C<< INNER >> method.
552              
553             my $ua = UA( HTTP::Tiny->new );
554             my $http_tiny_object = $ua->INNER;
555              
556             =head2 Introspection
557              
558             If your newtype is called B<MyNewtype>, then you can introspect it using
559             a few methods:
560              
561             =over
562              
563             =item C<< MyNewtype->class >>
564              
565             The class powering the newtype.
566              
567             =item C<< MyNewtype->inner_type >>
568              
569             The type constraint for the inner value.
570              
571             =item C<< MyNewtype->kind >>
572              
573             The kind of delegation being used.
574              
575             =back
576              
577             The object returned by C<< MyNewtype() >> is also a L<Type::Tiny> object,
578             so you can call any method from L<Type::Tiny>, such as
579             C<< MyNewtype->check( $value ) >> or C<< MyNewtype->coerce( $value ) >>.
580              
581             =head1 EXAMPLES
582              
583             =head2 Using newtypes instead of named parameters
584              
585             Let's say you have a function like this:
586              
587             sub run_processes {
588             my ( $runtime_processes, $startup_processes, $shutdown_processes ) = @_;
589             $_->() for @$startup_processes;
590             $_->() for @$runtime_processes;
591             $_->() for @$shutdown_processes;
592             }
593              
594             This function takes three arrayrefs of coderefs. It's very easy for the
595             caller to forget what order to pass them in, and potentially pass them in
596             the wrong order.
597              
598             Let's bring some newtypes into the mix:
599              
600             use feature 'state';
601             use Types::Common qw( CodeRef, ArrayRef );
602             use Type::Params qw( signature );
603             use Newtype (
604             StartupProcessList => { inner => ArrayRef[CodeRef] },
605             RuntimeProcessList => { inner => ArrayRef[CodeRef] },
606             ShutdownProcessList => { inner => ArrayRef[CodeRef] },
607             );
608            
609             sub run_processes {
610             state $sig = signature positional => [
611             RuntimeProcessList->no_coercions,
612             StartupProcessList->no_coercions,
613             ShutdownProcessList->no_coercions,
614             ];
615             my ( $runtime_processes, $startup_processes, $shutdown_processes ) = &$sig;
616             $_->() for @$startup_processes;
617             $_->() for @$runtime_processes;
618             $_->() for @$shutdown_processes;
619             }
620              
621             Now your function no longer accepts bare arrayrefs. Instead the caller needs
622             to convert their arrayrefs into your newtype. The need to call your function
623             like this:
624              
625             run_processes(
626             RuntimeProcessList( \@coderefs1 ),
627             StartupProcessList( \@coderefs2 ),
628             ShutdownProcessList( \@coderefs3 ),
629             );
630              
631             If they try to pass the lists in the wrong order, they'll get a type constraint
632             error.
633              
634             Exporting the C<RuntimeProcessList>, C<StartupProcessList>, and
635             C<ShutdownProcessList> functions to your caller is left as an exercise
636             for the reader!
637              
638             =head1 BUGS
639              
640             Please report any bugs to
641             L<https://github.com/tobyink/p5-newtype/issues>.
642              
643             =head1 SEE ALSO
644              
645             L<Type::Tiny::Class>, L<Subclass::Of>.
646              
647             L<https://wiki.haskell.org/Newtype>.
648              
649             =head1 AUTHOR
650              
651             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
652              
653             =head1 COPYRIGHT AND LICENCE
654              
655             This software is copyright (c) 2022 by Toby Inkster.
656              
657             This is free software; you can redistribute it and/or modify it under
658             the same terms as the Perl 5 programming language system itself.
659              
660             =head1 DISCLAIMER OF WARRANTIES
661              
662             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
663             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
664             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
665