array-lib egg
*************

Provides a SRFI-63 workalike

Written by Kon Lovett (mailto:klovett@pacbell.net)

This manual corresponds to version 1.7 of the array-lib extension library for Chicken Scheme.

About this egg
**************

Version history
===============

1.7
     Bug fix for ec

1.6
     Removal of common code, partial support for csi describe

1.5
     Exports

1.4
     Replaced #<rank>A print syntax with #A read/print syntax, bug fix for returning underlying storage object

1.3
     Optimized array construction

1.2
     Bug fix for unbound-variable array:store

1.1
     Record optimization

1.0
     Indexing optimization

0.9
     more SLIB procedures

0.8
     SLIB procedures

0.7
     Added procedures

0.6
     Added procedures

0.5
     Added procedures

0.4
     Added procedures

0.3
     Bug fix for empty arrays

0.2
     Bug fix for rank 0 arrays

0.1
     Initial release

Usage
=====

Load this egg like so:

(require-extension array-lib)

Requirements
============

This egg requires the following extensions:

misc-extn

Documentation
*************

The array-lib purports to be a Chicken workalike for SRFI-47 (http://srfi.schemers.org/srfi-47/srfi-47.html), SRFI-63 (http://srfi.schemers.org/srfi-63/srfi-63.html), and the SLIB array, subarray & arraymap modules.

Note: this array package is not compatible with the default array library SRFI-25 that is provided with the base system. Do not use these two libraries together in the same program. However it does provide a similar shape feature, but with a SRFI-63 compliant API.

SRFI-63 Discussion
==================

The signatures of all SRFI-63 procedures are supported by this API, only with extended interpretations of some arguments.

Both SRFI-47 and SRFI-63 array prototypes are supplied, including complex prototypes (see below).

Array constructors will return the underlying storage object, rather than an array object, when the constructed array is 0-origin & rank <= 1, per SRFI-63.

Where dimensions are expected a shape is also accepted. Where a rank is expected dimensions or a shape are also accepted.

Dimensions are a list of the number of elements for each dimension, or a dimension object (see below). For example, '(1 2) are dimensions of a rank 2 array.

A shape is a list of intervals, [lower upper), or a shape object (see below). For example, '((0 1) (0 2)) is a shape of a rank 2 array, with bounds [0 0] [0 1].

The dimensions '(2 0 3) are equivalent to the shape '(0 2 0 0 0 3).

The accepted list form of dimensions or shape for procedures taking these as tail arguments is as an 'exploded' list. Each element as an individual argument. For example, (make-array '(1 2) '(-8 -5)), not (make-array '((1 2) (-8 -5))).

All indices/dimensions/bounds/ranks must be fixnum. Not much of a restiction from SRFI-63, just a clarification.

An empty dimension, a dimension of 0, is not actually empty. The empty dimension will have a single element, the subarray "inside". However, no storage is consumed by an empty dimension.

Read Syntax
===========

A SRFI-10 (http://srfi.schemers.org/srfi-10/srfi-10.html) printer and reader is supplied.

An array specific read/print syntax is supplied: #A<rank><elements>, where <rank> is the array dimensionality and <elements> are a rank-nested list consisting of all the elements, in row-major order.

The SRFI-10 print-form preserves the underlying storage model and shape information, unlike the #A form, which only preserves the rank and element values. So, reading the #A form may not reconstruct the exact printed array.

Use (current-array-print-form ...) to select the desired form.

A limit is placed on the number of array elements printed, which may be overridden. See (current-array-print-count ...).

Parameters
==========

 -- parameter: current-array-bounds-check

          (current-array-bounds-check [FLAG #t])

     Sets or returns whether array indices are bounds-checked.

 -- parameter: current-array-element-check

          (current-array-element-check [FLAG #f])

     Sets or returns whether array elements are immediately type-checked before setting. When false the underlying storage type performs any validation.

 -- parameter: current-array-print-count

          (current-array-print-count [COUNT 50])

     Sets or returns the number of array elements to print. A COUNT of #f will set the count 0, and #t will set the count to a very big number. When COUNT is a number it must a zero or positive fixnum.

 -- parameter: current-array-print-form

          (current-array-print-form [FORM 'SRFI-10])

     Sets or returns the format for printing an array, either 'SRFI-10, 'A, or #f which turns off array element printing.

Predicates
==========

 -- procedure: array?

          (array? ARRAY)

     Returns whether the object is an array object, or accepted as an array. Acceptable objects are vector, string, byte-vector, and SRFI-4 (http://srfi.schemers.org/srfi-4/srfi-4.html) vectors.

 -- procedure: array-strict?

          (array-strict? ARRAY)

     Returns whether the object is only an array object.

 -- procedure: equal?

          (equal? ARRAY1 ARRAY2)

     Are the two arrays equal in all properties and elements?

 -- procedure: array-equal?

          (array-equal? ARRAY1 ARRAY2)

     Are the two arrays equal in dimensionality and elements?

     Signals an error when either of the arguments is not an array.

 -- procedure: array-empty?

          (array-empty? ARRAY)

     Returns #t for an empty array, #f for anything else.

 -- procedure: array-dimensions?

          (array-dimensions? DIMENSIONS)

     A set of dimensions, as produced by make-array-dimensions?

 -- procedure: array-shape?

          (array-shape? OBJECT)

     A shape, as produced by make-array-shape?

 -- procedure: array-in-bounds?

          (array-in-bounds? ARRAY INDEX ...)

     Are the indices valid for the array?

     Signals an error when not an array.

Array Properties
================

 -- procedure: array-store

          (array-store ARRAY)

     Returns the underlying storage object for ARRAY, or #f when not an array. Use this at your peril.

 -- procedure: array-start

          (array-start ARRAY RANK)

     Returns the start, or lower bound, of ARRAY along dimension RANK, or #f when not array.

 -- procedure: array-end

          (array-end ARRAY RANK)

     Returns the end, one beyond the upper bound, of ARRAY along dimension RANK, or #f when not an array.

 -- procedure: array-rank

          (array-rank ARRAY)

     Returns the number of dimensions for ARRAY, or 0 when not an array, an empty array, or a rank 0 array.

 -- procedure: array-dimensions

          (array-dimensions ARRAY)

     Returns the list of dimensions for ARRAY, or #f when not an array. The elements are the actual length of each dimension, so a dimension of 3, [0 3), is 3 and [1 3) is 2.

 -- procedure: array-bounds

          (array-bounds ARRAY)

     Returns the bounds list for ARRAY, or #f when not an array. A list of pairs, one for each dimension. Each pair is the interval [low high].

 -- procedure: array-shape

          (array-shape ARRAY)

     Returns the shape list for ARRAY, or #f when not an array. The list can be used as (apply make-array-shape LIST).

     To access the compiled shape information of an array use (array-bounds ...).

Array Shape & Dimensions
========================

 -- procedure: make-array-dimensions

          (make-array-dimensions DIMENSION ...)

     Returns a dimensions object.

 -- procedure: make-array-shape

          (make-array-shape START END ...)

     Returns a shape object suitable for use with the array construction procedures.

     A shape is composed of an even count series of intervals, [start end), for each dimension. Thus an index is within the bounds for a dimension if start <= index < end. To indicate an empty dimension use start = end, a special case.

     The interval may be on any integer, not just positive and 0. The start must still be strictly less than the end. So [-5 -2) is legal but [-2 -5) is not.

Array Operations
================

 -- procedure: array-print

          (array-print ARRAY [COUNT <very-big-number>] [PORT (current-output-port)])

     Prints COUNT elements of the array ARRAY on the specified port PORT.

 -- procedure: array-copy

          (array-copy [PROTOTYPE] ARRAY)

     Returns a copy of the array. When prototype is missing a deep copy is performed. When the prototype and the source array are the same, (eq? <prototype> <array>), a fresh array is returned with the same shape, using the array as the prototype. Otherwise a fresh array is returned with the specified prototype and elements from the array.

     The prototype and source array element types must be assignment compatible. Even so, precision maybe lost.

 -- procedure: make-array

          (make-array [PROTOTYPE] [SHAPE/DIMENSION ...])

     Creates and returns an array of type prototype with dimensions or shape, and filled with elements from prototype.

     A valid prototype is any object the meets (array? ...).

     If the prototype has no elements, then the initial elements of the returned array are unspecified.  Otherwise, the returned array will be filled with the element at the origin of prototype.

     (make-array [<prototype>]) will construct an empty array, not a rank 0 array. Such arrays cannot be used with any setter or getter. However, property queries will work.

     When the prototype is missing, vector is assumed.

 -- procedure: array

          (array [PROTOTYPE] RANK/SHAPE/DIMENSIONS [ELEMENT ...])

     Creates and returns an array of type prototype with dimensions, or shape, or rank and filled with the elements.

     When a rank is specified, it must be 0 or positive. When positive it is interpreted as the dimensions ((- rank 0) (- rank 1) ... (/ <# of elements> (factorial rank))). So rank 1 is (<#>), 2 is (2 <#>/2), 3 is (3 2 <#>/3x2), and so on. This is of dubious utility.

     When the prototype is missing, vector is assumed.

 -- procedure: make-shared-array

          (make-shared-array ARRAY MAPPER [SHAPE/DIMENSION ...])

     Can be used to create shared subarrays of other arrays. The mapper is a function that translates coordinates in the new array into coordinates in the old array.  A mapper must be linear, and its' range must stay within the bounds of the old array, but it can be otherwise arbitrary.

 -- procedure: list->array

          (list->array SHAPE/DIMENSIONS/RANK PROTOTYPE LIST)

     The list must be a rank-nested list consisting of all the elements, in row-major order, of the array to be created.

     Returns an array of rank, or shape, or dimensions and type prototype consisting of all the elements, in row-major order, of the list.  When the rank is 0, list is the lone array element; not necessarily a list.

 -- procedure: array->list

          (array->list ARRAY)

     Returns the array elements as a rank-nested list. For rank 0 arrays returns just the element. Will generate an error when not an array.

 -- procedure: vector->array

          (vector->array VECTOR PROTOTYPE [SHAPE/DIMENSION ...])

     The vector must be of length equal to the product of the dimensions, or shape element sizes.

     Returns an array of type prototype consisting of all the elements, in row-major order, of the vector.  In the case of a rank 0 array, the vector has a single element.

 -- procedure: array->vector

          (array->vector ARRAY)

     Returns the array elements as a new unpacked vector. Will generate an error when not an array.

 -- procedure: array-ref

          (array-ref ARRAY INDEX ...)

     Returns the array element at indices. Will generate an error when not an array or out-of-range condition.

 -- procedure: array-set!

          (array-set! ARRAY OBJECT INDEX ...)

     Sets the array element at indices to the object. Will generate an error when not an array, out-of-range condition, or the object is unsuitable as an array element.

Sub-Array Operations
====================

These are not part of the basic package. Be sure to (use array-lib-sub) for access.
 -- procedure: subarray

          (subarray ARRAY [SELECT ...])

     Returns a subarray sharing elements with ARRAY. For an array of rank N, there must be at least N SELECT arguments. For 0 <= I < N, SELECT[I] is either an integer, a list of two integers within the range for the Ith index, or #f.

     When SELECT[I] is a list of two integers, then the Ith index is restricted to that subrange in the returned array.

     When SELECT[I] is #f, then the full range of the Ith index is accessible in the returned array. An elided argument is equivalent to #f.

     When SELECT[I] is an integer, then the rank of the returned array is less than ARRAY, and only elements whose Ith index equals SELECT[I] are shared.

 -- procedure: array-trim

          (array-trim ARRAY [TRIM ...])

     Returns a subarray sharing elements with ARRAY except for slices removed from either side of each dimension. Each of the TRIM arguments is an exact integer indicating how much to trim.  A positive TRIM trims the data from the lower end and reduces the upper bound of the result; a negative TRIM trims from the upper end and increases the lower bound.

 -- procedure: array-row-ref

          (array-row-ref ARRAY INDEX ...)

     Returns the array row, as an unpacked vector, at indices. Will generate an error when not an array or out-of-range condition. The number of indices must be one less than the rank.

 -- procedure: array-row-set!

          (array-row-set! ARRAY OBJECT INDEX ...)

     Sets the array row at indices to the object. Will generate an error when not an array, out-of-range condition, or the object is unsuitable as an array row. The number of indices must be one less than the rank.

     The row object may be an one dimensional array, a list, or an atomic value. The row object length must match the target array row length. When an atomic value this operation is row fill.

 -- procedure: array-split

          (array-split ARRAY OUTER-RANK)

     Return a list of fresh subarrays, split along the specified outer rank, in ascending order by outer index.

 -- procedure: array-split/shared

          (array-split/shared ARRAY OUTER-RANK)

     Return a list of shared subarrays, split along the specified outer rank, in ascending order by outer index.

 -- procedure: array-join

          (array-join PROTOTYPE OUTER-SHAPE/DIMENSIONS [INNER-SHAPE/DIMENSIONS] [ARRAY ...])

     Construct a fresh array with specified prototype, outer dimensions, and optional inner dimensions, from the specified inner array(s).

     The outer dimension maybe a number (indicating the single, outer, dimension), a list of dimensions, a shape, or #f (indicating the count of the inner arrays is the outer dimension).

     If specified the inner dimension maybe a list of dimensions, or a shape. If missing the first inner array shape is used as the inner shape for the result array.

     The result array shape is the concatenation of the outer and inner shapes. The rank of the result array must be greater than the rank the inner array(s).

     All joined arrays must be of the same dimensionality.

 -- procedure: array-reverse

          (array-reverse ARRAY)

     Returns a fresh array with the top-level dimension reversed.

Higher Order Operations
=======================

These are not part of the basic package. Be sure to (use array-lib-hof) for access.
 -- procedure: make-array-index-generator

          (make-array-index-generator SHAPE/DIMENSIONS/ARRAY)

     Returns a zero argument procedure which returns an indices list (a full index) for the specified bounds upon each invocation, or #f when the indices are exhausted.

     An indices list is suitable for use with (apply array-ref/array-set! ... indices).

 -- procedure: array-for-each-index

          (array-for-each-index PROCEDURE [SHAPE/DIMENSIONS/ARRAY ...])

     Invokes the procedure with each set of indices for the specified bounds. The procedure arity is equal to the number of bounds. Each argument is a list of the indices, with rank length (length of the bounds).

     When an array is specified the bounds of the array are used.

     An indices list is suitable for use with (apply array-ref/array-set! ... indices).

     All arrays should be of the same dimensions. The operation will terminate when any of the set of indices is exhausted.

 -- procedure: array-for-each

          (array-for-each PROCEDURE [ARRAY ...])

     Apply the procedure to each element of the array(s). The procedure arity is equal to the number of the array(s).

     All arrays must be of the same dimensionality.

 -- procedure: array-map!

          (array-map! ARRAY PROCEDURE [ARRAY ...])

     Apply the procedure to each element of the array(s). The procedure arity is equal to the number of the array(s).

     Returns the first array with the mapped elements. An in-place map.

     All arrays must be of the same dimensionality.

 -- procedure: array-map

          (array-map PROTOTYPE PROCEDURE ARRAY ...)

     Apply the procedure to each element of the array(s). The procedure arity is equal to the number of the array(s).

     Returns a fresh array from the PROTOTYPE and the shape of the first ARRAY with the mapped elements.

     All arrays must be of the same dimensionality.

 -- procedure: array-fold

          (array-fold PROCEDURE SEED ARRAY ...)

     Apply the fold procedure to each element of the array(s). The procedure arity is 1 + the number of array(s). The first argument is the current accumulated value, or the initial seed. The rest of the arguments are the array elements.

     Returns the accumulated value.

     All arrays must be of the same dimensionality.

 -- procedure: array-project

          (array-project PROTOTYPE RANK/SHAPE/DIMENSIONS PROJECTOR ARRAY)

     Conform an N dimensional source array to a fresh M dimensional destination array.

     The projector takes 2 arguments, the destination row vector and the source row vector. The destination vector length is M and the source vector is length N. The projector is not required to use the supplied destination vector. However, it must return some vector of length M.

     Returns the array projection.

 -- procedure: array-index-map!

          (array-index-map! ARRAY PROCEDURE)

     Applys the PROCEDURE to each list of indexes of the ARRAY and replaces the existing element with the result of the procedure application.

 -- procedure: array-indexes

          (array-indexes ARRAY)

     Returns an array of lists of indexes for the ARRAY.

 -- procedure: array-copy!

          (array-copy! DESTINATION-ARRAY SOURCE-ARRAY)

     Copy the elements of the source array to the corresponding elements of the destination array. The source and destination arrays must have the same dimensions, but not necessarily the same shape.

     The source and destination element types must be assignment compatible. Even so, precision maybe lost.

Eager Comprehensions
====================

These are not part of the basic package. Be sure to (use array-lib-ec) for access. Requires SRFI-42 (http://www.call-with-current-continuation.org/eggs/srfi-42.html).
 -- macro: array-ec

          (array-ec PROTOTYPE SHAPE/DIMENSIONS [QUALIFIER ...] EXPRESSION)

     Returns an array with specified PROTOTYPE, and SHAPE/DIMENSIONS. Each element of the fresh array is produced by evaluating the EXPRESSION for every state generated by the set of QUALIFIER.

     Should more states be generated than elements of the array they are ignored.

 -- macro: :array

          (:array VARIABLE [(index INDEX-VARIABLE ...)] ARRAY ...)

     Generate each element of each ARRAY, binding the element to VARIABLE. Should the indices be wanted there must be as many INDEX-VARIABLE items as the rank of greatest dimensioned array.

Prototypes
==========

 -- procedure: a:floc128b

          (a:floc128b [INITIAL <undefined>])

     Returns an inexact 128 bit flonum complex uniform-array prototype.

 -- procedure: a:floc64b

          (a:floc64b [INITIAL <undefined>])

     Returns an inexact 64 bit flonum complex uniform-array prototype.

 -- procedure: a:floc32b

          (a:floc32b [INITIAL <undefined>])

     Returns an inexact 32 bit flonum complex uniform-array prototype.

 -- procedure: a:floc16b

          (a:floc16b [INITIAL <undefined>])

     Returns an inexact 16 bit flonum complex uniform-array prototype.

 -- procedure: a:flor128b

          (a:flor128b [INITIAL <undefined>])

     Returns an inexact 128 bit flonum real uniform-array prototype.

 -- procedure: a:flor64b

          (a:flor64b [INITIAL <undefined>])

     Returns an inexact 64 bit flonum real uniform-array prototype.

 -- procedure: a:flor32b

          (a:flor32b [INITIAL <undefined>])

     Returns an inexact 32 bit flonum real uniform-array prototype.

 -- procedure: a:flor16b

          (a:flor16b [INITIAL <undefined>])

     Returns an inexact 16 bit flonum real uniform-array prototype.

 -- procedure: a:floq128b

          (a:floq128b [INITIAL <undefined>])

     Returns an exact 128 bit decimal flonum rational uniform-array prototype.

 -- procedure: a:floq64b

          (a:floq64b [INITIAL <undefined>])

     Returns an exact 64 bit decimal flonum rational uniform-array prototype.

 -- procedure: a:floq32b

          (a:floq32b [INITIAL <undefined>])

     Returns an exact 32 bit decimal flonum rational uniform-array prototype.

 -- procedure: a:fixz64b

          (a:fixz64b [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 64 bits of precision.

 -- procedure: a:fixz32b

          (a:fixz32b [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 32 bits of precision.

 -- procedure: a:fixz16b

          (a:fixz16b [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 16 bits of precision.

 -- procedure: a:fixz8b

          (a:fixz8b [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 8 bits of precision.

 -- procedure: a:fixn64b

          (a:fixn64b [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 64 bits of precision.

 -- procedure: a:fixn32b

          (a:fixn32b [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 32 bits of precision.

 -- procedure: a:fixn16b

          (a:fixn16b [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 16 bits of precision.

 -- procedure: a:fixn8b

          (a:fixn8b [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 8 bits of precision.

 -- procedure: a:bool

          (a:bool [INITIAL <undefined>])

     Returns a boolean uniform-array prototype.

 -- procedure: ac64

          (ac64 [INITIAL <undefined>])

     Returns an inexact 64 bit flonum complex uniform-array prototype.

 -- procedure: ac32

          (ac32 [INITIAL <undefined>])

     Returns an inexact 32 bit flonum complex uniform-array prototype.

 -- procedure: ar64

          (ar64 [INITIAL <undefined>])

     Returns an inexact 64 bit flonum real uniform-array prototype.

 -- procedure: ar32

          (ar32 [INITIAL <undefined>])

     Returns an inexact 32 bit flonum real uniform-array prototype.

 -- procedure: as64

          (as64 [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 64 bits of precision.

 -- procedure: as32

          (as32 [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 32 bits of precision.

 -- procedure: as16

          (as16 [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 16 bits of precision.

 -- procedure: as8

          (as8 [INITIAL <undefined>])

     Returns an exact binary fixnum uniform-array prototype with at least 8 bits of precision.

 -- procedure: au64

          (au64 [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 64 bits of precision.

 -- procedure: au32

          (au32 [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 32 bits of precision.

 -- procedure: au16

          (au16 [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 16 bits of precision.

 -- procedure: au8

          (au8 [INITIAL <undefined>])

     Returns an exact non-negative binary fixnum uniform-array prototype with at least 8 bits of precision.

 -- procedure: at1

          (at1 [INITIAL <undefined>])

     Returns a boolean uniform-array prototype.

Issues
******

SRFI-25 indexing is 2.4 times faster! However, 'array-lib' has faster indexing than the reference SRFI-63 implementation.

Should signal specific conditions rather than an error.

Array aggregate operations are implemented in an element by element fashion.

The SRFI-42 general dispatcher (: ...) does not recognize arrays.

The 64-bit prototypes are currently implemented as unpacked vectors.

The prototypes will play well with the 'numbers' egg.

Needs a comprehensive test suite.

Examples
********

(use array-lib)

(current-array-print-form 'A)

(array-dimensions (make-array '#() 3 5))
=> (3 5)

(define fred (make-array '#(#f) 8 8))
(define freds-diagonal (make-shared-array fred (lambda (i) (list i i)) 8))
(array-set! freds-diagonal 'foo 3)
(array-ref fred 3 3)
=> foo
(define freds-center (make-shared-array fred (lambda (i j)
                                               (list (+ 3 i) (+ 3 j)))
                                        2 2))
(array-ref freds-center 0 0)
=> foo

(list->array 2 '#() '((1 2) (3 4)))
=> #A2((1 2) (3 4))
(list->array 0 '#() 3)
=> #A0 3

(array->list (array '#() '(2 3) 'ho 'ho 'ho 'ho 'oh 'oh))
=> ((ho ho ho) (ho oh oh))
(array->list (array '#() 0 'ho))
=> ho

(vector->array (vector 1 2 3 4) '#() 2 2)
=> #A2((1 2) (3 4))
(vector->array '#(3) '#())
=> #A0 3

(array->vector (array '#() (make-array-shape 0 2 0 2) 1 2 3 4))
=> #(1 2 3 4)
(array->vector (array '#() 0 'ho))
=> #(ho)

;;
;; See "array-lib-test.scm" in the unpacked egg for more examples.
;;

License
*******

Copyright (c) 2006, Kon Lovett.  All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the Software),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ASIS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Does not supercede any restrictions found in the source code.