1 LISP LIBRARY PACKAGES MANUAL 1 LISP LIBRARY PACKAGES MANUAL CMLARRAY 1 COMMON LISP 1 CMLARRAY 6 The following functions provide many features lacking in Interlisp's array support, in particular multidimensional and shared arrays. These definitions follow those given in the first edition of the Common Lisp: The Language, by Guy L. Steele (Digital Press, 1984). Some of the prose below is reproduced from an earlier ┅Excelsior构 edition of the manual, by permission. In general, the Common Lisp style of lambda arguments is used throughout when describing functions. For detailed information see the Common Lisp package's documentation (CML). 2 Loading CMLArray 1 Normally one loads the CMLArray package as part of loading the entire Common Lisp package; however, CMLArray can be used standalone. When used without CML there are syntactic limitations. Keyword arguments must be quoted and have the colon beginning them ┅character quoted构 with the percent sign. 2 Size Limitations 1 The implementation constraints are specified by the following symbolic constants. ARRAY-RANK-LIMIT [Constant] Maximum number of dimensions in an array. As in APL, the number of dimensions an array has is called its rank. ARRAY-DIMENSION-LIMIT [Constant] Maximum number of elements in any individual rank of an array. ARRAY-TOTAL-SIZE-LIMIT [Constant] Maximum total number of elements in an array. Implementation Note 1 For Interlisp-D these limits are: arrays with up to 128 ranks, individual dimensions of an array are constrained by the constant MAX.SMALLP. The total storage for a normal array data block may not exceed 65,533 words (a word contains 16 bits; pointers take two words). Note: if your application creates large arrays it is a good idea to set *PRINT-ARRAY* to NIL or *PRINT-LEVEL* and PRINT-LENGTH* to reasonably small values, as otherwise the printing routines will attempt to display their complete contents. 2 Creating and Testing Arrays 1 An array is a data structure that allows storage and access in a Cartesian coordinate system. By convention, all indexing in the Common Lisp world is zero-origin. (MAKE-ARRAY DIMENSIONS &KEY :ELEMENT-TYPE :INITIAL-ELEMENT:INITIAL-CONTENTS :DISPLACED-TO:DISPLACED-INDEX-OFFSET :ADJUSTABLE :FILL-POINTER) [Function] Only one of :INITIAL-ELEMENT :INITIAL-CONTENTS or :DISPLACED-TO may be specified. If no initialization is given for the array, the contents will be some implementation-dependent value. If an array is created without specifying :DISPLACED-TO, :ADJUSTABLE, or :FILL-POINTER, it is a ┅simple array,构 and will (in general) be stored more efficiently. Implementation Note 1 The existing Interlisp data types and BITMAP, ARRAYP, and STRINGP are all supported and can be manipulated with the functions in this package. DIMENSIONS is a list of non-negative integers that are to be the dimensions of the array; the length of the list defines the rank, or dimensionality, of the array. Note that if DIMENSIONS is NIL, then a zero-dimensional array is created, which contains one element. If a list of dimensions is given where one or more dimensions is zero, then a ┅degenerate array构 is created. It is an error to attempt to access or store into a ┅degenerate array.构 For convenience when making a one-dimensional array, the single dimension may be provided as an integer rather than a list of one integer. :ELEMENT-TYPE TYPE-SPECIFIER specifies the type of elements that are to be put into the array. Defaults to T. Note that this requests that this type be what the array holds, but doesn't declare it. The type given is cast into the next higher enclosing type of array. Thus, if an array of five-bit elements is requested, it is likely the array returned will be of the next enclosing type, probably an array capable of containing eight-bit bytes. The following is a list of type specifiers that may be passed as the element type: T%The elements will be capable of holding general Lisp objects (pointers); this is the default. FIXNUM%Elements will be capable of holding 32-bit two's complement integers. (MOD n)%The elements of the array should be capable of holding integers in the range zero to n minus one. (UNSIGNED-BYTE n)%Elements should be capable of holding integers of ┅n构 bits, unsigned. (INTEGER low high)%Elements should be capable of holding integers in the range ┅low构 to ┅high.构 BIT%Elements should be capable of holding a one-bit integer with value zero or one. FLOAT or SINGLE-FLOAT%Elements should be capable of holding 32-bit IEEE format floating-point numbers. STRING-CHAR%Elements should be capable of holding objects of type STRING-CHAR, which are the kind of elements found in the ARRAY subtype STRING. other%Any other legal structure type (data type) causes a pointer array to be created with element type T. Extension 1 XPOINTER%Elements will be un-reference-counted pointers. Implementation Notes 1 In Interlisp-D the ARRAY-ELEMENT-TYPE of the array returned will be one of: T, BIT, (UNSIGNED-BYTE 8), (UNSIGNED-BYTE 16), FIXNUM, SINGLE-FLOAT, STRING-CHAR, or XPOINTER. These types are implemented with one of the following internal data types: STRINGP, BITMAP, or ARRAY. STRINGP is returned when a simple array with element type STRING-CHAR is requested. BITMAP is returned for any simple rank two array whose elements can be contained in either (UNSIGNED-BYTE 1) or (UNSIGNED-BYTE 8). ARRAY is used for all others. While ARRAYP is supported by all other functions, MAKE-ARRAY currently does not return arrays implemented with this data type. :INITIAL-ELEMENT VALUE%This value must be an object of the type specified by the :ELEMENT-TYPE argument, and is used to initialize all the entries of the array. Default is NIL for pointer type, and zero for all numeric types. Implementation Note 1 In Interlisp-D uninitialized arrays are returned ┅zeroed,构 i.e., numeric arrays will have zeros in all positions, strings, the character with zero as its numeric value, pointer arrays NIL, etc. It is wise not to depend on this if you are writing portable code. :INITIAL-CONTENTS NESTED-SEQUENCES%If the array is zero-dimensional then this specifies its contents; otherwise, it must be a set of nested sequences (lists or arrays) whose length is equal to the first dimension, and each element of which must be a nested sequence for an array whose dimensions are the remaining dimensions, and so on. Extension 1 The NESTED-SEQUENCES used to specify the :INITIAL-CONTENTS may be either another array of the same dimensionality and element type, or a list of lists. :DISPLACED-TO ARRAY%This argument will be an array whose linearized data segment will be shared with the one being ┅made.构 This array must have the same :ELEMENT-TYPE as the one being created. See also the :DISPLACED-INDEX-OFFSET argument. Array elements are always stored in row major order (last index varies fastest). Implementation Note 1 Currently it is not possible to :DISPLACE-TO an existing Interlisp array data type like: BITMAP, STRINGP, ARRAYP. Only the new data type ARRAY allows this. :DISPLACED-INDEX-OFFSET INTEGER%When creating a displaced array, which shares storage with a source array, this specifies the offset from the origin of the source array, where the displaced array will have its zero index element. Default is zero. Extensions 1 Several additional keywords are available: :DISPLACED-TO-BASE POINTER%Like :DISPLACED-TO except its argument is a bare pointer or address, rather than another array. In this way, one can use the Common Lisp array functions to access parts of Interlisp-D's memory, such as the screen bit map. These next two keywords are rarely useful, except for programming that needs to deal directly with microcoded operations. :PAGE-ALIGN VALUE%If non-NIL causes the array's allocated block of storage to begin on a page boundary. :ALIGNMENT INTEGER%An integer, indicating object size in words. Allocates the array's storage block such that its address falls on an object boundary of the given size. :ADJUSTABLE VALUE%If value is non-NIL this array may be given to ADJUST-ARRAY to alter size and other parameters. Typically nonadjustable arrays will have a more efficient representation. :FILL-POINTER INTEGER-OR-T%The array being created must be one-dimensional. If T the fill pointer is set to the size in elements of the vector (useful if the array is also initialized containing a resource, with :INITIAL-ELEMENT or :INITIAL-CONTENTS, and in conjunction with VECTOR-POP), otherwise it must be an integer between zero and the size of the vector, inclusive. Examples 1 Create a one-dimensional array of five elements: (MAKE-ARRAY 5) Create a two-dimensional array, three by four, with eight-bit elements: (MAKE-ARRAY '(3 4) :ELEMENT-TYPE '(MOD 256)) Create a three-dimensional array, four by two by three, initially containing some symbols and numbers: (SETQ A (MAKE-ARRAY '(4 2 3) :INITIAL-CONTENTS '( ((a b c) (1 2 3)) ((d e f) (3 1 2)) ((g h i) (2 3 1)) ((j k l) (0 0 0))))) Create a new array with the same rank and dimensions, copying into it the contents of A: (MAKE-ARRAY '(4 2 3) :INITIAL-CONTENTS A) Create a one-dimensional array of 107 eight-bit bytes: (SETQ B (MAKE-ARRAY 107 :ELEMENT-TYPE '(UNSIGNED-BYTE 8))) Create a new array C, whose contents are shared with array B. The second element of C, with index one, is the same element as that at position 52 in B: (SETQ C (MAKE-ARRAY 8 :ELEMENT-TYPE '(UNSIGNED-BYTE 8) :DISPLACED-TO B :DISPLACED-INDEX-OFFSET 51)) Note that an :ELEMENT-TYPE specification of (UNSIGNED-BYTE 8) is equivalent to that in the first example of (MOD 256). (CL:ARRAYP OBJECT) [Function] Returns T if the given object is an array, NIL otherwise. Note that a one-dimensional array (VECTOR) is still considered an array, and a vector can be a string, etc. Vectors 1 A one-dimensional array is called a vector. A VECTOR that is not displaced, has no fill pointer, and is not adjustable, with element type T, is called a SIMPLE-VECTOR. (VECTOR &REST OBJECTS) [Function] Creates a SIMPLE-VECTOR, a one-dimensional array with element-type T and having no displacement, no fill pointer, and which will not be adjustable. The SIMPLE-VECTOR will be of the same size as the length of the list of objects, and its contents will be initialized with them. (VECTORP OBJECT) [Function] If the given object is a vector, returns T, else NIL. 2 Accessing and Changing the Elements of an Array 1 The main primitive to access the elements of an array is called AREF (for ┅Array REFerence of element构). Note that AREF does not take into account any :FILL-POINTER value. The number of indices given must equal the rank of the array. Arrays of NIL dimensions have their single element referenced with no subscripts. It is an error to attempt to reference a ┅degenerate array构 (see MAKE-ARRAY above). (AREF ARRAY &REST SUBSCRIPTS) [Function] This returns the element of ARRAY specified by the subscripts (which are all the remaining arguments after ARRAY), and each subscript must be a non-negative integer less than the corresponding array dimension. (SETF (AREF ARRAY &REST SUBSCRIPTS) VALUE) [Form] or (ASET VALUE ARRAY &REST SUBSCRIPTS) [Function] This is the main primitive to change the elements of an array. Note that this does not take into account any :FILL-POINTER value. Note: SETF syntax is only available with the CML package loaded. Vectors 1 A one-dimensional array is called a vector. (SVREF SIMPLE-VECTOR INDEX) [Function] Accesses an element of a simple-vector. (SETF (SVREF SIMPLE-VECTOR INDEX) VALUE) [Form] or (SVSET VALUE SIMPLE-VECTOR INDEX) [Function] Sets the value of an element in a simple-vector. Note: SETF syntax is only available with the CML package loaded. Bit Arrays 1 An array whose elements are of type BIT is called a bit array. (BIT BIT-VECTOR INDEX) [Function] (SBIT BIT-VECTOR INDEX) [Function] Reference an element of a bit vector (BIT), or simple bit vector (SBIT). (SETF (BIT BIT-VECTOR INDEX) VALUE) [Form] (SETF (SBIT BIT-VECTOR INDEX) VALUE) [Form] or (SBITSET VALUE BIT-VECTOR INDEX) [Function] Set the value of an element in a bit vector or simple bit vector. Note: SETF syntax is only available with the CML package loaded. Implementation Notes 1 In Interlisp-D these functions are currently unoptimized. The logical bit operations (BIT-AND, BIT-IOR, etc., on bit arrays) are not currently implemented. 2 Fill Pointer Operations 1 These functions manipulate vectors with fill pointers. These allow the creation of efficiently stored pushdown lists, etc. Moreover, they allow the notion of partially filled vectors (strings of easily variable length, etc.). Be aware that most functions outside this section ignore fill pointers (except for printing and equality tests). For a vector with a fill pointer, it is set to zero when the vector is ┅empty构 and the length of the vector when it is ┅full.构 (ARRAY-HAS-FILL-POINTER-P VECTOR) [Function] Returns T if the given VECTOR has a fill pointer, otherwise NIL. (VECTOR-PUSH NEW-ELEMENT VECTOR) [Function] Pushes a new element onto a vector with a fill pointer. If the fill pointer designates an element within the vector (e.g., there's room left) the element is stored in that position and the fill pointer is incremented by one. In this case VECTOR-PUSH returns the previous value of the fill pointer (the value is the index of the pushed element). If the fill pointer is too large (i.e., equal to the size of the vector) VECTOR-PUSH will not perform the store and increment and instead returns NIL. (VECTOR-PUSH-EXTEND NEW-ELEMENT VECTOR &OPTIONAL EXTENSION-SIZE) [Function] Just like VECTOR-PUSH, except if the fill pointer designates an out-of-bounds position the vector is enlarged (using ADJUST-ARRAY). If the vector is not :ADJUSTABLE an error is signalled. If provided EXTENSION-SIZE must be a positive integer, and is the amount by which to increase the size of the vector. If it is not provided an implementation default is used. (VECTOR-POP VECTOR) [Function] VECTOR is a one-dimensional array with a fill pointer. If the fill pointer is zero an error is signalled, otherwise it is decremented and the element at the new position is returned. (FILL-POINTER VECTOR) [Function] Returns the vector's fill pointer value. It is an error if the vector has no fill pointer. (SETF (FILL-POINTER VECTOR) VALUE) [Form] Allows the fill pointer of a vector to be set (it must have been created with one). The value must be a positive integer between zero and the size of the vector (inclusive). If the fill pointer is set to the size of the vector no elements may be pushed onto it (this is the ┅full构 condition). Note: SETF syntax is only available with the CML package loaded. 2 Informational Functions 1 These functions return the information in the header of the array. (ARRAY-ELEMENT-TYPE ARRAY) [Function] Returns a type specifier for the set of objects that can be stored in ARRAY. This set may be larger than the set requested when ARRAY was created; that is, (ARRAY-ELEMENT-TYPE (MAKE-ARRAY 5 :ELEMENT-TYPE '(MOD 5))) could be (MOD 8), or (UNISIGNED-BYTE 16), or FIXNUM, or even T. (ARRAY-RANK ARRAY) [Function] Returns the number of dimensions of ARRAY; to parallel the indexing range; this is a zero-origin number and thus will be a non-negative integer. (ARRAY-DIMENSION ARRAY AXIS-NUMBER) [Function] Returns the length of dimension number AXIS-NUMBER of ARRAY; AXIS-NUMBER should be a non-negative integer less than the rank of ARRAY. (ARRAY-DIMENSIONS ARRAY) [Function] Returns a list whose elements are the dimensions of ARRAY. (ARRAY-TOTAL-SIZE ARRAY) [Function] Returns the total number of elements in ARRAY, calculated as the product of all the dimensions. Roughly equivalent to (APPLY (FUNCTION TIMES) (ARRAY-DIMENSIONS ARRAY)) Note that the total size of a zero-dimensional array should be one. Note also that this function ignores fill pointers. (ARRAY-IN-BOUNDS-P ARRAY&REST SUBSCRIPTS ) [Function] This predicate checks whether the subscripts are all legal subscripts for ARRAY and is true if they are; otherwise it is false. The subscripts must be integers. The number of subscripts supplied must equal the rank of the array. E.g., if HA is a three-dimensional array, then (ARRAY-IN-BOUNDS-P HA 4 25 62) makes the check such that (AREF HA 4 25 62) will not cause an illegal subscript error. Note that this function ignores fill pointers. (ARRAY-ROW-MAJOR-INDEX ARRAY&REST SUBSCRIPTS) [Function] This function takes an array and valid subscripts for the array, and returns a single non-negative integer less than the total size of the array that identifies the accessed element in the row-major ordering of the elements. The number of subscripts supplied must equal the rank of the array. Each subscript must be a non-negative integer less than the corresponding array dimension. For a one-dimensional array, the result of this function always equals the supplied subscript. Like the other functions in this section, ARRAY-ROW-MAJOR-INDEX ignores fill pointers. (ADJUSTABLE-ARRAY-P ARRAY) [Function] Returns T if the ARRAY was created with a non-NIL :ADJUSTABLE argument. 2 Changing the Dimensions of an Array 1 (ADJUST-ARRAY ARRAY NEW-DIMENSIONS &KEY :ELEMENT-TYPE :INITIAL-ELEMENT :INITIAL-CONTENTS :DISPLACED-TO :DISPLACED-INDEX-OFFSET :FILL-POINTER) [Function] Takes an array and a list of dimensions, just as with MAKE-ARRAY. The number of dimensions specified by NEW-DIMENSIONS must equal the rank of ARRAY. Returns ARRAY, whose components have been updated to conform to the new specifications (but if the new dimensions require more space in the block data area, this will cause copying into a newly allocated block, and ARRAY will be :DISPLACED-TO this new block). Most other arguments function as they do in MAKE-ARRAY. Only one of either :INITIAL-ELEMENT, :INITIAL-CONTENTS, or :DISPLACED-TO may be specified. Interpretation 1 Common Lisp: The Language is obscure on exactly what ADJUST-ARRAY does. Careful reading and discussions with Common Lisp implementors outside Xerox has led to the following interpretation. The ADJUST-ARRAY function encounters four basic cases. These are listed in order of precedence, highest to lowest: New displacement. If a displacement is provided, none of the original array contents appear in the resulting array. Undisplace an array. If the original array was displaced to another array, then the original contents of the array, shared as they were with another array, disappear and new storage of the appropriate size is created. Change size. The array's total number of elements grows or shrinks and is copied to a new block of storage that the array is :DISPLACED-TO. Same size. The array's individual dimensions change size, but the array's total size remains the same. :ELEMENT-TYPE TYPE-SPECIFIER%Does not change the type of elements in the array! Rather, it signals an error if the array could not hold elements of this type. :INITIAL-ELEMENT OBJECT%Causes the newly adjusted array to have this element in all positions. :INITIAL-CONTENTS NESTED-SEQUENCES%Causes the newly adjusted array to have this as its contents. :DISPLACED-TO ARRAY%Causes the adjusted array to be a displaced array, one whose storage is shared with the given array. The given array must be large enough to contain the elements. :DISPLACED-INDEX-OFFSET INTEGER%Is a positive integer specifying the linear offset from the beginning of the ┅displaced to构 array's elements, where this array will begin its addressing. :FILL-POINTER INTEGER-OR-T%The array being adjusted must be one-dimensional and have a fill pointer. If the value is T the fill pointer is set to the length of the vector, otherwise it must be an INTEGER between zero and the size of the vector, inclusive. Extension 1 The keywords :PAGE-ALIGN :ALIGNMENT and :DISPLACED-TO-BASE are provided and behave as for MAKE-ARRAY. Implementation Note 1 Arrays that were previously aligned or displaced to a bare base pointer will lose these properties unless they are explicitly respecified in the call to ADJUST-ARRAY. 2 Array Input/Output 1 The following applies only to the printing of arrays and vectors when the CMLArray package is loaded. The following variables control array printing. Note that rereading an array printed to a file depends on none of its structure being hidden when printed. It is important to set the control variables to NIL before saving arrays to files. Reading 1 Note that the use of ┅#构 is only supported in CMLExec. Elsewhere (i.e., in Interlisp) the vertical bar ┅|构 must be used instead. The standard formats for reading arrays are all supported. These are: #LENGTH(CONTENTS) for vectors #LENGTH*BITS for bit vectors #RANKA(CONTENTS) for arrays A LENGTH field is optional. Note, however, that the RANK field for arrays is not optional. Type-in may suppress trailing elements if length is specified. For instance, a bit vector of 50 elements all zero may be written as: #50*0 Note that these formats do not attempt to preserve the element type, fill pointer, displacement, or adjustability of an array. Implementation Note 1 In Common Lisp the # read macro signals an error if this character is followed by a space, and an atom name containing all periods is declared ┅illegal.构 Thus, in a system with a full Common Lisp reader (which we currently don't have) attempting to read in an array, some of whose structure had been suppressed at print time, would produce an error. Printing 1 Print formats follow exactly those of reading. *PRINT-ARRAY* [Variable] Controls all printing of arrays, vectors, and bit vectors. If non-NIL arrays are printed uses one of the content displaying formats, described below. Otherwise they appear in the unprintable object format. *PRINT-LEVEL* [Variable] Controls the depth of array printing. NIL indicates no control is exercised (this is the default). If set to a number this variable suppresses printing of structure above the set level, displaying a ┅#构 instead. Zero is the base level, where all structure display is suppressed. A print level of one would not display any structure past the first level or dimension, etc. *PRINT-LENGTH* [Variable] Controls the length of any individual array segment printed. If NIL, no control is exercised (this is the default). If set to an integer, it suppresses printing of elements beyond this linear position, displaying an ellipsis instead. Some examples: level length display 0 3 # 1 3 #2A(# # #) 2 3 #2A((1 2 3 . . .) (4 5 6 . . .) (7 8 9 . . .) . . .) Implementation Note 1 In order to maintain some compatibility with Interlisp-D, the array-printing prefix character is initially set to vertical bar ┅|构. This can be changed to the actual Common Lisp character by setting the variable \CML.READPREFIX to the string ┅#构. Inside a CMLExec window this is done automatically; see the CML package documentation. In Interlisp, or without CML loaded, this syntax is accessible by prefixing the # character with ┅| 构 like this: |#(1 2 3) Implementation Note 1 *PRINT-ARRAY* defaults to NIL. If this is set to a non-NIL value, beware. When creating large arrays it is wise to set *PRINT-LEVEL* and *PRINT-LENGTH* to provide reasonable display limits. 2 Inspecting Arrays 1 Note: CMLArrayInspector is automatically loaded by CML but not by CMLArray. Thus, if you are using CMLArray standalone and would like to use CMLArrayInspector, you must explicitly load it. An array inspector has three windows: a header information window, a view format window, and a content display window attached on the left. The header information window displays the element type, total size, rank, and dimensionality of the array. The view format window controls which slice of the array's contents is shown in the contents display window. Buttoning on SHOW will display in the view format window the set of restrictions that describe the array slice being displayed in the contents window. Buttoning on APPLY will cause the current setting in the view format window to determine the array slice displayed in the contents display window. An array slice is determined by a set of restrictions on all the dimensions of the array. The restriction can be ALL (meaning to show every element of that dimension), or some integer less than that dimension of the array. The view format window will not appear if you are inspecting a vector. Example: Imagining the array to be a series of rows and columns you might, for instance, want to show all the elements in column three. To do this you would APPLY the restrictions: rows (dimension 0) set to ALL columns (dimension 1) set to 3 The contents display window is capable of showing either a two- or one-dimensional slice of an array. The window is scrollable. A particular datum in the contents display may be selected by left buttoning on it. Middle buttoning in the contents display then pops up a menu that allows either display of the indices of the datum (in a box in the header window), setting of this position's value, or binding IT to the selected datum.(LIST ((PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC ) STARTINGPAGE# 347) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD RIGHT) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC )) (270 12 288 36) NIL) (HEADING NIL (HEADINGTYPE FOOTINGR) (54 27 558 36) NIL) (HEADING NIL (HEADINGTYPE RECTOHEAD) (54 762 558 36) NIL) (TEXT NIL NIL (54 54 504 618) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC )) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD LEFT) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC )) (54 12 288 36) NIL) (HEADING NIL (HEADINGTYPE FOOTINGV) (54 27 558 36) NIL) (HEADING NIL (HEADINGTYPE VERSOHEAD) (54 762 558 36) NIL) (TEXT NIL NIL (54 54 504 684) NIL))) (PAGE NIL (PAPERSIZE Letter FOLIOINFO (ARABIC )) (0 0 612 792) ((FOLIO NIL (PARALOOKS (QUAD RIGHT) CHARLOOKS (SUPERSCRIPT 0 INVISIBLE OFF SELECTPOINT OFF PROTECTED OFF SIZE 10 FAMILY MODERN OVERLINE OFF STRIKEOUT OFF UNDERLINE OFF EXPANSION REGULAR SLOPE REGULAR WEIGHT MEDIUM INVERTED OFF USERINFO NIL STYLE NIL) FORMATINFO (ARABIC )) (270 12 288 36) NIL) (HEADING NIL (HEADINGTYPE FOOTINGR) (54 27 558 36) NIL) (HEADING NIL (HEADINGTYPE RECTOHEAD) (54 762 558 36) NIL) (TEXT NIL NIL (54 54 504 684) NIL)))))#.&()T./&T/8 T/T/T2 T) T/T/ T4 4D4D7D1122T2T1 .1)T.)2T)T(( )T)TB PAGEHEADING VERSOHEADB PAGEHEADING RECTOHEADA PAGEHEADINGFOOTINGVA PAGEHEADINGFOOTINGR TERMINAL MODERN MODERNMODERN HELVETICA MODERN MODERN MODERN MODERN # HRULE.GETFNMODERN #" HRULE.GETFNMODERN "! ! HRULE.GETFNMODERN    HRULE.GETFNMODERN   HRULE.GETFNMODERN  HRULE.GETFNMODERN HRULE.GETFNMODERN- HRULE.GETFNMODERN HRULE.GETFNMODERNR p ? .   HRULE.GETFNMODERN  7 HRULE.GETFNMODERN HRULE.GETFNMODERN  . 1  HRULE.GETFNMODERN    `H d J   SRS f  HRULE.GETFNMODERN 1  HRULE.GETFNMODERN     HRULE.GETFNMODERN  1  HRULE.GETFNMODERN   5  HRULE.GETFNMODERN    HRULE.GETFNMODERN + z  X     \  HRULE.GETFNMODERN 1H-g/Z*7<"x   HRULE.GETFNMODERN    6 HRULE.GETFNMODERN0 HRULE.GETFNMODERN   J b    /B HRULE.GETFNMODERN , (   -1B  HRULE.GETFNMODERN ?  I      ,BB   HRULE.GETFNMODERN :b HRULE.GETFNMODERN HRULE.GETFNMODERN  $     A     \  )B HRULE.GETFNMODERN HRULE.GETFNMODERNC F 6 ;@  $ h  '   8  ; ( K2y  J   > :  2 HRULE.GETFNMODERN$ HRULE.GETFNMODERN  wi    `[   HRULE.GETFNMODERN  twj  I @      HRULE.GETFNMODERN f   HRULE.GETFNMODERN  HRULE.GETFNMODERN HRULE.GETFNMODERNg  HRULE.GETFNMODERN      - #  HRULE.GETFNMODERN a  HRULE.GETFNMODERN /z<  HRULE.GETFNMODERN Ts   HRULE.GETFNMODERN  HRULE.GETFNMODERN HRULE.GETFNMODERNl  c'z