From sources-request@genrad.UUCP Fri Apr 12 17:38:09 1985 Relay-Version: version B 2.10.3 alpha 4/3/85; site seismo.UUCP Posting-Version: version B 2.10.2 9/3/84; site genrad.UUCP Path: seismo!harvard!talcott!panda!genrad!sources-request From: sources-request@genrad.UUCP Newsgroups: mod.sources Subject: Sun RPC part 2 of 10 (+ moderators note) Message-ID: <751@genrad.UUCP> Date: 12 Apr 85 22:38:09 GMT Date-Received: 13 Apr 85 05:21:40 GMT Sender: john@genrad.UUCP Lines: 2383 Approved: john@genrad.UUCP [ Moderators note: This module includes the troff macro package "tmac.sun" Note that this macro package uses the macro files for the "ms" macro package - which reside on /usr/lib/ms. Actually, for BSD4.2 on a VAX, I found I had to change lines in the package that looked like ".so \*(//ms.cov" to ".so \*(//s.cov" because the naming convention seems to be different. If you have trouble [nt]roffing the file, dont send mail to me, send mail directly to the author: sun!blyon ] From: blyon@sun (Bob Lyon) ----------------- cut here -------------------- # run this script through "sh" to extract files mkdir doc; cd doc echo x - README sed 's/^X//' >README <<'!Funky!Stuff!' rpc.prog and rpc.prog2 must be catted together before troffing. Same goes for xdr.spec and xdr.spec2. !Funky!Stuff! echo x - portmap.8c sed 's/^X//' >portmap.8c <<'!Funky!Stuff!' X.\" @(#)portmap.8c 1.1 85/02/25 SMI; X.TH PORTMAP 8C "1 February 1985" X.SH NAME portmap \- DARPA port to RPC program number mapper X.SH SYNOPSIS X.B /usr/etc/rpc.portmap X.SH DESCRIPTION X.I Portmap is a server that converts RPC program numbers into DARPA protocol port numbers. It must be running in order to make RPC calls. X.PP When an RPC server is started, it will tell X.I portmap what port number it is listening to, and what RPC program numbers it is prepared to serve. When a client wishes to make an RPC call to a given program number, it will first contact X.I portmap on the server machine to determine the port number where RPC packets should be sent. X.PP Normally, standard RPC servers are started by X.IR inetd (8c), so X.I portmap must be started before X.I inetd is invoked. X.SH "SEE ALSO" servers(5), rpcinfo(8), inetd(8) X.SH BUGS If X.I portmap crashes, all servers must be restarted. !Funky!Stuff! echo x - rpc.spec sed 's/^X//' >rpc.spec <<'!Funky!Stuff!' X.OH 'RPC Protocol Spec''Page \\\\n(PN' X.EH 'Page \\\\n(PN''RPC Protocol Spec' X.OF 'Sun Microsystems''Release 2.0' X.EF 'Release 2.0''Sun Microsystems' X.RP X.rm DY X.TL X.ps 20 Remote Procedure Call X.sp.5 Protocol Specification X. X.H 1 "Introduction" X.LP This document specifies a message protocol used in implementing Sun's Remote Procedure Call (RPC) package. The protocol is specified with the eXternal Data Representation (XDR) language. X.LP This document assumes that the reader is familiar with both RPC and XDR. It does not attempt to justify RPC or its uses. Also, the casual user of RPC does not need to be familiar with the information in this document. X. X.H 2 "Terminology" X.LP The document discusses servers, services, programs, procedures, clients and versions. A server is a machine where some number of network services are implemented. A service is a collection of one or more remote programs. A remote program implements one or more remote procedures; the procedures, their parameters and results are documented in the specific program's protocol specification (see Appendix 3 for an example). Network clients are pieces of software that initiate remote procedure calls to services. A server may support more than one version of a remote program in order to be forward compatible with changing protocols. X.LP For example, a network file service may be composed of two programs. One program may deal with high level applications such as file system access control and locking. The other may deal with low-level file I/O, and have procedures like ``read'' and ``write''. A client machine of the network file service would call the procedures associated with the two programs of the service on behalf of some user on the client machine. X.H 2 "The RPC Model" X.LP The remote procedure call model is similar to the local procedure call model. In the local case, the caller places arguments to a procedure in some well-specified location (such as a result register). It then transfers control to the procedure, and eventually gains back control. At that point, the results of the procedure are extracted from the well-specified location, and the caller continues execution. X.LP The remote procedure call is similar, except that one thread of control winds through two processes \(em one is the caller's process, the other is a server's process. That is, the caller process sends a call message to the server process and waits (blocks) for a reply message. The call message contains the procedure's parameters, among other things. The reply message contains the procedure's results, among other things. Once the reply message is received, the results of the procedure are extracted, and caller's execution is resumed. X.LP On the server side, a process is dormant awaiting the arrival of a call message. When one arrives the server process extracts the procedure's parameters, computes the results, sends a reply message, and then awaits the next call message. Note that in this model, only one of the two processes is active at any given time. That is, the RPC protocol does not explicitly support multi-threading of caller or server processes. X. X.H 2 "Transports and Semantics" X.LP The RPC protocol is independent of transport protocols. That is, RPC does not care how a message is passed from one process to another. The protocol only deals with the specification and interpretation of messages. X.LP Because of transport independence, the RPC protocol does not attach specific semantics to the remote procedures or their execution. Some semantics can be inferred from (but should be explicitly specified by) the underlying transport protocol. For example, RPC message passing using UDP/IP is unreliable. Thus, if the caller retransmits call messages after short time-outs, the only thing he can infer from no reply message is that the remote procedure was executed zero or more times (and from a reply message, one or more times). On the other hand, RPC message passing using TCP/IP is reliable. No reply message means that the remote procedure was executed at most once, whereas a reply message means that the remote procedure was exactly once. (Note: At Sun, RPC is currently implemented on top of TCP/IP and UDP/IP transports.) X. X.H 2 "Binding and Rendezvous Independence" X.LP The act of binding a client to a service is NOT part of the remote procedure call specification. This important and necessary function is left up to some higher level software. (The software may use RPC itself; see Appendix 3.) X.LP Implementors should think of the RPC protocol as the jump-subroutine instruction (``JSR'') of a network; the loader (binder) makes JSR useful, and the loader itself uses JSR to accomplish its task. Likewise, the network makes RPC useful, using RPC to accomplish this task. X. X.H 2 "Message Authentication" X.LP The RPC protocol provides the fields necessary for a client to identify himself to a service and vice versa. Security and access control mechanisms can be built on top of the message authentication. X.bp X. X.H 1 "Requirements" X.LP The RPC protocol must provide for the following: X.DS 1. Unique specification of a procedure to be called. 2. Provisions for matching response messages to request messages. 3. Provisions for authenticating the caller to service and vice versa. X.DE Besides these requirements, features that detect the following are worth supporting because of protocol roll-over errors, implementation bugs, user error, and network administration: X.DS 1. RPC protocol mismatches. 2. Remote program protocol version mismatches. 3. Protocol errors (like mis-specification of a procedure's parameters). 4. Reasons why remote authentication failed. 5. Any other reasons why the desired procedure was not called. X.DE X. X.H 2 "Remote Programs and Procedures" X.LP The RPC call message has three unsigned fields: remote program number, remote program version number, and remote procedure number. The three fields uniquely identify the procedure to be called. Program numbers are administered by some central authority (like Sun). Once an implementor has a program number, he can implement his remote program; the first implementation would most likely have the version number of 1. Because most new protocols evolve into better, stable and mature protocols, a version field of the call message identifies which version of the protocol the caller is using. Version numbers make speaking old and new protocols through the same server process possible. X.LP The procedure number identifies the procedure to be called. These numbers are documented in the specific program's protocol specification. For example, a file service's protocol specification may state that its procedure number 5 is X.L read and procedure number 12 is X.L write . X.LP Just as remote program protocols may change over several versions, the actual RPC message protocol could also change. Therefore, the call message also has the RPC version number in it; this field must be two (2). X.LP The reply message to a request message has enough information to distinguish the following error conditions: X.IP 1) The remote implementation of RPC does speak protocol version 2. The lowest and highest supported RPC version numbers are returned. X.IP 2) The remote program is not available on the remote system. X.IP 3) The remote program does not support the requested version number. The lowest and highest supported remote program version numbers are returned. X.IP 4) The requested procedure number does not exist (this is usually a caller side protocol or programming error). X.IP 5) The parameters to the remote procedure appear to be garbage from the server's point of view. (Again, this is caused by a disagreement about the protocol between client and service.) X. X.H 2 "Authentication" X.LP Provisions for authentication of caller to service and vice versa are provided as a wart on the side of the RPC protocol. The call message has two authentication fields, the credentials and verifier. The reply message has one authentication field, the response verifier. The RPC protocol specification defines all three fields to be the following opaque type: X.LS enum auth_flavor { AUTH_NULL = 0, AUTH_UNIX = 1, AUTH_SHORT = 2 /* and more to be defined */ }; X.sp.5 struct opaque_auth { union switch (enum auth_flavor) { default: string auth_body<400>; }; }; X.LE In simple English, any X.L opaque_auth structure is an X.L auth_flavor enumeration followed by a counted string, whose bytes are opaque to the RPC protocol implementation. X.LP The interpretation and semantics of the data contained within the authentication fields is specified by individual, independent authentication protocol specifications. Appendix 1 defines three authentication protocols. X.LP If authentication parameters were rejected, the response message contains information stating why they were rejected. X. X.H 2 "Program Number Assignment" X.LP Program numbers are given out in groups of 0x20000000 (536870912) according to the following chart: X.LS 0 - 1fffffff defined by Sun 20000000 - 3fffffff defined by user 40000000 - 5fffffff transient 60000000 - 7fffffff reserved 80000000 - 9fffffff reserved a0000000 - bfffffff reserved c0000000 - dfffffff reserved e0000000 - ffffffff reserved X.LE The first group is a range of numbers administered by Sun Microsystems, and should be identical for all Sun customers. The second range is for applications peculiar to a particular customer. This range is intended primarily for debugging new programs. When a customer develops an application that might be of general interest, that application should be given an assigned number in the first range. The third group is for applications that generate program numbers dynamically. The final groups are reservered for future use, and should not be used. X.LP The exact registration process for Sun defined numbers is yet to be established. X.bp X. X.H 1 "Other Uses and Abuses of the RPC Protocol" X.LP The intended use of this protocol is for calling remote procedures. That is, each call message is matched with a response message. However, the protocol itself is a message passing protocol with which other (non-RPC) protocols can be implemented. Sun currently uses (abuses) the RPC message protocol for the following two (non-RPC) protocols: batching (or pipelining) and broadcast RPC. These two protocols are discussed (but not defined) below. X. X.H 2 "Batching" X.LP Batching allows a client to send an arbitrarily large sequence of call messages to a server; batching uses reliable bytes stream protocols (like TCP/IP) for their transport. In the case of batching, the client never waits for a reply from the server and the server does not send replies to batch requests. A sequence of batch calls is usually terminated by a legitimate RPC in order to flush the pipeline (with positive acknowledgement). X. X.H 2 "Broadcast RPC" X.LP In broadcast RPC based protocols, the client sends an a broadcast packet to the network and waits for numerous replies. Broadcast RPC uses unreliable, packet based protocols (like UDP/IP) as their transports. Servers that support broadcast protocols only respond when the request is successfully processed, and are silent in the face of errors. X. X.H 1 "The RPC Message Protocol" X.LP This section defines the RPC message protocol in the XDR data description language. The message is defined in a top down style. Note: This is an XDR specification, not C code. X.LP X.LS 0 enum msg_type { CALL = 0, REPLY = 1 }; X.LE X.LS 0 /* * A reply to a call message can take on two forms: * the message was either accepted or rejected. */ enum reply_stat { MSG_ACCEPTED = 0, MSG_DENIED = 1 }; X.LE X.LS 0 /* * Given that a call message was accepted, the following is the status of * an attempt to call a remote procedure. */ enum accept_stat { SUCCESS = 0, /* remote procedure was successfully executed */ PROG_UNAVAIL = 1, /* remote machine exports the program number */ PROG_MISMATCH = 2, /* remote machine can't support version number */ PROC_UNAVAIL = 3, /* remote program doesn't know about procedure */ GARBAGE_ARGS = 4 /* remote procedure can't figure out parameters */ }; X.LE X.LS 0 /* * Reasons why a call message was rejected: */ enum reject_stat { RPC_MISMATCH = 0, /* RPC version number was not two (2) */ AUTH_ERROR = 1 /* caller not authenticated on remote machine */ }; X.LE X.LS 0 /* * Why authentication failed: */ enum auth_stat { AUTH_BADCRED = 1, /* bogus credentials (seal broken) */ AUTH_REJECTEDCRED = 2, /* client should begin new session */ AUTH_BADVERF = 3, /* bogus verifier (seal broken) */ AUTH_REJECTEDVERF = 4, /* verifier expired or was replayed */ AUTH_TOOWEAK = 5, /* rejected due to security reasons */ }; X.LE X.LS 0 /* * The RPC message: * All messages start with a transaction identifier, xid, followed by * a two-armed discriminated union. The union's discriminant is a msg_type * which switches to one of the two types of the message. The xid of a * REPLY message always matches that of the initiating CALL message. * NB: The xid field is only used for clients matching reply messages with * call messages; the service side cannot treat this id as any type of * sequence number. */ struct rpc_msg { unsigned xid; union switch (enum msg_type) { CALL: struct call_body; REPLY: struct reply_body; }; }; X.LE X.LS 0 /* * Body of an RPC request call: * In version 2 of the RPC protocol specification, rpcvers must be equal to 2. * The fields prog, vers, and proc specify the remote program, its version, * and the procedure within the remote program to be called. These fields are * followed by two authentication parameters, cred (authentication credentials) * and verf (authentication verifier). The authentication parameters are * followed * by the parameters to the remote procedure; these parameters are * specified by the specific program protocol. */ struct call_body { unsigned rpcvers; /* must be equal to two (2) */ unsigned prog; unsigned vers; unsigned proc; struct opaque_auth cred; struct opaque_auth verf; /* procedure specific parameters start here */ }; X.LE X.LS 0 /* * Body of a reply to an RPC request. * The call message was either accepted or rejected. */ struct reply_body { union switch (enum reply_stat) { MSG_ACCEPTED: struct accepted_reply; MSG_DENIED: struct rejected_reply; }; }; X.LE X.LS 0 /* * Reply to an RPC request that was accepted by the server. * Note: there could be an error even though the request was accepted. * The first field is an authentication verifier which the server generates * in order to validate itself to the caller. It is followed by a union * whose discriminant is an enum accept_stat. The SUCCESS arm of the union is * protocol specific. The PROG_UNAVAIL, PROC_UNAVAIL, and GARBAGE_ARGS arms * of the union are void. The PROG_MISMATCH arm specifies the lowest and * highest version numbers of the remote program that are supported by the * server. */ struct accepted_reply { struct opaque_auth verf; union switch (enum accept_stat) { SUCCESS: struct { /* * procedure-specific results start here */ }; PROG_MISMATCH: struct { unsigned low; unsigned high; }; default: struct { /* * void. Cases include PROG_UNAVAIL, * PROC_UNAVAIL, and GARBAGE_ARGS. */ }; }; }; X.LE X.LS 0 /* * Reply to an RPC request that was rejected by the server. * The request can be rejected because of two reasons - either the server is * not running a compatible version of the RPC protocol (RPC_MISMATCH), or * the server refused to authenticate the caller (AUTH_ERROR). In the case of * an RPC version mismatch, the server returns the lowest and highest supported * RPC version numbers. In the case of refused authentication, the failure * status is returned. */ struct rejected_reply { union switch (enum reject_stat) { RPC_MISMATCH: struct { unsigned low; unsigned high; }; AUTH_ERROR: enum auth_stat; }; }; X.LE X.bp X. X.H 1 "Appendix 1: Authentication Parameters Specification" X.LP As previously stated, authentication parameters are opaque, but open-ended to the rest of the RPC protocol. This section defines some ``flavors'' of authentication which have been implemented at (and supported by) Sun. X. X.H 2 "Null Authentication" X.LP Often calls must be made where the caller does not know who he is and the server does not care who the caller is. In this case, the auth_flavor value (the discriminant of the opaque_auth's union) of the RPC message's credentials, verifier, and response verifier is AUTH_NULL (0). The bytes of the auth_body string are undefined. It is recommended that the string length be zero. X. X.H 2 "UNIX Authentication" X.LP The caller of a remote procedure may wish to identify himself as he is identified on a X.UX system. The value of the X.I credential's discriminant of an RPC call message is AUTH_UNIX (1). The bytes of the X.I credential's string encode the the following (XDR) structure: X.LS struct auth_unix { unsigned stamp; string machinename<255>; unsigned uid; unsigned gid; unsigned gids<10>; }; X.LE The X.L stamp is an arbitrary id which the caller machine may generate. The X.L machinename is the name of the caller's machine (like ``krypton''). The X.L uid is the caller's effective user id. The X.L gid is the callers effective group id. The X.L gids is a counted array of groups which contain the caller as a member. The X.I verifier accompanying the credentials should be of AUTH_NULL (defined above). X.LP The value of the discriminate of the X.I "response verifier" received in the reply message from the server may be AUTH_NULL or AUTH_SHORT (2). In the case of AUTH_SHORT, the bytes of the X.I "response verifier" 's string encode an X.L auth_opaque structure. This new X.L auth_opaque structure may now be passed to the server instead of the original AUTH_UNIX flavor credentials. The server keeps a cache which maps short hand X.I auth_opaque structures (passed back via a AUTH_SHORT style X.L "response verifier" ) to the original credentials of the caller. The caller can save network bandwidth and server cpu cycles by using the new credentials. X.LP The server may flush the short hand X.I auth_opaque structure at any time. If this happens, the remote procedure call message will be rejected due to an authentication error. The reason for the failure will be AUTH_REJECTEDCRED. At this point, the caller may wish to try the original AUTH_UNIX style of credentials. X. X.H 1 "Appendix 2: Record Marking Standard (RM)" X.LP When RPC messages are passed on top of a byte stream protocol (like TCP/IP), it is necessary, or at least desirable, to delimit one message from another in order to detect and possibly recover from user protocol errors. Sun uses this RM/TCP/IP transport for passing RPC messages on TCP streams. One RPC message fits into one RM record. X.LP A record is composed of one or more record fragments. A record fragment is a four-byte header followed by X.I 0 to X.I "2\s-2\u31\d\s+2\-1" bytes of fragment data. The bytes encode an unsigned binary number; as with XDR integers, the byte order is from highest to lowest. The number encodes two values \(em a boolean which indicates whether the fragment is the last fragment of the record (bit value 1 implies the fragment is the last fragment) and a 31-bit unsigned binary value which is the length in bytes of the fragment's data. The boolean value is the highest-order bit of the header; the length is the 31 low-order bits. (Note that this record specification is X.I not in XDR standard form!) X. X.H 1 "Appendix 3: Port Mapper Program Protocol" X.LP The port mapper program maps RPC program and version numbers to UDP/IP or TCP/IP port numbers. This program makes dynamic binding of remote programs possible. X.LP This is desirable because the range of reserved port numbers is very small and the number of potential remote programs is very large. By running only the port mapper on a reserved port, the port numbers of other remote programs can be ascertained by querying the port mapper. X. X.H 2 "The Port Mapper RPC Protocol" X.LP The protocol is specified by the XDR description language. X.LP X.LS 0 Port Mapper RPC Program Number: 100000 Version Number: 1 Supported Transports: UDP/IP on port 111 RM/TCP/IP on port 111 X.LE X.LS 0 /* * Handy transport protocol numbers */ #define IPPROTO_TCP 6 /* protocol number used for rpc/rm/tcp/ip */ #define IPPROTO_UDP 17 /* protocol number used for rpc/udp/ip */ X.LE X.LS 0 /* Procedures */ /* * Convention: procedure zero of any protocol takes no parameters * and returns no results. */ 0. PMAPPROC_NULL () returns () X.LE X.LS 0 /* * Procedure 1, setting a mapping: * When a program first becomes available on a * machine, it registers itself with the port mapper program on the * same machine. The program passes its program number (prog), * version number (vers), transport protocol number (prot), * and the port (port) on which it awaits service request. The * procedure returns success whose value is TRUE if the procedure * successfully established the mapping and FALSE otherwise. The * procedure will refuse to establish a mapping if one already exists * for the tuple [prog, vers, prot]. */ 1. PMAPPROC_SET (prog, vers, prot, port) returns (success) unsigned prog; unsigned vers; unsigned prot; unsigned port; boolean success; X.LE X.LS 0 /* * Procedure 2, Unsetting a mapping: * When a program becomes unavailable, it should unregister itself * with the port mapper program on the same machine. The parameters * and results have meanings identical to those of PMAPPROC_SET. */ 2. PMAPPROC_UNSET (prog, vers, dummy1, dummy2) returns (success) unsigned prog; unsigned vers; unsigned dummy1; /* this value is always ignored */ unsigned dummy2; /* this value is always ignored */ boolean success; X.LE X.LS 0 /* * Procedure 3, looking-up a mapping: * Given a program number (prog), version number (vers) and * transport protocol number (prot), this procedure returns the port * number on which the program is awaiting call requests. A port * value of zeros means that the program has not been registered. */ 3. PMAPPROC_GETPORT (prog, vers, prot, dummy) returns (port) unsigned prog; unsigned vers; unsigned prot; unsigned dummy; /* this value is always ignored */ unsigned port; /* zero means the program is not registered */ X.LE X.LS 0 /* * Procedure 4, dumping the mappings: * This procedure enumerates all entries in the port mapper's database. * The procedure takes no parameters and returns a ``list'' of * [program, version, prot, port] values. */ 4. PMAPPROC_DUMP () returns (maplist) struct maplist { union switch (boolean) { FALSE: struct { /* void, end of list */ }; TRUE: struct { unsigned prog; unsigned vers; unsigned prot; unsigned port; struct maplist the_rest; }; }; } maplist; X.LE X.LS 0 /* * Procedure 5, indirect call routine: * The procedures allows a caller to call another remote procedure * on the same machine without knowing the remote procedure's port * number. Its intended use is for supporting broadcasts to arbitrary * remote programs via the well-known port mapper's port. The parameters * prog, vers, proc, and the bytes of args are the program number, * version number, procedure number, and parameters the the remote * procedure. * * NB: * 1. This procedure only sends a response if the procedure was * successfully executed and is silent (No response) otherwise. * 2. The port mapper communicates with the remote program via * UDP/IP only. * * The procedure returns the port number of the remote program and * the bytes of results are the results of the remote procedure. */ 5. PMAPPROC_CALLIT (prog, vers, proc, args) returns (port, results) unsigned prog; unsigned vers; unsigned proc; string args<>; unsigned port; string results<>; X.LE !Funky!Stuff! echo x - rpcinfo.8 sed 's/^X//' >rpcinfo.8 <<'!Funky!Stuff!' X.\" @(#)rpcinfo.8 1.1 85/02/25 SMI; X.TH RPCINFO 8 "1 February 1985" X.SH NAME rpcinfo \- report RPC information X.SH SYNOPSIS X.B "rpcinfo \-p" [ host ] X.br X.B "rpcinfo \-u" host program-number version-number X.br X.B "rpcinfo \-t" host program-number version-number X.SH DESCRIPTION X.I Rpcinfo makes an RPC call to an RPC server and reports what it finds. X.SH OPTIONS X.TP X.B \-p Probe the portmapper on X.IR host , and print a list of all registered RPC programs. If X.I host is not specified, it defaults to the value returned by X.IR hostname (1). X.TP X.B \-u Make an RPC call to procedure 0 of X.I program-number using UDP, and report whether a response was received. X.TP X.B \-t Make an RPC call to procedure 0 of X.I program-number using TCP, and report whether a response was received. X.SH "SEE ALSO" X.I "RPC Reference Manual," portmap(8) !Funky!Stuff! echo x - tmac.sun sed 's/^X//' >tmac.sun <<'!Funky!Stuff!' X.\" @(#)tmac.sun 1.1 84/12/21 SMI; The Sun Macro Package X.ds // /usr/lib/ms/ X. \" IZ - initialize (before text begins) X.de IZ X.nr FM 1i X.nr YY -\\n(FMu X.nr XX 0 1 X.nr IP 0 X.nr PI 4n X.nr QI 5n X.nr FI 2n X.nr I0 \\n(PIu X.if n .nr PD 1v X.if t .nr PD .5v X.if n .nr DD 1v X.if t .nr DD .5v X.nr PS 11 X.nr VS 13 X.ps \\n(PS X.vs \\n(VSp X.nr dP 1 X.nr dV 1 X.nr ML 3v X.nr IR 0 X.nr TB 0 X.nr SJ \\n(.j X.if \\nO .po \\nOu X.nr PO \\n(.ou X.nr LL 6.5i X.ll \\n(LLu X.lt 6.5i X.ev 1 X.nr FL 6i X.ll \\n(FLu X.ps 8 X.vs 10p X.ev X.ds CH - \\\\n(PN - X.if n .ds CF \\*(DY X.wh 0 NP X.wh -\\n(FMu FO X.ch FO 16i X.wh -\\n(FMu FX X.ch FO -\\n(FMu X.wh -\\n(FMu/2u BT X.. X. \" RT - reset (at new paragraph) X.de RT X.if !\\n(1T .BG X.if !\\n(IK .if !\\n(IF .if !\\n(IX .if !\\n(BE .di X.if \\n(TM .ls 2 X.ce 0 X.ul 0 X.if \\n(QP \{\ X. ll +\\n(QIu X. in -\\n(QIu X. nr QP -1 X.\} X.if \\n(NX<=1 .if !\\n(AJ .ll \\n(LLu X.if !\\n(IF \{\ X. ps \\n(PS X. if \\n(VS>=40 .vs \\n(VSu X. if \\n(VS<=39 .vs \\n(VSp X.\} X.if !\\n(IP .nr I0 \\n(PIu X.if \\n(IP \{\ X. in -\\n(I\\n(IRu X. nr IP -1 X.\} X.ft 1 X.TA X.fi X.. X. \" TA - set default tabs X.de TA X.if n .ta 8n 16n 24n 32n 40n 48n 56n 64n 72n 80n X.if t .ta 5n 10n 15n 20n 25n 30n 35n 40n 45n 50n 55n 60n 65n 70n 75n X.. X. \" BG - begin (at first paragraph) X.de BG X.br X.nr YE 1 X.di X.ce 0 X.nr KI 0 X.hy 14 X.nr 1T 1 X.S\\n(ST X.rm S0 S1 S2 SY TX AX WT RP X.\"redefs X.de TL X.ft 3 X.ce 99 X.sp X.LG \\.. X.de AU X.ft 2 X.if n .ul 0 X.ce 99 X.sp X.NL \\.. X.de AI X.ft 1 X.if n .ul 0 X.ce 99 X.if n .sp X.if t .sp .5 X.NL \\.. X.RA X.rn FJ FS X.rn FK FE X.nf X.ev 1 X.ps \\n(PS-2 X.vs \\n(.s+2p X.ev X.if !\\n(KG .nr FP 0 X.nr KG 0 X.if \\n(FP \{\ X. FS X. FG X. FE X.\} X.br X.if \\n(TV .if n .sp 2 X.if \\n(TV .if t .sp 1 X.fi X.ll \\n(LLu X.. X. \" RA - redefine abstract X.de RA X.de AB X.br X.if !\\n(1T .BG X.ce X.sp X.if !\\n(.$ ABSTRACT X.if \\n(.$ .if !\\$1no \\$1 X.if !\\n(.$ .sp X.if \\n(.$ .if !\\$1no .sp X.sp X.nr AJ 1 X.in +\\n(.lu/12u X.ll -\\n(.lu/12u X.RT X.if \\n(TM .ls 1 \\.. X.de AE X.nr AJ 0 X.br X.in 0 X.ll \\n(LLu X.if \\n(VS>=40 .vs \\n(VSu X.if \\n(VS<=39 .vs \\n(VSp X.if \\n(TM .ls 2 \\.. X.. X. \" RP - released paper format X.de RP X.nr ST 2 X.if \\$1no .nr ST 1 X.pn 0 X.br X.. X. \" TL - source file for cover sheet X.de TL X.rn TL @T X.so \*(//ms.cov X.TL X.rm @T X.. X. \" Paragraph Depth X.de PD X.if t .nr PD .5v X.if n .nr PD 1v X.if !\\$1 .nr PD \\$1v X.. X. \" PP - regular paragraph X.de PP X.RT X.if \\n(1T .sp \\n(PDu X.ne 1.1 X.ti +\\n(PIu X.. X. \" LP - left paragraph X.de LP X.RT X.if \\n(1T .sp \\n(PDu X.ne 1.1 X.ti \\n(.iu X.. X. \" IP - indented paragraph X.de IP X.RT X.if \\n(1T .sp \\n(PDu X.ne 1.1 X.if !\\n(IP .nr IP +1 X.if \\n(.$-1 .nr I\\n(IR \\$2n X.in +\\n(I\\n(IRu X.ta \\n(I\\n(IRu X.if \\n(.$ \{\ X.ds HT \&\\$1\^\^\^ X.ti -\\n(I\\n(IRu \\*(HT\t\c X.if \w\\*(HTu>(\\n(I\\n(IRu) .br X.\} X.. X. \" XP - exdented paragraph X.de XP X.RT X.if \\n(1T .sp \\n(PDu X.ne 1.1 X.if !\\n(IP .nr IP +1 X.in +\\n(I\\n(IRu X.ti -\\n(I\\n(IRu X.. X. \" QP - quote paragraph X.de QP X.ti \\n(.iu X.RT X.if \\n(1T .sp \\n(PDu X.ne 1.1 X.nr QP 1 X.in +\\n(QIu X.ll -\\n(QIu X.ti \\n(.iu X.if \\n(TM .ls 1 X.. X. \" SH - section header X.de SH X.ti \\n(.iu X.RT X.if \\n(1T .sp X.RT X.ne 3.1 X.ft B X.. X. \" $1 = C: As Chapter Heading; TOC Entry X. \" UH - UnNumbered $1 = M: As Chapter Heading; no TOC entry X. \" Headings $1 = H: Centered Heading; no TOC entry X. \" $1 = HC: Centered Heading; TOC Entry X. \" $1 = S: Left Adjusted Heading; no TOC entry X. \" $1 = SC: Left Adjusted Heading; TOC Entry X. \" $1 = CONTENTS: Setup for Table of Contents X. \" $1 = INDEX: Setup for Index X. \" $1 = TABLES: Setup for List of Tables X. \" $1 = FIGURES: Setup for List of Figures X.de UH X.SH X.if '\\$1'C' \{\ X.ne 1.0i+2v X.ad c X.ps 18 X.vs 24 \\& X.sp 0.5i \\$2 X.sp 0.5i X.ps X.vs X.ad b X.R \} X.if '\\$1'M' \{\ X.ne 1.0i+2v X.ad c X.ps 18 X.vs 24 \\& X.sp 0.5i \\$2 X.sp 0.5i X.ps X.vs X.ad b X.R \} X.if '\\$1'H' \{\ X.ne 0.7i+2v X.ad c X.if \\n(NS=2 .ft B X.if \\n(NS=2 .ps 14p X.if \\n(NS=2 .vs 18p \\& X.sp 0.25i \\$2 X.sp 0.1i X.ad b X.R \} X.if '\\$1'S' \{\ X.ne 0.2i+2v X.if \\n(NS=3 .ft I X.if \\n(NS=3 .ps 12p X.if \\n(NS=3 .vs 15p \\& X.sp 0.1i \\$2 X.sp 0.1i X.R \} X.if '\\$1'HC' \{\ X.ne 0.7i+2v X.ad c X.if \\n(NS=2 .ft B X.if \\n(NS=2 .ps 14p X.if \\n(NS=2 .vs 18p \\& X.sp 0.25i \\$2 X.sp 0.1i X.ad b X.R \} X.if '\\$1'SC' \{\ X.ne 0.2i+2v X.if \\n(NS=3 .ft I X.if \\n(NS=3 .ps 12p X.if \\n(NS=3 .vs 15p \\& X.sp 0.1i \\$2 X.sp 0.1i X.R \} X.if '\\$1'C' .if \\n(IK \!.tm .CE U "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'C' .if !\\n(IK .tm .CE U "\\$2" \\n(PN \\n(dT \\n(H1 X.if '\\$1'HC' .if \\n(IK \!.tm .CE UH "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'HC' .if !\\n(IK .tm .CE UH "\\$2" \\n(PN \\n(dT \\n(H1 X.if '\\$1'SC' .if \\n(IK \!.tm .CE UH "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'SC' .if !\\n(IK .tm .CE UH "\\$2" \\n(PN \\n(dT \\n(H1 X.if '\\$1'CONTENTS' .nr cF 1 X.if '\\$1'TABLES' .nr cF 1 X.if '\\$1'FIGURES' .nr cF 1 X.if '\\$1'INDEX' .nr cF 1 X.if \\n(cF \{\ X.LP X.EH '''' X.OH '''' X.EF ''\- \\\\\\\\n(PN \-'' X.OF ''\- \\\\\\\\n(PN \-'' X.if \\nP .pn \\nP+1 X.if \\nP .nr PN \\nP X.nf X.if '\\$1'CONTENTS' .ds hD Contents X.if '\\$1'TABLES' .ds hD Tables X.if '\\$1'FIGURES' .ds hD Figures X.if '\\$1'INDEX' .ds hD Index X.ps 11 X.nr PS 11 X.vs 14 X.nr VS 14 X.ne 1.0i+2v \\& X.sp 0.5i X.ce X.ps 18 X.vs 24 X.ft B \\*(hD X.sp 0.5i X.R X.ps 11 X.nr PS 11 X.vs 14 X.nr VS 14 X.af PN i X.if !'\\$1'INDEX' \{\ X.ll -0.5i X.in +0.5i \} X.if '\\$1'INDEX' \{\ X.ps 10 X.nr PS 10 X.vs 12 X.nr VS 12 X.2C\}\} X.. X. \" SE - Make special entry in the Contents File X.de SE X.if \\n(IK \!.tm SE \\$1\t\\$2\t\\$3\t\\$4\t\\$5\t\\$6\t\\$7\t\\$8\t\\$9\t\\\\n(PN\t\\n(dT\t\\n(H1 X.if !\\n(IK .tm SE \\$1\t\\$2\t\\$3\t\\$4\t\\$5\t\\$6\t\\$7\t\\$8\t\\$9\t\\n(PN\t\\n(dT\t\\n(H1 X.. X. \" H - Header - $1=level, $2=text X. \" $1: [1-5]=levels, C=chapter, A=appendix, PA=paperappendix X.de H X.ti \\n(.iu X.RT X.if \\n(1T .sp X.RT X.ne 3.1 X.ft B X.nr NS \\$1 X.if '\\$1'C' .nr NS 1 X.if '\\$1'C' .nr dT 1 X.if '\\$1'A' .nr NS 1 X.if '\\$1'A' .nr dT 1 X.if '\\$1'PA' .nr NS 1 X.if \\n(NS=1 .if !'\\$1'1' .if !'\\$1'PA'\{\ X.if \\nC .nr H1 \\nC-1 X.nr C 0 X.nr T1 0 X.nr F1 0 X.bp 1 \} X.if '\\$1'A' .if !\\n(aP \{\ X.nr aP 1 X.nr H1 0 X.af H1 A \} X.if '\\$1'PA' .if !\\n(aP \{\ X.nr aP 1 X.nr H1 0 X.af H1 A \} X.af PN 1 X.nr H\\n(NS +1 X.if !\\n(NS-4 .nr H5 0 X.if !\\n(NS-3 .nr H4 0 X.if !\\n(NS-2 .nr H3 0 X.if !\\n(NS-1 .nr H2 0 X.if \\n(NS=1 .ds MT \\$2 X.if \\n(NS=1 .if !'\\$1'1' .if !'\\$1'PA'\{\ X.ad c X.ps 18 X.vs 24 \\& X.sp 0.5i X.if '\\$1'C' .ds hS Chapter \\n(H1 X.if '\\$1'A' .ds hS Appendix \\n(H1 \\*(hS X.sp \\$2 X.sp 0.5i X.ps X.vs X.ad b \} X.if \\n(NS>=1 .if !'\\$1'C' .if !'\\$1'A' .if !'\\$1'PA'\{\ X.sp 10p X.ne 33p+20p X.ds SN \\n(H1. X.if \\n(NS>1 .as SN \\n(H2. X.if \\n(NS>2 .as SN \\n(H3. X.if \\n(NS>3 .as SN \\n(H4. X.if \\n(NS>4 .as SN \\n(H5. X.if \\n(NS=1 .ft B X.if \\n(NS=1 .ps 16p X.if \\n(NS=1 .vs 18p X.if \\n(NS=2 .ft B X.if \\n(NS=2 .ps 14p X.if \\n(NS=2 .vs 18p X.if \\n(NS=3 .ft I X.if \\n(NS=3 .ps 12p X.if \\n(NS=3 .vs 15p X.if \\n(NS=4 .ft I X.if \\n(NS=4 .ps 11p X.if \\n(NS=4 .vs 15p X.if \\n(NS=5 .ft R X.if \\n(NS=5 .ps \\n(PSp X.if \\n(NS=5 .vs \\n(VSp X.in +\\w'\\*(SN\\ \\ 'u X.ta \\w'\\*(SN\\ \\ 'u X.ti -\\w'\\*(SN\\ \\ 'u \\*(SN\\ \\ \t\c \&\\$2 X.in X.ps X.vs X.sp 7p \} X.if '\\$1'PA'\{\ X.sp 13p X.ne 33p+20p X.ft B X.ps 16p X.vs 18p X.in +\\w'\\*(SN\\ \\ 'u X.ta \\w'\\*(SN\\ \\ 'u X.ti -\\w'\\*(SN\\ \\ 'u X.ds SN Appendix \\n(H1. X.ti -\\w'\\*(SN\\ \\ 'u \\*(SN\\ \\ \t\c \&\\$2 X.in X.ps X.vs X.sp 7p \} X.R X.if '\\$1'C' .if \\n(IK \!.tm .CE C "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'C' .if !\\n(IK .tm .CE C "\\$2" \\n(PN \\n(dT \\n(H1 X.if '\\$1'A' .if \\n(IK \!.tm .CE A "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'A' .if !\\n(IK .tm .CE A "\\$2" \\n(PN \\n(dT \\n(H1 X.if '\\$1'1' .if \\n(IK \!.tm .CE N "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'1' .if !\\n(IK .tm .CE N "\\$2" \\n(PN \\n(dT \\n(H1 X.if '\\$1'PA' .if \\n(IK \!.tm .CE N "\\$2" \\\\n(PN \\n(dT \\n(H1 X.if '\\$1'PA' .if !\\n(IK .tm .CE N "\\$2" \\n(PN \\n(dT \\n(H1 X.if \\n(NS>1 .if \\n(IK \!.tm .CE N "\\$2" \\\\n(PN \\n(dT \\n(H1 \\n(H2 \\n(H3 \\n(H4 \\n(H5 X.if \\n(NS>1 .if !\\n(IK .tm .CE N "\\$2" \\n(PN \\n(dT \\n(H1 \\n(H2 \\n(H3 \\n(H4 \\n(H5 X.. X. \" TN - Table Caption X.de TN X.nr T1 +1 X.sp X.if \\n(dT .ds tS Table \\n(H1-\\n(T1: \\$1 X.if !\\n(dT .ds tS Table \\n(T1: \\$1 X.ce \\*(tS X.sp X.ie \\n(IK \!.tm .CE T "\\$1" \\\\n(PN \\n(dT \\n(H1 \\n(T1 X.el .tm .CE T "\\$1" \\n(PN \\n(dT \\n(H1 \\n(T1 X.. X. \" FN - Figure Caption X.de FN X.nr F1 +1 X.sp X.if \\n(dT .ds tS Figure \\n(H1-\\n(F1: \\$1 X.if !\\n(dT .ds tS Figure \\n(F1: \\$1 X.ce \\*(tS X.sp X.ie \\n(IK \!.tm .CE F "\\$1" \\\\n(PN \\n(dT \\n(H1 \\n(F1 X.el .tm .CE F "\\$1" \\n(PN \\n(dT \\n(H1 \\n(F1 X.. X. \" CE - table of contents entry X. \" $1 : header type; $2 : text; $3 : page number; $4 : document type X. \" $5 : chapter number; $6, 7, 8 : additional numbers X.de CE X.fi X.na X.nh X.rm lS X.ds rS \\$3 X.if !'\\$4'0' .ds rS \\$5-\\$3 X.if '\\$1'N' .if '\\$6\\$7\\$8\\$9'' .ds rS \fB\\$3\fP X.if '\\$1'C' .if !'\\$5'' .if !'\\$5'0' .ds rS \fB\\$5-\\$3\fP X.if '\\$1'A' .if !'\\$5'' .if !'\\$5'0' .ds rS \fB\\$5-\\$3\fP X.if '\\$1'T' .if '\\$4'0' .ds lS Table \\$6\ \ X.if '\\$1'F' .if '\\$4'0' .ds lS Figure \\$6\ \ X.if '\\$1'T' .if '\\$4'1' .ds lS Table \\$5-\\$6\ \ X.if '\\$1'F' .if '\\$4'1' .ds lS Figure \\$5-\\$6\ \ X.if '\\$1'A' .ds lS \fBAppendix \\$5\fP\ \ X.if '\\$1'C' .ds lS \fBChapter \\$5\fP\ \ X.if '\\$1'N' .ds lS \\$5.\ \ X.if '\\$1'N' .if '\\$6\\$7\\$8\\$9'' .ds lS \fB\\$5.\fP\ \ X.if '\\$1'N' .if !'\\$6'' .if !'\\$6'0' .ds lS " \\$5.\\$6.\ \ X.if '\\$1'N' .if !'\\$7'' .if !'\\$7'0' .ds lS " \\$5.\\$6.\\$7.\ \ X.if '\\$1'N' .if !'\\$8'' .if !'\\$8'0' .ds lS " \\$5.\\$6.\\$7.\\$8.\ \ X.if '\\$1'N' .if !'\\$9'' .if !'\\$9'0' .ds lS " \\$5.\\$6.\\$7.\\$8.\\$9\ \ X.if '\\$1'N' .if '\\$6\\$7\\$8\\$9'' .ne 3 X.if '\\$1'U' .ne 3 X.if '\\$1'A' .ne 3 X.if '\\$1'C' .ne 3 X.if '\\$1'N' .if '\\$6\\$7\\$8\\$9'' .sp X.if '\\$1'U' .sp X.if '\\$1'A' .sp X.if '\\$1'C' .sp X.\" Reduce line length, save section # width, increase indent: X.nr $l \\n(.l \"save line length X.ll -8n \"try 8 ens for now X.nr wN \\w\\*(lSu \"wN = width of section number X.in +\\n(wNu X.\" Output number (lS) and text ($2) with short line length X.ti -\\n(wNu \"don't indent first line X.vs \\n(.sp+2p \"normalize spacing X.\" We need at least two lines for this 'moving-backward' hack to work: X.ne 2v \&\\*(lS\\$2 X.\"Restore line length and indent X.ll X.in X.\" Go back to previous line, output leader & page number: X.nf \"leaders only work right in no-fill mode! X.\" If last line broke, we have to correct for indent: X.if (\\w\\*(lS\\$2u)<=(\\n(.lu-\\n(.iu-8n) .nr wN 0 X.ll -\\n(wNu X.ti +\\n(wNu X.ta \\n(.lu-\\n(.iu-5nR \\n(.lu-\\n(.iuR X.sp -1v X.vs \"(now can restore original vertical spacing) \\h'|\\n(.nu+.5n'\s-3\a\s+3\t\\*(rS X.\"Restore line length (again): X.ll X.. X. \" NH - numbered header X.de NH X.SH X.nr NS \\$1 X.if !\\n(.$ .nr NS 1 X.if !\\n(NS .nr NS 1 X.nr H\\n(NS +1 X.if !\\n(NS-4 .nr H5 0 X.if !\\n(NS-3 .nr H4 0 X.if !\\n(NS-2 .nr H3 0 X.if !\\n(NS-1 .nr H2 0 X.if !\\$1 .if \\n(.$ .nr H1 1 X.if \\$1S \{\ X. nr NS \\n(.$-1 X. nr H1 \\$2 X. nr H2 \\$3 X. nr H3 \\$4 X. nr H4 \\$5 X. nr H5 \\$6 X.\} X.ds SN \\n(H1. X.if \\n(NS-1 .as SN \\n(H2. X.if \\n(NS-2 .as SN \\n(H3. X.if \\n(NS-3 .as SN \\n(H4. X.if \\n(NS-4 .as SN \\n(H5. \\*(SN X.. X. \" LS - listing start X.de LS X.ie \\$1no .ID \\$2 X.el .DS I \\$1 X.nr PQ \\n(.f X.ft L X.ps -\\n(dP X.vs -\\n(dV X.nr @ \\w'x'u*8 X.if \\n(.$ .nr @ \\w'x'u*\\$2 X.if \\n(.$ .if \\$1no .nr @ \\w'x'u*\\$3 X.ta \\n@u +\\n@u +\\n@u +\\n@u +\\n@u +\\n@u +\\n@u +\\n@u +\\n@u +\\n@u X.. X. \" LE - listing end X.de LE X.ft \\n(PQ X.ps \\n(PS X.if \\n(VS>=40 .vs \\n(VSu X.if \\n(VS<=39 .vs \\n(VSp X.DE X.. X. \" DS - display with keep (L=left I=indent C=center B=block) X.de DS X.KS X.\\$1D \\$2 \\$1 X.ft 1 X.ps \\n(PS X.if \\n(VS>=40 .vs \\n(VSu X.if \\n(VS<=39 .vs \\n(VSp X.. X.de D X.ID \\$1 X.. X. \" ID - indented display with no keep X.de ID X.XD X.if t .in +.5i X.if n .in +8 X.if \\n(.$ .if !\\$1I .if !\\$1 \{\ X. in \\n(OIu X. in +\\$1n X.\} X.. X. \" LD - left display with no keep X.de LD X.XD X.. X. \" CD - centered display with no keep X.de CD X.XD X.ce 999 X.. X. \" XD - real display macro X.de XD X.nf X.nr OI \\n(.i X.sp \\n(DDu X.if \\n(TM .ls 1 X.. X. \" DE - end display of any kind X.de DE X.ce 0 X.if \\n(BD .DF X.nr BD 0 X.in \\n(OIu X.KE X.if \\n(TM .ls 2 X.sp \\n(DDu X.fi X.. X. \" BD - block display: center entire block X.de BD X.XD X.nr BD 1 X.nf X.in \\n(OIu X.di DD X.. X. \" DF - finish block display X.de DF X.di X.if \\n(dl>\\n(BD .nr BD \\n(dl X.if \\n(BD<\\n(.l .in (\\n(.lu-\\n(BDu)/2u X.nr EI \\n(.l-\\n(.i X.ta \\n(EIuR X.DD X.in \\n(OIu X.. X. \" KS - begin regular keep X.de KS X.nr KN \\n(.u X.if !\\n(IK .if !\\n(IF .KQ X.nr IK +1 X.. X. \" KQ - real keep processor X.de KQ X.br X.nr KI \\n(.i X.ev 2 X.TA X.br X.in \\n(KIu X.ps \\n(PS X.if \\n(VS>=40 .vs \\n(VSu X.if \\n(VS<=39 .vs \\n(VSp X.ll \\n(LLu X.lt \\n(LTu X.if \\n(NX>1 .ll \\n(CWu X.if \\n(NX>1 .lt \\n(CWu X.di KK X.nr TB 0 X.. X. \" KF - begin floating keep X.de KF X.nr KN \\n(.u X.if !\\n(IK .FQ X.nr IK +1 X.. X. \" FQ - real floating keep processor X.de FQ X.nr KI \\n(.i X.ev 2 X.TA X.br X.in \\n(KIu X.ps \\n(PS X.if \\n(VS>=40 .vs \\n(VSu X.if \\n(VS<=39 .vs \\n(VSp X.ll \\n(LLu X.lt \\n(LTu X.if \\n(NX>1 .ll \\n(CWu X.if \\n(NX>1 .lt \\n(CWu X.di KK X.nr TB 1 X.. X. \" KE - end keep X.de KE X.if \\n(IK .if !\\n(IK-1 .if !\\n(IF .RQ X.if \\n(IK .nr IK -1 X.. X. \" RQ - real keep release X.de RQ X.br X.di X.nr NF 0 X.if \\n(dn-\\n(.t .nr NF 1 X.if \\n(TC .nr NF 1 X.if \\n(NF .if !\\n(TB .sp 200 X.if !\\n(NF .if \\n(TB .nr TB 0 X.nf X.rs X.nr TC 5 X.in 0 X.ls 1 X.if !\\n(TB \{\ X. ev X. br X. ev 2 X. KK X.\} X.ls X.ce 0 X.if !\\n(TB .rm KK X.if \\n(TB .da KJ X.if \\n(TB \!.KD \\n(dn X.if \\n(TB .KK X.if \\n(TB .di X.nr TC \\n(TB X.if \\n(KN .fi X.in X.ev X.. X. \" start picture X.de PS X. \" $1 is height, $2 is width in units X.if t .sp .3 X.in (\\n(.lu-\\$2u)/2u X.ne \\$1u X.. X. \" end of picture X.de PE X.in X.if t .sp .6 X.. X. \" KD - keep redivert X.de KD X.nr KM 0 X.if \\n(.zKJ .nr KM 1 X.if \\n(KM \!.KD \\$1 X.if !\\n(KM .if \\n(.t<\\$1 .di KJ X.. X. \" EM - end macro (process leftover keep) X.de EM X.br X.if !\\n(TB .if t .wh -1p CM X.if \\n(TB \{\ \&\c ' bp X. NP X. ch CM 160 X.\} X.. X.de XK X.nr TD 1 X.nf X.ls 1 X.in 0 X.rn KJ KL X.KL X.rm KL X.if \\n(.zKJ .di X.nr TB 0 X.if \\n(.zKJ .nr TB 1 X.br X.in X.ls X.fi X.nr TD 0 X.. X. \" NP - new page X.de NP X.if !\\n(LT .nr LT \\n(LLu X.if \\n(FM+\\n(HM>=\\n(.p \{\ X. tm HM + FM longer than page X. ab X.\} X.\".if t .CM X.if !\\n(HM .nr HM 1i X.po \\n(POu X.nr PF \\n(.f X.nr PX \\n(.s X.ft 1 X.ps \\n(PS 'sp \\n(HMu/2u X.PT 'sp |\\n(HMu X.HD \"undefined X.ps \\n(PX X.ft \\n(PF X.nr XX 0 1 X.nr YY 0-\\n(FMu X.ch FO 16i X.ch FX 17i X.ch FO -\\n(FMu X.ch FX \\n(.pu-\\n(FMu X.if \\n(MF .FV X.nr MF 0 X.mk X.os X.ev 1 X.if !\\n(TD .if \\n(TC<5 .XK X.nr TC 0 X.ev X.nr TQ \\n(.i X.nr TK \\n(.u X.if \\n(IT \{\ X. in 0 X. nf X. TT X. in \\n(TQu X. if \\n(TK .fi X.\} X.ns X.mk #T X.if t .if \\n(.o+\\n(LL>7.54i .tm PO + LL wider than 7.54i X.. X. \" PT - page titles X.de PT X.lt \\n(LTu X.pc % X.nr PN \\n% X.nr PT \\n% X.if \\n(P1 .nr PT 2 X.if \\n(PT>1 .if !\\n(EH .if !\\n(OH .tl \\*(LH\\*(CH\\*(RH X.if \\n(PT>1 .if \\n(OH .if o .tl \\*(O1 X.if \\n(PT>1 .if \\n(EH .if e .tl \\*(E2 X.lt \\n(.lu X.. X. \" OH - odd page header X.de OH X.nr OH 1 X.if !\\n(.$ .nr OH 0 X.ds O1 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 X.. X. \" EH - even page header X.de EH X.nr EH 1 X.if !\\n(.$ .nr EH 0 X.ds E2 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 X.. X. \" P1 - PT on 1st page X.de P1 X.nr P1 1 X.. X. \" FO - footer X.de FO X.rn FO FZ X.if \\n(IT .nr T. 1 X.if \\n(IT .if !\\n(FC .T# 1 X.if \\n(IT .br X.nr FC +1 X.if \\n(NX<2 .nr WF 0 X.nr dn 0 X.if \\n(FC<=1 .if \\n(XX .XF X.rn FZ FO X.nr MF 0 X.if \\n(dn .nr MF 1 X.if !\\n(WF .nr YY 0-\\n(FMu X.if !\\n(WF .ch FO \\n(YYu X.if !\\n(dn .nr WF 0 X.if \\n(FC<=1 .if !\\n(XX \{\ X. if \\n(NX>1 .RC X. if \\n(NX<2 'bp X.\} X.nr FC -1 X.if \\n(ML .ne \\n(MLu X.. X. \" BT - bottom title X.de BT X.nr PF \\n(.f X.nr PX \\n(.s X.ft 1 X.ps \\n(PS X.lt \\n(LTu X.po \\n(POu X.if \\n(TM .if \\n(CT \{\ X. tl ''\\n(PN'' X. nr CT 0 X.\} X.if \\n% .if !\\n(EF .if !\\n(OF .tl \\*(LF\\*(CF\\*(RF X.if \\n% .if \\n(OF .if o .tl \\*(O3 X.if \\n% .if \\n(EF .if e .tl \\*(E4 X.ft \\n(PF X.ps \\n(PX X.. X. \" OF - odd page footer X.de OF X.nr OF 1 X.if !\\n(.$ .nr OF 0 X.ds O3 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 X.. X. \" EF - even page footer X.de EF X.nr EF 1 X.if !\\n(.$ .nr EF 0 X.ds E4 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 X.. X. \" 2C - double column X.de 2C X.MC X.. X. \" 1C - single column X.de 1C X.MC \\n(LLu X.hy 14 X.. X. \" MC - multiple columns, arg is col width X.de MC X.nr L1 \\n(LL*7/15 X.if \\n(.$ .nr L1 \\$1n X.nr NQ \\n(LL/\\n(L1 X.if \\n(NQ<1 .nr NQ 1 X.if \\n(NQ>2 .if (\\n(LL%\\n(L1)=0 .nr NQ -1 X.if !\\n(1T \{\ X. BG X. if n .sp 4 X. if t .sp 2 X.\} X.if !\\n(NX .nr NX 1 X.if !\\n(NX=\\n(NQ \{\ X. RT X. if \\n(NX>1 .bp X. mk X. nr NC 1 X. po \\n(POu X.\} X.if \\n(NQ>1 .hy 12 X.nr NX \\n(NQ X.nr CW \\n(L1 X.ll \\n(CWu X.nr FL \\n(CWu*11u/12u X.if \\n(NX>1 .nr GW (\\n(LL-(\\n(NX*\\n(CW))/(\\n(NX-1) X.nr RO \\n(CW+\\n(GW X.ns X.. X.de RC X.if \\n(NC>=\\n(NX .C2 X.if \\n(NC<\\n(NX .C1 X.nr NC \\n(ND X.if \\n(iL>0 .if !"\\*(iC"" \{\ X.if \\n(.i>0 .ti -\\n(.i \\*(iC X.ti -4 \} X.. X.de C1 X.rt X.po +\\n(ROu X.nr ND \\n(NC+1 X.nr XX 0 1 X.if \\n(MF .FV X.ch FX \\n(.pu-\\n(FMu X.ev 1 X.if \\n(TB .XK X.nr TC 0 X.ev X.nr TQ \\n(.i X.if \\n(IT .in 0 X.if \\n(IT .TT X.if \\n(IT .in \\n(TQu X.mk #T X.ns X.. X.de C2 X.po \\n(POu 'bp X.nr ND 1 X.. X. \" RS - right shift X.de RS X.nr IS \\n(IP X.RT X.nr IP \\n(IS X.if \\n(IP .in +\\n(I\\n(IRu X.nr IR +1 X.nr I\\n(IR \\n(PIu X.in +\\n(I\\n(IRu X.. X. \" RE - retreat left X.de RE X.nr IS \\n(IP X.RT X.nr IP \\n(IS X.if \\n(IR .nr IR -1 X.if \\n(IP<=0 .in -\\n(I\\n(IRu X.. X. \" I - italic font X.de I X.nr PQ \\n(.f X.if t .ft 2 X.ie \\$1 .if n .ul 999 X.el .if n .ul 1 X.if t .if !\\$1 \&\f\\n(PQ\\$3\fI\\$1\|\f\\n(PQ\\$2 X.if n .if \\n(.$=1 \&\\$1 X.if n .if \\n(.$>2 \&\\$3\c X.if n .if \\n(.$>1 \&\\$1\c X.if n .if \\n(.$>1 \&\\$2 X.. X. \" B - bold font X.de B X.nr PQ \\n(.f X.if t .ft 3 X.ie \\$1 .if n .ul 999 X.el .if n .ul 1 X.if t .if !\\$1 \&\f\\n(PQ\\$3\fB\\$1\f\\n(PQ\\$2 X.if n .if \\n(.$=1 \&\\$1 X.if n .if \\n(.$>2 \&\\$3\c X.if n .if \\n(.$>1 \&\\$1\c X.if n .if \\n(.$>1 \&\\$2 X.. X. \" R - Roman font X.de R X.if n .ul 0 X.ft 1 X.. X. \" L - listing font X.de L X.if n .ul \%\&\\$3\fL\\$1\f1\&\\$2 X.. X. \" LB - bold listing font X.de LB X.if n .ul \%\&\\$3\f(LB\\$1\f1\&\\$2 X.. X. \" UL - underline in troff X.de UL X.if t \\$1\l'|0\(ul'\\$2 X.if n .I \\$1 \\$2 X.. X. \" SM - make text small X.de SM X.ps -2 X.if !"\\$1"" \\$3\&\\$1\\$2 X.if !"\\$1"" .ps +2 X.. X. \" LG - larger X.de LG X.ps +2 X.if !"\\$1"" \\$3\&\\$1\\$2 X.if !"\\$1"" .ps -2 X.. X. \" NL - normal X.de NL X.ps \\n(PS X.. X. \" combinations of Roman, italic, bold X.de RI \&\fR\\$1\fI\\$2\^\fR\\$3\fI\\$4\^\fR\\$5\fI\\$6\^\fR\\$7\fI\\$8\^\fR\\$9 X.. X.de RB \&\fR\\$1\fB\\$2\fR\\$3\fB\\$4\fR\\$5\fB\\$6\fR\\$7\fB\\$8\fR\\$9 X.. X.de IR \&\fI\\$1\^\fR\\$2\fI\\$3\^\fR\\$4\fI\\$5\^\fR\\$6\fI\\$7\^\fR\\$8\fI\\$9\^\fR X.. X.de IB \&\fI\\$1\^\fB\\$2\fI\\$3\^\fB\\$4\fI\\$5\^\fB\\$6\fI\\$7\^\fB\\$8\fI\\$9\^\fR X.. X.de BR \&\fB\\$1\fR\\$2\fB\\$3\fR\\$4\fB\\$5\fR\\$6\fB\\$7\fR\\$8\fB\\$9\fR X.. X.de BI \&\fB\\$1\fI\\$2\^\fB\\$3\fI\\$4\^\fB\\$5\fI\\$6\^\fB\\$7\fI\\$8\^\fB\\$9\fR X.. X. \" \** - numbered footnote X.ds * \\*([.\\n+*\\*(.] X. \" FJ - replaces FS after cover X.de FJ 'ce 0 X.di X.ev 1 X.ll \\n(FLu X.da FF X.br X.if \\n(IF .tm Nested footnote X.nr IF 1 X.if !\\n+(XX-1 .FA X.if !\\n(MF .if !\\n(.$ .if \\n* .FP \\n* X.if !\\n(MF .if \\n(.$ .FP \\$1 no X.. X. \" FK - replaces FE after cover X.de FK X.br X.in 0 X.nr IF 0 X.di X.ev X.if !\\n(XX-1 .nr dn +\\n(.v X.nr YY -\\n(dn X.if !\\n(NX .nr WF 1 X.if \\n(dl>\\n(CW .nr WF 1 X.if (\\n(nl+\\n(.v)<=(\\n(.p+\\n(YY) .ch FO \\n(YYu X.if (\\n(nl+\\n(.v)>(\\n(.p+\\n(YY) \{\ X. if \\n(nl>(\\n(HM+1.5v) .ch FO \\n(nlu+\\n(.vu X. if \\n(nl+\\n(FM+1v>\\n(.p .ch FX \\n(.pu-\\n(FMu+2v X. if \\n(nl<=(\\n(HM+1.5v) .ch FO \\n(HMu+(4u*\\n(.vu) X.\} X.. X. \" FS - begin footnote on cover X.de FS X.ev 1 X.br X.ll \\n(FLu X.da FG X.if !\\n(.$ .if \\n* .FP \\n* X.if \\n(.$ .FP \\$1 no X.. X. \" FE - end footnote on cover X.de FE X.br X.di X.nr FP \\n(dn X.if !\\n(1T .nr KG 1 X.ev X.. X. \" FA - print line before footnotes X.de FA X.in 0 X.if n _________________________ X.if t \l'1i' X.br X.. X. \" FP - footnote paragraph X.de FP X.sp \\n(PDu/2u X.if \\n(FF<2 .ti \\n(FIu X.if \\n(FF=3 \{\ X. in \\n(FIu*2u X. ta \\n(FIu*2u X. ti 0 X.\} X.if !\\n(FF \{\ X. ie "\\$2"no" \\$1\0\c X. el \\*([.\\$1\\*(.]\0\c X.\} X.if \\n(FF .if \\n(FF<3 \{\ X. ie "\\$2"no" \\$1\0\c X. el \\$1.\0\c X.\} X.if \\n(FF=3 \{\ X. ie "\\$2"no" \\$1\t\c X. el \\$1.\t\c X.\} X.. X. \" FV - get leftover footnote from previous page X.de FV X.FS X.nf X.ls 1 X.FY X.ls X.fi X.FE X.. X. \" FX - divert leftover footnote for next page X.de FX X.if \\n(XX .di FY X.if \\n(XX .ns X.. X. \" XF - actually print footnote X.de XF X.if \\n(nlu+1v>(\\n(.pu-\\n(FMu) .ch FX \\n(nlu+1.9v X.ev 1 X.nf X.ls 1 X.FF X.rm FF X.nr XX 0 1 X.br X.ls X.di X.fi X.ev X.. X. \" TS - source file for tbl X.de TS X.rn TS @T X.so \*(//ms.tbl X.TS \\$1 \\$2 X.rm @T X.. X. \" EQ - source file for eqn X.de EQ X.rn EQ @T X.so \*(//ms.eqn X.EQ \\$1 \\$2 X.rm @T X.. X. \" ]- - source file for refer X.de ]- X.rn ]- @T X.so \*(//ms.ref X.]- X.rm @T X.. X. \" [< - for refer -s or -e X.de ]< X.rn ]< @T X.so \*(//ms.ref X.]< X.rm @T X.. X.if \n(.V>19 .ds [. \f1[ X.if \n(.V>19 .ds .] ]\fP X.if \n(.V<20 .ds [. \f1\s-2\v'-.4m' X.if \n(.V<20 .ds .] \v'.4m'\s+2\fP X.ds <. . X.ds <, , X.if n .ds Q \&" X.if n .ds U \&" X.if n .ds - \%-- X.if t .ds Q `` X.if t .ds U '' X.if t .ds - \(em X.ds ' \h'\w'e'u/5'\z\'\h'-\w'e'u/5' X.ds ` \h'\w'e'u/5'\z\`\h'-\w'e'u/5' X.ds ^ \h'\w'o'u/10'\z^\h'-\w'e'u/10' X.ds , \h'\w'c'u/5'\z,\h'-\w'e'u/5' X.ds : \h'\w'u'u/5'\z"\h'-\w'e'u/5' X.ds ~ \h'\w'n'u/10'\z~\h'-\w'e'u/10' X.ds C \h'\w'c'u/5'\v'-.6m'\s-4\zv\s+4\v'.6m'\h'-\w'c'u/5' X. \" AM - better accent marks X.de AM X.so \*(//ms.acc X.. X. \" TM - thesis mode X.de TM X.so \*(//ms.ths X.. X. \" BX - word in a box X.de BX X.if t \(br\|\\$1\|\(br\l'|0\(rn'\l'|0\(ul' X.if n \(br\\kA\|\\$1\|\\kB\(br\v'-1v'\h'|\\nBu'\l'|\\nAu'\v'1v'\l'|\\nAu' X.. X. \" B1 - source file for boxed text X.de B1 X.rn B1 @T X.so \*(//ms.tbl X.B1 \\$1 X.rm @T X.. X. \" XS - table of contents X.de XS X.rn XS @T X.so \*(//ms.toc X.XS \\$1 \\$2 X.rm @T X.. X. \" IX - Make an Index Entry X.de IX X.if \\nI .if \\n(dT .if \\n(IK \!.tm .IE\t\\$1\t\\$2\t\\$3\t\\n(H1-\\\\n(PN\t X.if \\nI .if \\n(dT .if !\\n(IK .tm .IE\t\\$1\t\\$2\t\\$3\t\\n(H1-\\n(PN\t X.if \\nI .if !\\n(dT .if \\n(IK \!.tm .IE\t\\$1\t\\$2\t\\$3\t\\\\n(PN\t X.if \\nI .if !\\n(dT .if !\\n(IK .tm .IE\t\\$1\t\\$2\t\\$3\t\\n(PN\t X.if !\\nI .if \\n(dT .if \\n(IK \!.tm .IE\tENTRY\t\\$1\t\\$2\t\\$3\t\\$4\t\\$5\t\\$6\t\\n(H1-\\\\n(PN X.if !\\nI .if \\n(dT .if !\\n(IK .tm .IE\tENTRY\t\\$1\t\\$2\t\\$3\t\\$4\t\\$5\t\\$6\t\\n(H1-\\n(PN X.if !\\nI .if !\\n(dT .if \\n(IK \!.tm .IE\tENTRY\t\\$1\t\\$2\t\\$3\t\\$4\t\\$5\t\\$6\t\\\\n(PN X.if !\\nI .if !\\n(dT .if !\\n(IK .tm .IE\tENTRY\t\\$1\t\\$2\t\\$3\t\\$4\t\\$5\t\\$6\t\\n(PN X.. X. \" IH - Make an Index Header X.de IH X.if \\n(dT .if \\n(IK \!.tm .IE\tHEADER\t\\$1\t\\$2\t\\$3\t\\$4\t\\n(H1-\\\\n(PN X.if \\n(dT .if !\\n(IK .tm .IE\tHEADER\t\\$1\t\\$2\t\\$3\t\\$4\t\\n(H1-\\n(PN X.if !\\n(dT .if \\n(IK \!.tm .IE\tHEADER\t\\$1\t\\$2\t\\$3\t\\$4\t\\\\n(PN X.if !\\n(dT .if !\\n(IK .tm .IE\tHEADER\t\\$1\t\\$2\t\\$3\t\\$4\t\\n(PN X.. X. \" UX - UNIX macro X.de UX X.ie \\n(UX \s-1UNIX\s0\\$1 X.el \{\ \s-1UNIX\s0\\$1\(dg X.FS \(dg \s-1UNIX\s0 is a trademark of Bell Laboratories. X.FE X.nr UX 1 X.\} X.. X.\" X.\" Here is the SUN normal form macro, X.\" which tries to align for the cross grid X.\" X.de Sn X.ta 2i 3i 4i 5i 6i X.nr PS 10 X.nr VS 12 X.nr LL 5.8i X.nr PO +.75i X.ps 10 X.vs 12 X.ll 5.8i X.po +.75i X.tl ''' X.. X.\" X.\" Do a small type display X.\" X.de Ds X.DS X.ps 10 X.vs 12 X.. X.de De X.DE X.. X.\" X.\" These are my memo macros, invoked by using X.\" .MM and then specifying the appropriate pieces. X.\" Relies on the -ms or -msun macros. X.\" X.\" .MM -- initialize memo X.\" .TO -- Send it to X.\" .FR -- From X.\" .DA -- String for date X.\" .SU -- String for subject X.\" .CC -- Carbon Copies X.\" .DI -- Distribution List X.\" .EC -- End copy list X.\" X.de MM X.vs 10p X.sp 8v X.ll 6.0i X.ps 26 X.br X.in +5i X.ft 3 s\|\|u\|\|n X.br X.ps 12 X.ft 1 microsystems X.in -5i X.br X.sp X.ps 12 X.. X.de TO X.mk X.ps 9 To: X.ps 11 X.if t .ti +\w'Subject: 'u X.rt \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.. X.de DA X.if t .in +6i X.if t .in -\w'\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7'u X.if t .in -\w'Date: 'u X.if t .rt X.if n .sp Date: X.if t .br X.if t .rt X.if t .ti +\w'Date: 'u \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.br X.if t .in +w'\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7'u X.if t .in +w'Date: 'u X.if t .in -6i X.sp X.. X.de FR X.mk X.ps 9 From: X.if t .rt X.ps 11 X.if t .ti +\w'Subject: 'u \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.if t .rt X.sp X.. X.de SU X.mk X.ps 9 Subject: X.if t .rt X.ps 11 X.if t .ti +\w'Subject: 'u \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.if t .rt X.sp X.. X.de CC X.mk X.ps 9 CC: X.ps 11 X.in +\w'Subject: 'u X.if t .rt X.nf X.. X.de DI X.ps 9 Distribution X.br X.mk List: X.ps 11 X.in +\w'Subject: 'u X.rt X.nf X.. X.de EC X.sp X.in -\w'Subject: 'u X.fi X.. X.de pp X.sp X.. X.\" X.\" These are macros for making foils. X.\" .Fp invokes the foil package initialization stuff, X.\" .Fl gets you a foil, and X.\" .It gets an item X.\" .Tl gets a title for the foil X.\" .Ip gets a second paragraph in the bullet X.\" .Tp gets a text paragraph, not printed on foils X.\" .Te ends a text paragraph X.\" X.de Fp X.EF 'Copyright 1984 Sun Micro''Educational Material' X.OF 'Copyright 1984 Sun Micro''Educational Material' X.. X.de Fl X.bp 1 X.LP X.sp 2 X.ll 6.5i X.nr PS 18 X.nr VS 21 X.ps 18 X.vs 21 X.. X.de Tl X.ps \\n(PS+10 X.vs \\n(VS+11 X.ce 10 X.ft 3 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.ft 1 X.ce 0 X.br X.ps \\n(PS X.vs \\n(VS X.. X.de Sl X.ps \\n(PS+4 X.vs \\n(VS+5 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.br X.ps \\n(PS X.vs \\n(VS X.. X.de St X.rs X.ps \\n(PS+4 X.vs \\n(VS+5 \|\| X.sp -2 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.sp 2 X.br X.ps \\n(PS X.vs \\n(VS X.. X.de It X.sp 1 X.IP \(bu X.ps \\n(PS+6 X.vs \\n(VS+7 \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 X.sp 1 X.ps \\n(PS X.vs \\n(VS X.. X.de Ip X.sp 1 X.. X.de Tp X.ig Te X.. X.co X.if \n(mo-0 .ds MO January X.if \n(mo-1 .ds MO February X.if \n(mo-2 .ds MO March X.if \n(mo-3 .ds MO April X.if \n(mo-4 .ds MO May X.if \n(mo-5 .ds MO June X.if \n(mo-6 .ds MO July X.if \n(mo-7 .ds MO August X.if \n(mo-8 .ds MO September X.if \n(mo-9 .ds MO October X.if \n(mo-10 .ds MO November X.if \n(mo-11 .ds MO December X.ds DY \*(MO \n(dy, 19\n(yr X.nr * 0 1 X.IZ X.em EM X.rm IZ RA // !Funky!Stuff! exit