File Coverage

blib/lib/JSON/Schema/Helper.pm
Criterion Covered Total %
statement 192 252 76.1
branch 136 222 61.2
condition 77 164 46.9
subroutine 23 24 95.8
pod 0 9 0.0
total 428 671 63.7


line stmt bran cond sub pod time code
1             package JSON::Schema::Helper;
2              
3             ###
4             # JSONSchema Validator - Validates JavaScript objects using JSON Schemas
5             # (http://www.json.com/json-schema-proposal/)
6             #
7             # Copyright (c) 2007 Kris Zyp SitePen (www.sitepen.com)
8             # Licensed under the MIT (MIT-LICENSE.txt) license.
9             #To use the validator call JSONSchema.validate with an instance object and an optional schema object.
10             #If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
11             #that schema will be used to validate and the schema parameter is not necessary (if both exist,
12             #both validations will occur).
13             #The validate method will return an array of validation errors. If there are no errors, then an
14             #empty list will be returned. A validation error will have two properties:
15             #"property" which indicates which property had the error
16             #"message" which indicates what the error was
17             ##
18              
19             # TODO: {id}, {dependencies}
20              
21 9     9   136 use 5.010;
  9         27  
22 9     9   40 use strict qw( vars subs );
  9         14  
  9         264  
23 9     9   45 use constant FALSE => !1;
  9         27  
  9         717  
24 9     9   40 use constant TRUE => !!1;
  9         14  
  9         419  
25 9     9   5860 no autovivification;
  9         7847  
  9         36  
26              
27 9     9   428 use JSON qw[-convert_blessed_universally];
  9         14  
  9         61  
28 9     9   2591 use JSON::Hyper;
  9         19  
  9         197  
29 9     9   4958 use JSON::Schema::Null;
  9         24  
  9         255  
30 9     9   7160 use POSIX qw[modf];
  9         74866  
  9         74  
31 9     9   12227 use Scalar::Util qw[blessed];
  9         19  
  9         461  
32 9     9   8349 use match::simple qw[match];
  9         30329  
  9         66  
33              
34             our $AUTHORITY = 'cpan:TOBYINK';
35             our $VERSION = '0.016';
36              
37             sub new
38             {
39 55     55 0 141 my ($class, %args) = @_;
40 55   33     310 $args{hyper} //= JSON::Hyper->new;
41 55   50     1137 $args{errors} //= [];
42 55   50     129 $args{format} //= {};
43 55         153 return bless \%args, $class;
44             }
45              
46             sub validate
47             {
48 55     55 0 79 my ($self, $instance, $schema) = @_;
49             ## Summary:
50             ## To use the validator call JSONSchema.validate with an instance object and an optional schema object.
51             ## If a schema is provided, it will be used to validate. If the instance object refers to a schema (self-validating),
52             ## that schema will be used to validate and the schema parameter is not necessary (if both exist,
53             ## both validations will occur).
54             ## The validate method will return an object with two properties:
55             ## valid: A boolean indicating if the instance is valid by the schema
56             ## errors: An array of validation errors. If there are no errors, then an
57             ## empty list will be returned. A validation error will have two properties:
58             ## property: which indicates which property had the error
59             ## message: which indicates what the error was
60             ##
61 55         134 return $self->_validate($instance, $schema, FALSE);
62             }
63              
64             sub checkPropertyChange
65             {
66 0     0 0 0 my ($self, $value, $schema, $property) = @_;
67 0   0     0 $property //= 'property';
68             ## Summary:
69             ## The checkPropertyChange method will check to see if an value can legally be in property with the given schema
70             ## This is slightly different than the validate method in that it will fail if the schema is readonly and it will
71             ## not check for self-validation, it is assumed that the passed in value is already internally valid.
72             ## The checkPropertyChange method will return the same object type as validate, see JSONSchema.validate for
73             ## information.
74             ##
75 0         0 return $self->_validate($value, $schema, $property);
76             }
77              
78             sub _validate
79             {
80 55     55   95 my ($self, $instance, $schema, $_changing) = @_;
81            
82 55         112 $self->{errors} = [];
83            
84 55 50       136 if ($schema)
85             {
86 55   50     185 $self->checkProp($instance, $schema, '', ($_changing // ''), $_changing);
87             }
88 55 50 33     515 if(!$_changing and defined $instance and ref $instance eq 'HASH' and defined $instance->{'$schema'})
      33        
      33        
89             {
90 0         0 $self->checkProp($instance, $instance->{'$schema'}, '', '', $_changing);
91             }
92            
93             return {
94 55         367 valid => (@{$self->{errors}} ? FALSE : TRUE),
95             errors => $self->{errors},
96 55 100       67 };
97             }
98              
99             sub checkType
100             {
101 185     185 0 352 my ($self, $type, $value, $path, $_changing, $schema) = @_;
102            
103 185         198 my @E;
104             my $addError = sub
105             {
106 34     34   46 my ($message) = @_;
107 34         87 my $e = { property=>$path, message=>$message };
108 34         61 foreach (qw(title description))
109             {
110             $e->{$_} = $schema->{$_}
111 68 50       182 if defined $schema->{$_};
112             }
113 34         63 push @E, $e;
114 185         598 };
115            
116 185 100       440 if ($type)
117             {
118             # if (ref $type ne 'HASH'
119             # and $type ne 'any'
120             # and ($type eq 'null' ? $self->jsIsNull($value) : $self->jsMatchType($type, $value))
121             # and !(ref $value eq 'ARRAY' and $type eq 'array')
122             # and !($type eq 'integer' and $value % 1 == 0))
123 155 100       483 if (ref $type eq 'ARRAY')
    100          
    100          
124             {
125 23         22 my @unionErrors;
126 23         37 TYPE: foreach my $t (@$type)
127             {
128 51         105 @unionErrors = $self->checkType($t, $value, $path, $_changing, $schema);
129 51 100       149 last unless @unionErrors;
130             }
131 23 100       92 return @unionErrors if @unionErrors;
132             }
133             elsif (ref $type eq 'HASH')
134             {
135 17         36 local $self->{errors} = [];
136 17         59 $self->checkProp($value, $type, $path, undef, $_changing);
137 17         18 return @{ $self->{errors} };
  17         97  
138             }
139             elsif (!$self->jsMatchType($type, $value))
140             {
141 34         73 $addError->($self->jsGuessType($value)." value found, but a $type is required");
142 34         215 return @E;
143             }
144             }
145 122         530 return;
146             }
147              
148             # validate a value against a property definition
149             sub checkProp
150             {
151 165     165 0 317 my ($self, $value, $schema, $path, $i, $_changing) = @_;
152 165         174 my $l;
153 165 100       348 $path .= $path ? ".${i}" : "\$${i}";
154            
155             my $addError = sub
156             {
157 26     26   443 my ($message) = @_;
158 26         79 my $e = { property => $path, message => $message };
159 26         51 foreach (qw(title description))
160             {
161             $e->{$_} = $schema->{$_}
162 52 50       149 if defined $schema->{$_};
163             }
164 26         28 push @{$self->{errors}}, $e;
  26         68  
165 165         585 };
166            
167 165 50 33     443 if (ref $schema ne 'HASH' and ($path or ref $schema ne 'CODE'))
      66        
168             {
169 12 50       34 if (ref $schema eq 'CODE')
    50          
170             {
171             # ~TOBYINK: I don't think this makes any sense in Perl
172 0         0 $addError->("is not an instance of the class/constructor " . $schema);
173             }
174             elsif ($schema)
175             {
176 0         0 $addError->("Invalid schema/property definition " . $schema);
177             }
178 12         50 return undef;
179             }
180            
181 153         223 eval { $self->{'hyper'}->process_includes($schema, $self->{'base'}) };
  153         570  
182            
183 153 50 33     7400 if ($_changing and $schema->{'readonly'})
184             {
185 0         0 $addError->("is a readonly field, it can not be changed");
186             }
187 153 50       436 if ($schema->{'extends'})
188             {
189 0         0 $self->checkProp($value, $schema->{'extends'}, $path, $i, $_changing);
190             }
191            
192             # validate a value against a type definition
193 153 100       305 if (!defined $value)
194             {
195 19         19 my $required;
196 19 100       59 $required = !$schema->{'optional'} if exists $schema->{'optional'};
197 19 100       55 $required = $schema->{'required'} if $schema->{'required'};
198            
199 19 100       53 $addError->("is missing and it is required") if $required;
200             }
201             else
202             {
203 134         169 push @{$self->{errors}}, $self->checkType($schema->{'type'}, $value, $path, $_changing, $schema);
  134         420  
204            
205 134 50 33     428 if (defined $schema->{'disallow'}
206             and !$self->checkType($schema->{'disallow'}, $value, $path, $_changing))
207             {
208 0         0 $addError->(" disallowed value was matched");
209             }
210            
211 134 100       271 if (!$self->jsIsNull($value))
212             {
213 128 100 100     908 if (ref $value eq 'ARRAY')
    100 66        
      66        
214             {
215 7         15 my $items = $schema->{items};
216            
217 7 50       29 if (ref $items eq 'ARRAY')
    50          
218             { # check each item in $schema->{items} vs corresponding array value
219 0         0 my $i = 0;
220 0         0 while ($i < @$items)
221             {
222 0 0       0 my $x = defined $value->[$i] ? $value->[$i] : JSON::Schema::Null->new;
223 0         0 push @{$self->{errors}}, $self->checkProp($x, $items->[$i], $path, $i, $_changing);
  0         0  
224 0         0 $i++;
225             }
226 0 0       0 if (exists $schema->{additionalItems})
227             {
228 0         0 my $additional_items = $schema->{additionalItems};
229 0 0       0 if (!$additional_items)
230             {
231 0 0       0 if (defined $value->[$i])
232             {
233 0         0 $addError->("has too many items");
234             }
235             }
236             else
237             {
238 0         0 while ($i < @$value)
239             {
240 0 0       0 my $x = defined $value->[$i] ? $value->[$i] : JSON::Schema::Null->new;
241 0         0 push @{$self->{errors}}, $self->checkProp($x, $additional_items, $path, $i, $_changing);
  0         0  
242 0         0 $i++;
243             }
244             }
245             }
246             }
247             elsif (ref $items eq 'HASH')
248             { # check single $schema->{items} hash vs all values in array
249 0         0 for (my $i=0; $i < @$value; $i++)
250             {
251 0 0       0 my $x = defined $value->[$i] ? $value->[$i] : JSON::Schema::Null->new;
252 0         0 push @{$self->{errors}}, $self->checkProp($x, $items, $path, $i, $_changing);
  0         0  
253             }
254             }
255 7 50 33     24 if ($schema->{'minItems'}
256             and scalar @$value < $schema->{'minItems'})
257             {
258 0         0 $addError->("There must be a minimum of " . $schema->{'minItems'} . " in the array");
259             }
260 7 50 33     25 if ($schema->{'maxItems'}
261             and scalar @$value > $schema->{'maxItems'})
262             {
263 0         0 $addError->("There must be a maximum of " . $schema->{'maxItems'} . " in the array");
264             }
265 7 50       19 if ($schema->{'uniqueItems'})
266             {
267 0         0 my %hash;
268 0         0 $hash{ to_json([$_],{canonical=>1,convert_blessed=>1}) }++ for @$value;
269 0 0       0 $addError->("Array must not contain duplicates.")
270             unless scalar(keys %hash) == scalar(@$value);
271             }
272             }
273             elsif (defined $schema->{'properties'}
274             or defined $schema->{'additionalProperties'}
275             or defined $schema->{'patternProperties'}
276             or $schema->{'type'} eq 'object')
277             {
278 70         75 push @{$self->{errors}}, $self->checkObj($value, $path, $schema->{'properties'}, $schema->{'additionalProperties'}, $schema->{'patternProperties'}, $_changing);
  70         297  
279             }
280            
281 128 50 33     391 if ($schema->{'pattern'} and $self->jsMatchType('string', $value))
282             {
283 0         0 my $x = $schema->{'pattern'};
284 0 0       0 $addError->("does not match the regex pattern $x")
285             unless $value =~ /$x/;
286             }
287 128 50 33     345 if ($schema->{'format'} and
      66        
288             ($self->jsMatchType('string', $value) or $self->jsMatchType('number', $value)))
289             {
290             my $format_checker = exists $self->{format}{ $schema->{format} }
291             ? $self->{format}{ $schema->{format} }
292 2 50       13 : qr//;
293            
294             $addError->("does not match format ".$schema->{format})
295 2 100       9 unless match($value, $format_checker);
296             }
297 128 100 66     1019 if ($schema->{'maxLength'} and $self->jsMatchType('string', $value)
      100        
298             and length($value) > $schema->{'maxLength'})
299             {
300 1         5 $addError->("may only be " . $schema->{'maxLength'} . " characters long");
301             }
302 128 100 66     346 if ($schema->{'minLength'} and $self->jsMatchType('string', $value)
      100        
303             and length($value) < $schema->{'minLength'})
304             {
305 2         8 $addError->("must be at least " . $schema->{'minLength'} . " characters long");
306             }
307 128 50 66     569 if (defined $schema->{'minimum'} and not $self->jsMatchType('number', $value))
    100          
308             {
309 0 0 0     0 if ((defined $schema->{'minimumCanEqual'} and not $schema->{'minimumCanEqual'})
      0        
310             or $schema->{'exclusiveMinimum'})
311             {
312             $addError->("must be greater than minimum value '" . $schema->{'minimum'}) . "'"
313 0 0       0 if $value lt $schema->{'minimum'};
314             }
315             else
316             {
317             $addError->("must be greater than or equal to minimum value '" . $schema->{'minimum'}) . "'"
318 0 0       0 if $value le $schema->{'minimum'};
319             }
320             }
321             elsif (defined $schema->{'minimum'})
322             {
323 6 50 33     31 if ((defined $schema->{'minimumCanEqual'} and not $schema->{'minimumCanEqual'})
      33        
324             or $schema->{'exclusiveMinimum'})
325             {
326             $addError->("must be greater than minimum value " . $schema->{'minimum'})
327 0 0       0 unless $value > $schema->{'minimum'};
328             }
329             else
330             {
331             $addError->("must be greater than or equal to minimum value " . $schema->{'minimum'})
332 6 100       22 unless $value >= $schema->{'minimum'};
333             }
334             }
335 128 50 66     485 if (defined $schema->{'maximum'} and not $self->jsMatchType('number', $value))
    100          
336             {
337 0 0 0     0 if ((defined $schema->{'maximumCanEqual'} and not $schema->{'maximumCanEqual'})
      0        
338             or $schema->{'exclusiveMaximum'})
339             {
340             $addError->("must be less than or equal to maximum value '" . $schema->{'maximum'}) . "'"
341 0 0       0 if $value gt $schema->{'maximum'};
342             }
343             else
344             {
345             $addError->("must be less than or equal to maximum value '" . $schema->{'maximum'}) . "'"
346 0 0       0 if $value ge $schema->{'maximum'};
347             }
348             }
349             elsif (defined $schema->{'maximum'})
350             {
351 6 50 33     33 if ((defined $schema->{'maximumCanEqual'} and not $schema->{'maximumCanEqual'})
      33        
352             or $schema->{'exclusiveMaximum'})
353             {
354             $addError->("must be less than maximum value " . $schema->{'maximum'})
355 0 0       0 unless $value < $schema->{'maximum'};
356             }
357             else
358             {
359             $addError->("must be less than or equal to maximum value " . $schema->{'maximum'})
360 6 100       28 unless $value <= $schema->{'maximum'};
361             }
362             }
363 128 100       285 if ($schema->{'enum'})
364             {
365 8         10 my %enum;
366 8         9 $enum{ to_json([$_],{canonical=>1,convert_blessed=>1}) }++ for @{ $schema->{'enum'} };
  8         59  
367 8         504 my $this_value = to_json([$value],{canonical=>1,convert_blessed=>1});
368 4         24 $addError->("does not have a value in the enumeration {" . (join ",", @{ $schema->{'enum'} }) . '}')
369 8 100       172 unless exists $enum{$this_value};
370             }
371 128 50 33     632 if ($schema->{'divisibleBy'} and $self->jsMatchType('number', $value))
    50 33        
372             {
373 0         0 my ($frac,$int) = modf($value / $schema->{'divisibleBy'});
374 0 0       0 $addError->("must be divisible by " . $schema->{'divisibleBy'})
375             if $frac;
376             }
377             elsif ($schema->{'maxDecimal'} and $self->jsMatchType('number', $value)) # ~TOBYINK: back-compat
378             {
379 0         0 my $regexp = "\\.[0-9]{" . ($schema->{'maxDecimal'} + 1) . ",}";
380 0 0       0 $addError->("may only have " . $schema->{'maxDecimal'} . " digits of decimal places")
381             if $value =~ /$regexp/;
382             }
383             } # END: if (!$self->jsIsNull()) { ... }
384             } # END: if (!$defined $value) {} else {...}
385 153         760 return;
386             }; # END: sub checkProp
387              
388              
389             sub checkObj
390             {
391 70     70 0 184 my ($self, $instance, $path, $objTypeDef, $additionalProp, $patternProp, $_changing) = @_;
392 70         75 my @errors;
393            
394             my $addError = sub
395             {
396 12     12   15 my ($message) = @_;
397 12         30 my $e = { property=>$path, message=>$message };
398 12         14 push @{$self->{errors}}, $e;
  12         28  
399 70         249 };
400            
401 70         104 eval { $self->{'hyper'}->process_includes($objTypeDef, $self->{'base'}) };
  70         252  
402            
403 70 100       3249 if (ref $objTypeDef eq 'HASH')
404             {
405 69 100       157 if (ref $instance ne 'HASH')
406             {
407 6         15 $addError->("an object is required");
408             }
409            
410 69         175 foreach my $i (keys %$objTypeDef)
411             {
412 76 50       183 unless ($i =~ /^__/)
413             {
414 76 100       302 my $value = defined $instance->{$i} ? $instance->{$i} : exists $instance->{$i} ? JSON::Schema::Null->new : undef;
    100          
415 76         118 my $propDef = $objTypeDef->{$i};
416 76         263 $self->checkProp($value, $propDef, $path, $i, $_changing);
417             }
418             }
419             } # END: if (ref $objTypeDef eq 'HASH')
420            
421 70         200 foreach my $i (keys %$instance)
422             {
423 75         167 my $prop_is_hidden = ($i =~ /^__/);
424 75   100     292 my $prop_is_explicitly_allowed = (defined $objTypeDef and defined $objTypeDef->{$i});
425 75   66     351 my $prop_is_implicitly_allowed = (!!$additionalProp
426             or !!$patternProp
427             or not defined $additionalProp);
428            
429 75 100 66     364 unless ($prop_is_hidden or $prop_is_explicitly_allowed or $prop_is_implicitly_allowed)
      100        
430             {
431 6         18 $addError->("The property $i is not defined in the schema and the schema does not allow additional properties");
432             }
433              
434             # TOBY: back-compat
435 75   66     420 my $requires = $objTypeDef && $objTypeDef->{$i} && $objTypeDef->{$i}->{'requires'};
436 75 50 33     180 if (defined $requires and not defined $instance->{$requires})
437             {
438 0         0 $addError->("the presence of the property $i requires that $requires also be present");
439             }
440            
441 75   66     505 my $deps = $objTypeDef && $objTypeDef->{$i} && $objTypeDef->{$i}->{'dependencies'};
442 75 50       141 if (defined $deps)
443             {
444             # TODO
445             }
446            
447 75 50       208 my $value = defined $instance->{$i} ? $instance->{$i} : exists $instance->{$i} ? JSON::Schema::Null->new : undef;
    100          
448 75 100 66     475 if (defined $objTypeDef
      100        
449             and ref $objTypeDef eq 'HASH'
450             and !defined $objTypeDef->{$i})
451             {
452 17         38 $self->checkProp($value, $additionalProp, $path, $i, $_changing);
453             }
454            
455 75 50       142 if (defined $patternProp)
456             {
457 0         0 while (my ($pattern, $scm) = each %$patternProp)
458             {
459 0 0       0 $self->checkProp($value, $scm, $path, $i, $_changing)
460             if $i =~ /$pattern/;
461             }
462             }
463            
464 75 50 33     530 if(!$_changing and defined $value and ref $value eq 'HASH' and defined $value->{'$schema'})
      66        
      66        
465             {
466 0         0 push @errors, $self->checkProp($value, $value->{'$schema'}, $path, $i, $_changing);
467             }
468             }
469 70         259 return @errors;
470             }
471              
472             sub jsIsNull
473             {
474 164     164 0 216 my ($self, $value) = @_;
475            
476 164 100 66     690 return TRUE if blessed($value) && $value->isa('JSON::Schema::Null');
477            
478 146         433 return FALSE;
479             }
480              
481             sub jsMatchType
482             {
483 147     147 0 219 my ($self, $type, $value) = @_;
484            
485 147 100       325 if (lc $type eq 'string')
486             {
487 29 100       200 return (ref $value) ? FALSE : TRUE;
488             }
489              
490 118 100       234 if (lc $type eq 'number')
491             {
492 13 100 66     160 return ($value =~ /^\-?[0-9]*(\.[0-9]*)?$/ and length $value) ? TRUE : FALSE;
493             }
494            
495 105 100       204 if (lc $type eq 'integer')
496             {
497 12 100       68 return ($value =~ /^\-?[0-9]+$/) ? TRUE : FALSE;
498             }
499            
500 93 100       178 if (lc $type eq 'boolean')
501             {
502 8 100       22 return FALSE if (ref $value eq 'JSON::Schema::Null');
503 6 0 0     16 return TRUE if (ref $value eq 'SCALAR' and $$value==0 || $$value==1);
      33        
504 6 100       31 return TRUE if ($value eq TRUE);
505 4 50       55 return TRUE if ($value eq FALSE);
506 4 50       11 return TRUE if (ref $value eq 'JSON::PP::Boolean');
507 4 50       8 return TRUE if (ref $value eq 'JSON::XS::Boolean');
508 4         27 return FALSE;
509             }
510              
511 85 100       173 if (lc $type eq 'object')
512             {
513 78 100       341 return (ref $value eq 'HASH') ? TRUE : FALSE;
514             }
515            
516 7 100       15 if (lc $type eq 'array')
517             {
518 6 100       24 return (ref $value eq 'ARRAY') ? TRUE : FALSE;
519             }
520              
521 1 50       4 if (lc $type eq 'null')
522             {
523 1         3 return $self->jsIsNull($value);
524             }
525            
526 0 0       0 if (lc $type eq 'any')
527             {
528 0         0 return TRUE;
529             }
530            
531 0 0       0 if (lc $type eq 'none')
532             {
533 0         0 return FALSE;
534             }
535            
536 0 0 0     0 if (blessed($value) and $value->isa($type))
    0 0        
537             {
538 0         0 return TRUE;
539             }
540             elsif (ref($value) and ref($value) eq $type)
541             {
542 0         0 return TRUE;
543             }
544            
545 0         0 return FALSE;
546             }
547              
548             sub jsGuessType
549             {
550 34     34 0 45 my ($self, $value) = @_;
551            
552 34 100       72 return 'object'
553             if ref $value eq 'HASH';
554              
555 32 100       77 return 'array'
556             if ref $value eq 'ARRAY';
557              
558 29 0 33     65 return 'boolean'
      33        
559             if (ref $value eq 'SCALAR' and $$value==0 and $$value==1);
560            
561 29 50       119 return 'boolean'
562             if ref $value =~ /^JSON::(.*)::Boolean$/;
563            
564 29 100       55 return 'null'
565             if $self->jsIsNull($value);
566            
567 18 50       37 return ref $value
568             if ref $value;
569              
570 18 100       79 return 'integer'
571             if $value =~ /^\-?[0-9]+$/;
572            
573 12 100       86 return 'number'
574             if $value =~ /^\-?[0-9]*(\.[0-9]*)?$/;
575            
576 4         17 return 'string';
577             }
578              
579             1;
580              
581             __END__
582              
583             =head1 NAME
584              
585             JSON::Schema::Helper - helper class for JSON::Schema
586              
587             =head1 SEE ALSO
588              
589             L<JSON::Schema>.
590              
591             =head1 AUTHOR
592              
593             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
594              
595             =head1 COPYRIGHT AND LICENCE
596              
597             Copyright 2007-2009 Kris Zyp.
598              
599             Copyright 2010-2012 Toby Inkster.
600              
601             This module is tri-licensed. It is available under the X11 (a.k.a. MIT)
602             licence; you can also redistribute it and/or modify it under the same
603             terms as Perl itself.
604              
605             =head2 a.k.a. "The MIT Licence"
606              
607             Permission is hereby granted, free of charge, to any person obtaining a copy
608             of this software and associated documentation files (the "Software"), to deal
609             in the Software without restriction, including without limitation the rights
610             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
611             copies of the Software, and to permit persons to whom the Software is
612             furnished to do so, subject to the following conditions:
613              
614             The above copyright notice and this permission notice shall be included in
615             all copies or substantial portions of the Software.
616              
617             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
618             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
619             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
620             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
621             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
622             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
623             THE SOFTWARE.
624              
625             =cut