git: purgatorio

Download patch

ref: 70f57939ef437a822bfacde3a6e487633b6ba706
parent: 42d448ae565b8114797afce598ddc34b8ed97e7d
author: henesy <devnull@localhost>
date: Sat Nov 3 22:28:43 EDT 2018

init 2

--- /dev/null
+++ b/INSTALL
@@ -1,0 +1,86 @@
+Installing hosted Inferno from source
+
+Overview
+
+     Like the native kernels  emu relies on  several  auxil-
+iary libraries (the source of which it often shares with the
+native kernels).  Emu itself is built by the  mkfile in the
+emu subdirectory containing the platform-specific source for
+the host platform.  Each library has its own    mkfile;  the
+various  components  are  made  in  the  right order by the
+mkfile at the root of the Inferno tree.   The    mkfile  for
+each  platform  will also invoke  mk recursively to make the
+appropriate libraries for a given configuration.
+
+     The Unix emu variant generally is  covered  by  `POSIX'
+(with  common  extensions)  but  each Unix port has one file
+that   differs   considerably   for   each   port,    namely
+emu/platform/os.c, the differences corresponding to the dif-
+ferent ways  under  Unix  of  implementing  kernel-scheduled
+threads efficiently.
+
+     There  are  working  emu  versions   for   FreeBSD/386,
+Irix/mips,  Linux/386, NetBSD/386, MacOSX/386, MacOSX/power,
+Plan 9, Solaris/sparc, and Windows (NT,  2000  and  Explorer
+plug-in).   Each platform typically uses mechanisms specific
+to the host operating system to implement Inferno's internal
+thread/process  structure.   POSIX  threads  have often been
+found to be insufficient (poorly implemented) on some  plat-
+forms, and if so are avoided.  See  kproc in  emu/*/os.c.
+
+     Source is included for ports to HP/UX  (S800  architec-
+ture),  Solaris/386, and Unixware, in case someone wishes to
+take them up now, but we have not determined their fitness.
+
+     The Plan 9 hosted implementation is unusual in that  it
+supports several processor types:  386,  mips,  power (Power
+PC) and  sparc.  Furthermore, all versions of   emu  can  be
+built on any processor type, in the usual way for Plan 9.
+
+     Otherwise, as distributed,  emu for a platform can only
+be built when running on that platform.
+
+     One unusual variant makes the whole of Inferno a  plug-
+in  for Microsoft's Internet Explorer, giving the same envi-
+ronment for Inferno applications running in an HTML page  as
+is  provided by hosted or native Inferno.  That is, there is
+not a distinct `applet' environment with special programming
+interfaces.   The  source for the various plug-in components
+is found in  /tools/plugin and    /usr/internet  within  the
+Inferno  tree;  they  use the version of  emu defined by the
+configuration file  /emu/Nt/ie.
+
+Build steps
+
+     All the libraries and executables can  be  built  in  a
+tree containing only the source code.  To do that for a sup-
+ported variant of hosted Inferno, on Unix or Plan 9, do  the
+following in the root of the Inferno tree:
+
+1    Edit    mkconfig  to  reflect  your  host  environment,
+     specifically  ROOT  (which  must  be  an  absolute path
+     name), SYSHOST and OBJTYPE.  The comments in  the  file
+     should help you choose.
+
+2    Run  makemk.sh to rebuild the   mk  command,  which  is
+     used to build everything else.
+
+3    Set  PATH (or  path on Plan 9)  to  include  the    bin
+     directory for the platform, which will now contain the
+     mk binary just built.  On Unix, export  PATH.
+
+4    Then  mk nuke to remove any extraneous object files.
+
+5    Finally,    mk  install  to  create  and  install   the
+     libraries,    limbo  compiler,  emu for hosted Inferno,
+     and auxiliary commands.  The rules do that in an  order
+     that ensures that the commands or libraries needed by a
+     later stage are built and installed first.  (Note  that
+     a  plain   mk will not suffice, because it does not put
+     the results in the search path.)
+
+Doing something similar  on  Windows  or  Plan  9  currently
+requires  the  executable  for    mk  to be available in the
+search path, since there is no  equivalent  of    makemk.sh.
+Otherwise  the procedure is the same.  On Plan 9, of course,
+the host system's normal version of  mk should be adequate.
--- /dev/null
+++ b/README.md
@@ -1,0 +1,9 @@
+Inferno® is a distributed operating system, originally developed at Bell Labs, but now developed and maintained by Vita Nuova® as Free Software.  Applications written in Inferno's concurrent programming language, Limbo, are compiled to its portable virtual machine code (Dis), to run anywhere on a network in the portable environment that Inferno provides.  Unusually, that environment looks and acts like a complete operating system.
+
+The use of a high-level language and virtual machine is sensible but mundane. The interesting thing is the system's representation of services and resources.  They are represented in a file-like name hiearchy.  Programs access them using only the file operations open, read/write, and close.  The 'files' may of course represent stored data, but may also be devices, network and protocol interfaces, dynamic data sources, and services.  The approach unifies and provides basic naming, structuring, and access control mechanisms for all system resources.  A single file-service protocol (the same as Plan 9's 9P) makes all those resources available for import or export throughout the network in a uniform way, independent of location. An application simply attaches the resources it needs to its own per-process name hierarchy ('name space').
+
+The system can be used to build portable client and server applications. It makes it straightforward to build lean applications that share all manner of resources over a network, without the cruft of much of the 'Grid' software one sees.
+
+Inferno can run 'native' on various ARM, PowerPC, SPARC and x86 platforms but also 'hosted', under an existing operating system (including FreeBSD, Irix, Linux, MacOS X, Plan 9, and Solaris), again on various processor types.
+
+This Bitbucket project includes source for the basic applications, Inferno itself (hosted and native), all supporting software, including the native compiler suite, essential executables and supporting files.
--- /dev/null
+++ b/doc/20010618.ms
@@ -1,0 +1,941 @@
+.TL
+Inferno 3rd Edition \- June 2001 Revision
+.br
+Release Notes and Errata
+.AI
+Vita Nuova
+support@vitanuova.com
+.br
+18 June 2001
+.SP 4
+.NH 1
+Installation
+.LP
+If you have a previous version of Inferno installed, this one must not
+be installed over it.
+If you have a Lucent Inferno 2.3 release from 1999 or earlier, you
+should make a completely new installation from this CD.
+If you have installed the Vita Nuova `Binary and Limited Source' CD you
+should also make a new installation from this CD.
+If you have previously installed the Vita Nuova Full Source CD from July 2000,
+see the section `Updating the July 2000 release' at the end of this document.
+(You could also make a fresh installation in a new directory, or remove the old
+release and install this one if there are no files you wish to keep.)
+.LP
+Follow the installation instructions in ``Installation of the Inferno Software''
+at the end of Volume 2.
+The printed copy has several mistakes:
+.IP \(bu
+Page 327 notes that on Unix
+if the installation is done as user
+.CW root 
+but a user
+.CW inferno
+exists the files will be owned by
+.CW inferno .
+They are not.
+Indeed, on Unix there is no reason to install the package as
+the super-user
+.CW root .
+Do the installation as the user, perhaps
+.CW inferno ,
+that is to own the files.
+.IP \(bu
+It refers on page 327
+to the Windows installation program as
+.CW Nt-386.exe .
+The correct name is used on the next
+page in the actual instructions, namely
+.CW \einstall\esetup.exe .
+.IP \(bu
+The Windows
+.CW setup.exe
+will offer to create the target installation directory if it does not exist.
+On all other systems, you must first create the directory yourself.
+.IP \(bu
+Solaris and some other commercial Unix systems
+do not read the `Joliet' format section of the CD,
+which uses Unicode names, and
+they
+force the names in the non-Joliet portion on the CD to lower case, sometimes
+with hyphens converted to underscores.
+The installation script on Solaris is therefore
+.CW install/solaris_sparc.sh .
+The installation script itself works despite this.
+Alternatively, if the CD is mounted with the option
+.CW nomaplcase
+the system will not force the names to lower case
+and all names will appear as we intended
+(see the Solaris manual entry for
+.I mount_hsfs ).
+Future CDs will use Rock Ridge format as well as Joliet to avoid the problem.
+(We attempted that this time
+but ran into trouble on Windows systems because of an error in the CD writing program.)
+Linux and FreeBSD show the names we intended.
+.LP
+When installing on Windows NT or Windows 2000, the installation program determines
+if the current user belongs to the
+.CW Administrators
+group.
+If so, the Start Menu entry is created in the
+.CW "All Users"
+profile, otherwise it is created in the user's private profile.
+On Windows 95 and Windows 98, if the user has a private profile the
+Start Menu entry is created there,
+otherwise it is created in the main system Start Menu.
+Furthermore,
+.CW setup.exe
+looks for
+.CW "Start Menu"
+to install the shortcut, but that name is locale-dependent,
+and thus the shortcut will not be installed correctly in non-English locales,
+although Inferno itself will be installed successfully.
+.LP
+When the installation completes normally,
+it prints ``installation complete'', but on some platforms it can then print
+``Killed: ...'' followed by the command line used in the installation shell script.
+Provided it has said ``installation complete'' and there were no errors noted
+prior to that, the installation has succeeded.
+The ``Killed'' message results from the installation software
+running inside the Inferno environment having shut down that environment.
+It does not mean that installation failed.
+.LP
+If an installation does fail, for instance by running out of space,
+delete everything in the target directory before retrying the installation.
+Also see the ``Known Problems'' section below.
+.NH 1
+CD Number
+.LP
+There is a set of six unique numbers on the back of the CD case.
+You should keep the case or record the numbers:
+they identify your subscription, and you will need them
+to gain access to subscriber's services we provide electronically.
+(They are randomly generated and usable in a 6/49 lottery!)
+.NH 1
+Hosted Operating System versions
+.LP
+The software was compiled on the operating system versions listed below.
+UNIX systems show the output from
+.CW "uname -a"
+and the version of the C compiler,
+if known.
+See the section
+.I "Known problems"
+below for a list of known problems for any given release.
+.TS
+center;
+lf(B) lf(R)w(4i) .
+Windows Nt	Windows NT4.0 SP4
+Linux	T{
+Linux vespa 2.2.9-19mdk #1 Wed May 19 19:53:00 GMT 1999 i586 ...
+.br
+(gcc-2.91.66)
+T}
+Solaris	T{
+SunOS pazzo 5.6 Generic_105181-03 sun4u sparc SUNW,Ultra-5_10
+.br
+(gcc 2.95)
+T}
+FreeBSD 4.x	T{
+FreeBSD outside 4.0-RELEASE FreeBSD 4.0-RELEASE #0: ... i386
+.br
+(gcc 2.95.2)
+T}
+HP/UX	T{
+HP-UX hpserv1 B.10.20 A 9000/715 2013314861 ...
+.br
+(c89)
+T}
+IRIX 5.3	T{
+IRIX invece 5.3 11091812 IP22 mips
+.br
+(MIPS cc)
+T}
+Plan9/x86	Third Edition, updates to 5th June 2001
+.TE
+.LP
+The Windows version has also been tested and
+used extensively on the following variants:
+.DS
+.ft B
+Windows '95
+Windows '98
+Windows Me
+.ft R
+.DE
+We have also installed and run the system under Windows 2000, both
+client and server, but there is a problem with the cursor under Windows 2000 client (see below).
+.LP
+Inferno source code is included for the following, but they have neither been
+built nor tested:
+.DS
+.ft B
+Plan 9 (mips, sparc, power)
+Solaris/386
+Unixware v 2.3
+.ft R
+.DE
+.NH 1
+Known problems
+.LP
+See
+.CW www.vitanuova.com/inferno/
+for current pointers to information about Inferno.
+You should particularly check the Frequently Asked Questions at
+.P1
+www.vitanuova.com/inferno/faq.html
+.P2
+and the current Bugs list at
+.P1
+www.vitanuova.com/inferno/bugs.html
+.P2
+The Subscriber area will include online updates after 6 July 2001.
+.LP
+Now, the bad news:
+.IP \(bu
+The Windows NT installation program will create a Start Menu shortcut that invokes
+.I emu
+with a
+.CW "-g800x600"
+argument. The
+.I emu
+display will be incorrect if the screen width available is less than 800 pixels and is not a multiple
+of four. The problem can be seen if the PC is configured with a resolution of 800x600 pixels
+and the Microsoft Office shortcut bar is active. The simplest fix is to change the
+.I emu
+shortcut to use a
+.CW "-g788x600"
+argument instead.
+.IP \(bu
+As mentioned above, the Windows NT installation program looks only for
+.CW "Start Menu"
+not the locale-dependent name.
+.IP \(bu
+Changing the cursor image does not work under Windows 2000 Client;
+this mainly affects
+.I acme ,
+which changes the cursor when rearranging or resizing frames.
+.IP \(bu
+The HP version of hosted Inferno was generated by HP/UX version B.10.20.
+On the HP platform,
+.CW emu
+can currently only be run in interpreted mode; the compiled mode (ie,
+.CW -c1
+option)
+will fault.
+.IP \(bu
+Some Inferno calls return error strings provided by Windows, without modification.
+They can be obscure:
+for instance, ``windows error 10049'' is produced by network calls
+that attempt to use symbolic names when
+.I cs (8)
+has not been started.
+.IP \(bu
+On all systems, the mapping from Inferno names and permissions to the underlying
+operating system's names and permissions needs more work, particularly on Windows.
+Common problems include:
+.RS
+.IP \-
+File names in the Inferno environment cannot be longer than 27 bytes.
+.IP \-
+.I Ftpfs
+cannot access files with long names or names containing spaces.
+.IP \-
+The contents of
+.CW /dev/user
+on Windows will contain the Windows user name, which can contain spaces.
+.IP \-
+Files created inside the Inferno hierarchy by host system applications
+can sometimes have odd permissions when accessed within Inferno.
+.IP \-
+Readonly files and open files cannot be removed under Windows.
+.LP
+In general, the mapping between Inferno users and groups and Windows/Nt users and groups
+is systematic, as described  in
+.I sys-stat (2):
+.QS
+.I Emu
+attempts to maintain a limited but consistent map
+between Inferno and NT worlds, specifically between Inferno
+names and NT security IDs.
+Special NT group `Everyone'
+represents `other' for file permissions.  The Inferno uid is
+the file owner under NT; the Inferno gid reported is the
+first user in the file's ACL that is neither the owner nor
+Everyone; failing that, the gid is the file's owner.
+.QE
+.LP
+The effects of this mapping are sometimes peculiar: for instance, something that
+is thought of as a user appears as the group name in
+.I ls ,
+and vice-versa.
+Either the implementation or the mapping might need to be rethought.
+.RE
+.IP \(bu
+.I bufio (2)
+maintains an internal list of files open for output,
+to support its little-used
+.CW flush -all
+operation.
+Unfortunately, that means that if several processes
+use the same Bufio module instance (the result of a single
+.CW load )
+concurrently for output to different files, they must separately interlock the open, create and close calls.
+.IP \(bu
+The file
+.CW utils/5l/thumb.c
+contains comments in the C++ style, which (reasonably enough) are not accepted by the
+ANSI C compiler on the HP/UX system we used, and thus the current
+.CW 5l
+is not compiled for HP/UX; they will be changed to ANSI C comments by
+one of the online updates.
+.NH 1
+Contents
+.LP
+This revision offers the following, compared to the July 2000 release.
+.SH
+.I "Repairs and changes"
+.IP \(bu
+Many bug fixes and improvements appear throughout.
+Many commands have been revised to print usage and diagnostic consistently, and give reliable exit status for
+.CW sh .
+.IP \(bu
+The shell
+.CW sh
+has repairs and several visible changes:
+.I sh-expr (1)
+implements a
+.CW %
+operator for remainder;
+a new
+.CW @
+operator creates a sub-shell to execute a command, allowing the calling shell to be insulated
+by
+.CW pctl
+(see
+.I sh-std (1))
+from changes to name space and environment;
+environment variables are stored in printable form;
+a newline is allowed after a caret;
+and everyone's favourite change, the colon character
+.CW : ' `
+is no longer reserved in argument words
+(allowing URLs to be given without quoting).
+.IP \(bu
+Inferno's Acme has been revised to match the version in Plan 9 (Third Edition).
+In particular, the
+.CW Edit
+built-in has been added, allowing the use of structural regular expressions
+and the
+.CW sam
+command language for efficient editing within
+Acme,
+replacing the
+.CW /acme/edit
+suite of commands.
+The Acme panes have acquired a similar touch of colour.
+.IP \(bu
+Charon has also had many fixes and improvements, particularly to
+Javascript extraction, frames and layout code.
+Sometimes the `fix' requires making Charon mimic the interpretation of incorrect HTML
+of other browsers.
+The PNG image format is now supported.
+Cookies are enabled by default (too many sites use them);
+parsing and production of the cookie file has been repaired.
+The progress bar is more compact.
+Support for longer SSL keys is enabled by default.
+.IP \(bu
+The software installation commands
+.CW install/*
+have been extensively revised,
+and documented by
+.I archfs (4)
+and
+.I create (8).
+They are based (though not entirely) on Russ Cox's update
+package for Plan 9.
+.IP \(bu
+.I format (8)
+can format an ordinary file, for instance to prepare flash partition
+contents in a hosted environment for a native Inferno device.
+.IP \(bu
+.CW mount
+allows the certificate file to be named directly.
+.IP \(bu
+.CW ns
+correctly quotes the fields in its output.
+.IP \(bu
+.CW /services/server/config
+no longer gives the unauthenticated
+.CW nobody ') (`
+option to
+.I styx (8);
+some unused entries have also been deleted.
+.IP \(bu
+.I srv (8)
+passes all arguments to servers it spawns, including the command name.
+It also ensures each server has its own process group, file descriptors
+and name space.
+.IP \(bu
+.I stack (1)
+has a new
+.CW -p
+option to add names to the source file search list.
+.IP \(bu
+.I deflate (2)
+correctly detects end-of-file;
+.I inflate (2)
+correctly decodes the combined compressed code-length tables
+.IP \(bu
+Tk's handling of objects in canvases is better:
+raise and lower work properly; stipple is implemented.
+.IP \(bu
+Tk now knows that a window pops up when resized, and adjusts
+the z-order accordingly.
+.IP \(bu
+Tk's scroller always expands the fraction of a
+.CW moveto
+when it evaluates the scrolling command.
+.SH
+.I "New commands and modules"
+.IP \(bu
+.I ftpfs (4)
+provides a way to make a remote FTP site visible in the Inferno name space
+(it was documented in the printed manual but not previously included with the system).
+.IP \(bu
+.I listen (1)
+provides a convenient way to listen for incoming calls to one or more Inferno services,
+with optional use of
+.I ssl (3)
+for authentication and encryption.
+This can replace the clumsy use of
+.I srv (8).
+.IP \(bu
+.I dial
+(see
+.I listen (1))
+is the complement of
+.I listen ;
+it dials a service, with optional authentication and encryption.
+.IP \(bu
+.I lockfs (4)
+enforces multiple reader, exclusive writer access to the contents of a name space.
+.IP \(bu
+The device
+.I prof (3)
+serves a name space for controlling the profiling of Limbo modules,
+and retrieving the resulting data.
+The module
+.I profile (2)
+offers a convenient interface, relating the profiling data to the source code.
+Finally,
+.I prof (1)
+is the command line interface to enable profiling and display the results.
+.IP \(bu
+.CW uuencode
+and
+.CW uudecode
+interpret a format used to encode binary data printably on Usenet and in mail messages;
+see
+.I uuencode (1).
+.IP \(bu
+.I Read (1)
+writes to standard output the result of a single
+.I sys-read (2)
+of a given number of bytes from standard input,
+with optional seek offset.
+(See
+.I getlines
+in
+.I sh-std (1)
+for a way to read a line from standard input.)
+.IP \(bu
+.I Tcs (1)
+uses
+.I convcs (2)
+to offer character set conversion on files.
+.IP \(bu
+.I wm-misc (1)
+mentions
+.CW wm/mand ,
+a browser for fractals,
+and
+.CW wm/polyhedra ,
+a polyhedra viewer
+.IP \(bu
+.I cfg (2)
+provides a module to read configuration files.
+.IP \(bu
+.I dividers (2)
+provides user-draggable dividing lines to separate Tk widgets,
+allowing screen space to be allocated to widgets by dragging a dividing line.
+.IP \(bu
+.I imagefile (2)
+offers support for reading PNG image files
+.SH
+.I "Interface changes and extensions"
+.IP \(bu
+.CW Url
+.CW /module/url.m ) (
+now requires an
+.CW init
+function to be invoked before other functions in the module
+.IP \(bu
+.I convcs (2)
+has changed its interface significantly (see the manual page);
+it also offers support for UTF-7.
+Even the module name has changed, to
+.CW Convcs
+(from
+.CW ConvCS ).
+.IP \(bu
+.I plumber (8)
+now returns an error to a message's sender if it cannot be plumbed,
+as was previously documented;
+it handles
+.CW ^
+correctly in regular expressions
+.IP \(bu
+.I readdir (2)
+returns all file names in union directories
+.IP \(bu
+.I string (2)'s
+quoting and unquoting functions are correct and more efficient
+.IP \(bu
+.I styxlib (2)
+forces an internal process into a new empty name space to
+allow detection of the last unmount of the served space by a file server
+.IP \(bu
+.I translate (2)
+supports writing Unicode characters in hexadecimal using Limbo's \f5\eu\fP\fIXXXX\fP
+syntax
+.IP \(bu
+.I workdir (2)
+returns a better guess at the current directory on native Inferno
+(hosted implementation will be supported in the next update)
+.IP \(bu
+.I cs (8)
+keeps a cache of recent translations;
+.I ipsrv (8)
+uses UDP/IP by default, not TCP/IP, for domain name lookup
+.IP \(bu
+.I httpd (8)
+can now be said to work as documented
+.IP \(bu
+.I wm-sh (1)
+provides a new control file
+.CW /chan/shctl
+to allow it to be kept informed
+of the current directory (and
+.CW /lib/wmsetup
+defines a Shell function to do that)
+and to implement buttons below the title bar,
+as with
+.I mash-tk (1).
+.IP \(bu
+A collection of playing card images has been added in
+.CW /icons/cards .
+.IP \(bu
+.CW /lib/wmsetup
+defines a
+.CW cd
+function to keep
+.CW wm/sh
+informed of the current directory;
+the
+.CW Web
+menu item is now called
+.CW Charon ;
+a new
+.CW Manual
+entry invokes
+.I wm-man (1);
+and the game
+.CW Tetris
+has been added to the
+.CW Misc
+submenu.
+.IP \(bu
+The manual pages
+.I draw-font (2),
+.I draw-image (2),
+and
+.I draw-screen (2)
+now document
+.CW display
+and
+.CW screen
+members of various data structures.
+.IP \(bu
+.I security-auth (2)
+and
+.I security-login (2)
+note that
+.CW keyring.m
+must be included.
+.IP \(bu
+In
+.I sh (2),
+the function
+.CW exec
+has been renamed
+.CW run ,
+to reflect more accurately what it does.
+.IP \(bu
+In
+.I sys-pctl (2),
+the type of the second parameter to
+.CW Sys->pctl
+is actually
+.CW "list of int"
+not
+.CW "list of ref Sys->FD" .
+.IP \(bu
+.I ssl (3)
+documents the new
+.CW encalg
+and
+.CW hashalg
+files, which list the supported algorithms.
+.IP \(bu
+.I canvas (9)
+describes the new
+.CW -winding
+option
+.IP \(bu
+.CW /services/cs/services
+lists the Software Download Server port
+and removes others that are obsolete.
+.IP \(bu
+.CW /services/server/config
+no longer gives the unauthenticated
+.CW nobody ') (`
+option to
+.I styx (8);
+some unused entries have also been deleted.
+.SH
+.I "Limbo compiler"
+.IP \(bu
+The Limbo compiler correctly clears reference values (eg,
+.CW list ,
+.CW ref
+and
+.CW array )
+when they go out of scope when necessary (eg, in loops), causing the storage to be reclaimed,
+and the values to be correctly
+.CW nil
+when the scope is next entered.
+.IP \(bu
+A bug that caused temporaries sometimes to be reused too early has been fixed.
+.IP \(bu
+The compile-time evaluation of floating-point
+.CW >
+does not calculate
+.CW >=
+instead.
+.IP \(bu
+A little context has been added to `syntax error' messages.
+.SH
+.I "Compilers and architectures"
+.IP \(bu
+The system now supports the Thumb variant of the ARM architecture,
+including full interworking of Thumb code and 32-bit ARM code;
+there is a Thumb JIT compiler for the virtual machine, and support for
+Thumb mode in the disassembler and debugger.
+The Thumb compiler is
+.CW tc ;
+the existing ARM linker
+.CW 5l
+links both ARM and Thumb code.
+.IP \(bu
+A bug in
+.CW 5l
+has been fixed that could very occasionally place a literal pool inside a case table.
+.IP \(bu
+The compilers find include files correctly under Nt.
+.SH
+.I "Hosted and Native Inferno"
+.IP \(bu
+.I Emu
+has the following fixes and improvements:
+.RS
+.IP \-
+support for logging of memory pool usage
+.IP \-
+FreeBSD support uses
+.I rfork
+not
+.I pthreads .
+.IP \-
+Linux support no longer relies on being able to set the TSS register.
+.IP \-
+A memory leak when a kernel process exits has been fixed.
+.IP \-
+A start has been made on tidying up the audio support; the
+.CW svp.c
+file has gone and platforms that do not currently support audio
+no longer must include a stub driver.
+.IP \-
+The Linux and
+FreeBSD ports use an alternative implementation of Inferno graphics
+under X11 that should allow the program to run under 16-bit graphics and higher.
+.RE
+.IP \(bu
+For the native kernels only:
+.RS
+.IP \-
+The native kernel implements Rob Pike's `lexical names' (as in Plan 9), which helps
+provide more sensible data to
+.I workdir (2).
+The hosted Inferno implementation of lexical names will appear in a future update.
+Note that
+.CW /os/port/ns.c
+no longer exists, and native kernel configuration files should no longer mention
+.CW ns
+in the
+.CW port
+section.
+Drivers that serve a directory hierarchy might need to support the
+.CW DEVDOTDOT
+value for the table index in their
+.CW devgen
+function.
+.IP \-
+.CW os/ip/bootp.c
+will correctly time out if there is no response.
+.CW os/ip/ihbootp.c
+will now work with an RFC1084 BOOTP server.
+Note that both are likely to be replaced in future by
+Limbo applications that do BOOTP and DHCP.
+.IP \-
+.CW os/pc/cga.c
+provides a replacement for
+.CW screen.c
+for use when only a simple CGA console is needed or possible.
+.IP \-
+The file descriptor array is correctly freed when the file descriptor
+group is closed, fixing a memory leak.
+.IP \-
+A few files that were left off the July 2000 CD have been included this time.
+.IP \-
+ARM/Thumb kernels have been implemented; those implementations
+are not included in this update because the hardware is specialised but ask if you could use them.
+.RE
+.LP
+The remaining points are common to both hosted and native Inferno:
+.IP \(bu
+A write on closed pipe does not produce an exception if the process has been killed.
+.IP \(bu
+.I Devbwrite
+will not lose memory if an error is raised by the device driver (eg, interrupt).
+.IP \(bu
+.I ssl (3)
+has
+.CW encalg
+and
+.CW hashalg
+files
+.IP \(bu
+.I Kfs (3)
+offers
+.CW readonly
+and
+.CW readwrite
+commands, and an
+.CW ro
+(readonly)
+option to the
+.CW init
+request.
+.IP \(bu
+.I Srv (3)
+rejects attempts to create an unusable name containing a `/'.
+.IP \(bu
+The
+.CW NODEVS
+flag of
+.I sys-pctl (2)
+is correctly copied when the name space is duplicated.
+.\" the following is only in the 386 version
+.\" .IP \(bu
+.\" .I Prog (3)
+.\" can optionally give the correct Dis pc for the debugger even for compiled modules; if
+.\" .CW cflag
+.\" (or
+.\" .CW -c
+.\" option for
+.\" .I emu )
+.\" is 2 not 1, a mapping table is retained after JIT compilation.
+.SH
+.I "SA1100 native"
+.IP \(bu
+A new
+.CW archether
+function in
+.CW arch*.c
+(when required)
+is invoked by
+.CW devether.c
+to discover the configuration of Ethernet devices.
+.IP \(bu
+.CW devuart.c
+supports the use of XON/XOFF;
+the first line of the
+.CW stat
+file gives the current UART settings;
+it no longer panics if an overrun occurs;
+and
+.CW setlength
+accesses the correct structures.
+.IP \(bu
+The CS8900 driver
+.CW ether8900.c
+is more general, supporting the I/O port interface as well as the memory interface.
+.IP \(bu
+Obsolete definitions have been removed from several include files
+(eg,
+.CW io.h )
+and obsolete (typically #ifdef'd code) has been removed from source files.
+.NH 1
+IDEA™
+.LP
+The software includes an implementation of the IDEA encryption algorithm,
+for non-commercial use.
+IDEA was patented by Ascom-Tech AG (European patent EP 0 482 154 B1, US patent number
+US005214703, and patent filed in Japan).
+At time of writing, there was no licence fee required for noncommercial use.
+If you intend to use IDEA encryption commercially with Inferno, you should consult
+.CW http://www.it-sec.com/idea_lic_policy.html
+for the current licensing policy of iT_SEC Systec Ltd, which currently holds the patents and trademark.
+Note that IDEA is not required for
+successful use of Inferno.
+It is not by default enabled by
+.I rstyxd (8),
+and otherwise is used only by SSL3 (for the browser), in
+.CW /appl/lib/crypt/ssl3.b ,
+where it can be disabled.
+.NH 1
+Updating the July 2000 Full Source release
+.LP
+A set of update packages for the July 2000 release is provided in the directory
+.CW /updates
+on this June 2001 CD.
+You should install the updates as the host operating system user who owns the Inferno files and directories
+on your system.
+You might like to take a backup copy of the existing tree, just in case.
+Do the following to update the installation.
+(Next time we hope to provide a more automated scheme.
+You might check
+.CW www.vitanuova.com/inferno/
+to see if there are any more recent instructions.)
+.IP 1.
+Copy the directory
+.CW updates
+and its subdirectories from the CD to a directory
+.CW updates
+in the root of your existing Inferno hierarchy.
+Make sure there is sufficient space in the file system holding that hierarchy.
+If all platform files are copied and installed, about 45 Mbytes will be needed
+to hold the compressed update packages in
+.CW updates ,
+with a further
+35 Mbytes needed for an temporary uncompressed copy
+of the largest package, and allow 10 Mbytes for new additional material, giving
+90 Mbytes in all.
+The
+.CW updates
+directory can be removed after installation.
+.IP 2.
+Start the existing Inferno
+.I emu ;
+it will be quicker if you use the
+.CW -c1
+option to force compiled mode.
+It is best to use only the Inferno console; do not start the window system, since
+the updates will change files in the running system.
+On the other hand, it is a good idea to make the window in the host
+operating system a scrolling one, so that you can scroll back to
+see any errors.
+All following commands are run in the Inferno environment.
+.IP 3.
+Change to the directory
+.CW updates
+and load the standard Inferno shell module:
+.RS
+.P1
+cd /updates
+load std
+.P2
+.RE
+.NE 1i
+.IP 4.
+Unpack the updated installation software:
+.RS
+.P1
+gunzip <install.tgz | {cd /; gettar}
+.P2
+.RE
+.IP 5.
+Update the installed Inferno, source and utility source directories
+using the script
+.CW applybase :
+.RS
+.P1
+sh ./applybase
+.P2
+.LP
+That script updates the
+.CW inferno ,
+.CW src
+and
+.CW utils
+packages.
+You will see one warning:
+.P1
+skipping /dis/install/inst.dis: locally modified
+.P2
+because that file was updated by step 4.
+You might see other warnings if you have modified any other files from the original release.
+.RE
+.IP 6.
+Update one or more platform specific files for your platform(s).
+The directories are named after the platforms:
+.CW Solaris
+for Solaris,
+.CW Plan9
+for Plan 9,
+.CW Nt
+for all Windows systems,
+and so on.
+For each
+.I platform
+that you run, do:
+.RS
+.P1
+for (a in \fIplatform\fP/*) {install/inst -v -t $a}
+.P2
+.RE
+.IP 7.
+Quit
+.I emu .
+The new version of
+.I emu
+will be called
+.CW emu.new
+in the platform-specific directory
+(eg,
+.CW Solaris/sparc/bin/emu.new ).
+Rename the old
+.CW emu
+file as
+.CW emu.old ,
+then rename the new
+.CW emu.new
+as
+.CW emu
+on Plan 9 and Unix systems,
+or
+.CW emu.exe
+on Windows.
+When run, it should announce itself as
+``Inferno Third Edition (18 Jun 2001)''.
binary files /dev/null b/doc/20010618.pdf differ
--- /dev/null
+++ b/doc/20011003.ms
@@ -1,0 +1,758 @@
+.TL
+Inferno 3rd Edition \- 3 October 2001 Update
+.br
+Release Notes
+.AI
+Vita Nuova
+support@vitanuova.com
+.br
+3 October 2001
+.SP 4
+.NH 1
+Contents
+.LP
+This set of updates applies to the 18 June 2001 base.
+The installed software must therefore be that of 18 June 2001, whether installed directly,
+or the result of updating the original July 2000 release with update packages.
+.LP
+This update offers the following, compared to the June 2001 release.
+.SH
+.I "Repairs and changes"
+.IP \(bu
+Various minor bug fixes and improvements appear here and there.
+They include corrected usage messages, status returned to the shell on error,
+diagnosing failures to load library modules,
+and use of the
+.CW %r
+format to improve diagnostics.
+Many
+.I wm
+applications adjust their display to suit small screens (eg, on the Compaq iPAQ);
+currently the applications do some of the work themselves but it will soon be automatic.
+Other changes are listed below.
+.IP \(bu
+.I Date (1)
+takes the options
+.CW -u
+(show UTC/GMT)
+and
+.CW -n
+(print time as a number).
+If given a number of seconds as its argument,
+.I date
+takes that as the time to convert.
+.IP \(bu
+.I Format (8)
+supports tiny partitions.
+.IP \(bu
+.CW /appl/env.b
+uses
+.I env (2)
+to access environment variables.
+.IP \(bu
+For packages created after Saturday 8 September 2001,
+.CW install/create
+converts the leading
+.CW 10
+to the letter
+.CW A
+so that the names of update files remain in sorted order.
+.IP \(bu
+.CW install/inst
+takes a
+.CW -c
+option to cause it to carry on even if some files or directories cannot be made or updated.
+(This option is intended for special applications and should not generally be used when applying system updates.)
+.IP \(bu
+.CW install/install
+takes a
+.CW -P
+option that lists the packages to install.
+The
+.CW -g
+option causes
+.CW install
+to install all available packages.
+.IP \(bu
+The installation software regards files that have had carriage returns inserted
+before newlines as identical to the original files when deciding when files
+have been modified locally.
+.IP \(bu
+The
+.CW wm
+applications now check the whole string received on the window
+control channel returned by
+.I wmlib (2)'s
+.CW titlebar,
+not just an initial letter;
+in particular, they check for
+.CW "exit"
+not just
+.CW 'e' .
+.IP \(bu
+.I Wm (1)
+takes the option
+.CW -s
+to suppress the start menu.
+.IP \(bu
+.I Keyring-gensk (2)
+and
+.I createsignerkey (8)
+provide experimental support for the RSA algorithm for signatures instead
+of the default El-Gamal algorithm;
+.CW /keyring/rsaalg.c
+is new.
+.IP \(bu
+.CW /keyring/egalg.c
+uses the correct structure for Public keys.
+.IP \(bu
+.I Listen (1)
+has a new option
+.CW -i
+that takes a shell command for each listener to run to set up appropriate
+context (eg, name space) before listening for incoming calls.
+.IP \(bu
+.I man (1)
+allows non-numerics in section names.
+.IP \(bu
+.CW /appl/cmd/mkfile
+now includes
+.CW /mkfiles/mksubdirs
+and has acquired the list of
+.CW cmd
+subdirectories from
+.CW /appl/mkfile .
+.IP \(bu
+.I Puttar
+gives warnings not fatal errors when files or directories cannot be found.
+.IP \(bu
+.I sh-expr (1)
+implements the
+.CW !=
+operator.
+.IP \(bu
+.I Tail (1)
+no longer gives an array bound error when a binary file does not end with a newline.
+.IP \(bu
+.CW tiny/sh
+does not break when
+.I filepat (2)
+is not available.
+.IP \(bu
+.I Webgrab (1)
+has several repairs to its HTTP protocol implementation, making it work with multi-homed servers.
+.IP \(bu
+.CW wm/sendmail
+no longer fails to save messages when requested(!).
+.IP \(bu
+.I Arg (2)
+allows re-use by ensuring that its globals are reinitialised by its
+.CW init
+function.
+.IP \(bu
+.I Bufio (2)
+correctly implements relative seek.
+.IP \(bu
+.I Convcs (2)
+provides several more character sets.
+.IP \(bu
+.I Cs (8)
+does not complain if it is already running, suppressing a previously confusing diagnostic.
+.IP \(bu
+.CW lib/deflate
+no longer fails on the output of some PC versions of
+.I gzip .
+.IP \(bu
+.I Wmlib (2)
+adapts a little better to different font and screen sizes (though more remains to be done);
+on small screens, defined as those less than 480 pixels wide,
+.I wm (1)
+puts all windows at the screen origin by default.
+.SH
+.I "Interface changes and extensions"
+.IP \(bu
+.I Wm-deb (1)
+has got a
+.CW stack
+button to bring up the stack window if it has previously been dismissed.
+It also allows breakpoints to be set in modules that have not yet been loaded.
+.IP \(bu
+.CW wm/memory 's
+display has been redesigned to be more informative.
+.IP \(bu
+.CW wm/tetris
+allows the use of a stylus (or mouse) to guide the placement of pieces.
+.IP \(bu
+.CW wm/view
+supports PNG format
+.IP \(bu
+.CW wm/view
+has a new option
+.CW -i
+for use in
+.I plumbing (6)
+files, to cause it to listen for messages from the
+.I plumber (8).
+Existing plumbing files that invoke
+.CW wm/view
+will typically need to change to add that option for image viewing
+using the plumber to work as expected.
+.IP \(bu
+.I Newns (2)
+provides more general option parsing by using
+.I arg (2),
+and does error checking unless the
+.CW -i
+option is given to the
+.I namespace (6)
+commands.
+Its internal
+.CW mount
+commandalso accepts the new options
+.CW -k
+.I keyfile
+to select the source of the authentication key, and
+.CW -C
+.I alg
+to select the encryption algorithm.
+.IP \(bu
+.I Plumber (8)
+takes a
+.CW -v
+option to cause it to log the contents of messages (for debugging plumbing applications), and
+also the option
+.CW -c
+.I wmchan
+to select an alternative window manager channel instead of
+.CW /chan/wm
+when the
+.CW -w
+option is used.
+.SH
+.I "Tk changes and extensions"
+.LP
+Many of the Tk changes enforce rules and do more error-checking than before,
+but there are several extensions and interface changes as well.
+.IP \(bu
+Tk applications must create the parent widget before its children.
+Currently the check to enforce this rule has been suppressed, but it will be enabled in future.
+.IP \(bu
+Widget names are now checked for well-formedness: neither trailing dot nor double dot are allowed.
+.IP \(bu
+When text in a text widget is deleted, embedded windows in
+that text are only deleted if they are descendents of the text
+widget.
+.IP \(bu
+Text widget now redisplays correctly when an embedded window
+is destroyed.
+.IP \(bu
+Text widget now checks for embedded windows in the text that have been destroyed since they were added to the text.
+.IP \(bu
+Widgets packed under a destroyed widget that are not
+descendents of that widget are now removed correctly
+from the packing hierarchy.
+.IP \(bu
+.CW -activebackground
+now changes the border appropriately, same as
+.CW -background .
+.IP \(bu
+.CW scrollbar
+now returns currently activated part when
+.CW activate
+is called
+with no arguments.
+.IP \(bu
+Only one part of a scrollbar may be active at any one time.
+.IP \(bu
+Tk can now distinguish between a null argument
+.CW {}
+and a missing argument.
+.IP
+Creating an embedded window in a text widget at index 1.0
+no longer causes the packer to go into an infinite loop.
+.IP \(bu
+Changing the options on an embedded window in a text
+widget caused an uninitialised pointer access.
+.IP \(bu
+Changing the window associated with an embedded window item
+in text and canvas widgets previously did not disassociate the old window correctly.
+.IP \(bu
+Changing the window associated with an embedded window item
+in a text widget did not set the widget's size appropriately.
+.IP \(bu
+The
+.CW -baseline
+alignment option for embedded windows in text widgets previously
+did not calculate the line height correctly.
+.IP \(bu
+The
+.CW -relief
+setting for buttons is now restored after enter/leave or selection.
+.IP \(bu
+Buttons 4, 5 and 6 have been added (for the iPAQ).
+.IP \(bu
+Tk no longer crashes if the `grab' changes during the processing of a mouse event.
+.IP \(bu
+A new event
+.CW <Destroy>
+can be bound to a widget to receive notification when it is destroyed (eg, by the destruction of
+a parent widget).
+The
+.CW <Configure>
+event is propagated to slaves as well as the configured master.
+These two changes make it easier to implement pseudo-widgets such as
+.I dividers (2).
+.IP \(bu
+.CW -anchor
+has been implemented for labels;
+.CW -justify
+should be implemented as documented.
+.IP \(bu
+Submenus are unmapped correctly.
+.IP \(bu
+Tk detects command loops (by limiting recursion depth).
+.IP \(bu
+.CW canvas
+has a new boolean option
+.CW -buffered
+that controls whether the whole canvas, or just the visible region, is allocated an off-screen buffer image.
+It defaults to just the visible area only.
+.IP \(bu
+.CW canvas
+has new operations
+.CW screenx
+and
+.CW screeny
+to map canvas coordinates to screen coordinates.
+.SH
+.I "New commands and modules"
+.IP \(bu
+A collection of small and tiny playing card images have been added, in
+.CW /icons/smallcards
+and
+.CW /icons/tinycards .
+.IP \(bu
+.CW install/wfind
+lists the versions of a given file in a set of installation packages.
+.IP \(bu
+.I Touchcal (8)
+provides touch-screen calibration; it runs both inside and outside the window
+manager
+.I wm (1).
+Both internal and external interfaces are completely different from previous versions.
+.IP \(bu
+.I Wm-keyboard (1)
+describes new commands
+.CW wm/keyboard
+and
+.CW wm/pen
+that provide soft keyboard and single-stroke gesture recognition for touch screen devices.
+.IP \(bu
+.I Gamesrv (4)
+provides a file system interface for multi-player networked games;
+.I gamesrv (2)
+provides the interface for the game-specific engines loaded on demand by the game server.
+.IP \(bu
+.CW utils/awk
+is a new directory containing the source for a version of
+.I awk
+for use in doing Inferno ports for systems that lack it (or a sufficiently recent version), including Windows.
+It is not currently made automatically for any system.
+It is covered by its own licence; see the
+.CW README
+and
+.CW NOTICE
+files in that directory.
+.SH
+.I "Limbo compiler"
+.IP \(bu
+The compiler now adds a source file name (relative to the Inferno root) to each Dis
+file, to allow
+.I debug (2)
+and thus the debugger
+.CW wm/deb
+and other commands such as
+.I profile (1)
+and
+.I stack (1)
+to find source
+and
+.CW .sbl
+files without prompting.
+.IP \(bu
+The initialisation of large arrays avoids deep recursion, preventing a trap on Nt
+and a large stack on other platforms.
+.IP \(bu
+Overflow is avoided when sorting integers for case statements.
+.SH
+.I "Compilers and architectures"
+.IP \(bu
+The linker
+.CW 5l
+has a critical bug fix in 
+.CW utils/5l/span.c
+that fixes a bug in the flushing of literal pools.
+.IP \(bu
+.CW 5coff
+has a small change to make the output conform to actual practice
+not COFF documentation.
+.SH
+.I "Hosted and Native Inferno"
+.IP \(bu
+.I Emu
+has the following fixes and improvements:
+.RS
+.IP \(bu
+Trap handling on Windows now (we hope) does all that is required
+to work on many versions, variants, updates and releases.
+.IP \(bu
+The cursor appears correctly under Windows 2000.
+.IP \(bu
+Windows
+.I emu
+passes page up, down scroll, pause, insert, delete and print
+characters through to
+.CW /dev/keyboard .
+.IP \(bu
+.CW styx.c
+prevents bad Styx messages from causing trouble.
+.IP \(bu
+.CW devenv.c
+returns
+.CW "file exists"
+if an attempt is made to create an existing name;
+it implements
+.CW ORCLOSE .
+.IP \(bu
+.CW devroot.c
+makes directories mode 555 not 777.
+.RE
+.IP \(bu
+For the native kernels only:
+.RS
+.IP \(bu
+.I Env (3)
+is now provided for native kernels.
+To add it to a kernel, change the kernel configuration file as follows:
+.RS
+.IP 1.
+Include the device driver
+.CW env
+in the
+.CW dev
+section.
+.IP 2.
+Include the support file
+.CW env
+in the
+.CW port
+section.
+.IP 3.
+Include the name
+.CW /env
+in the
+.CW root
+section.
+.LP
+To exclude it from a kernel, include the support file
+.CW noenv
+in the
+.CW port
+section.
+You should only do this if you are trying to make a small highly specialised kernel;
+general applications are likely to make more use of
+.CW /env
+now that it is there,
+eventually to replace
+.CW sysenv 
+and to select locales.
+.RE
+.IP \(bu
+Common floating-point emulator code has moved from platform-specific directories to
+.CW /os/port/fpi.c
+and
+.CW /os/port/fpimem.c ,
+with corresponding changes to configuration files and
+.CW mkfiles .
+.IP \(bu
+The scheduling code in
+.CW /os/port/proc.c
+has changed to support wait-for-interrupt.
+If no process can be scheduled, the platform-specific function
+.CW "void idlehands(void)"
+is called, with interrupts
+.I off
+(unlike the function of the same name in Plan 9).
+On most platforms, it currently is an empty function defined by
+.CW #define
+in
+.CW fns.h ,
+and the scheduler effectively spins waiting for an interrupt to make a kernel process ready,
+but on the iPAQ and a few other platforms it uses the hardware-specific
+``wait for interrupt'' function, for power saving.
+.IP \(bu
+A new package
+.CW ipaq
+is available that populates
+.CW /os/ipaq
+with the preliminary Inferno port to the Compaq iPAQ.
+.IP \(bu
+.CW /os/ip
+has incorporated bug fixes and improvements from Plan 9 to
+keep the source code up to date:
+.RS
+.IP \-
+.CW /net/ndb
+has been added, to allow for future changes in IP configuration code
+.IP \-
+permissions are checked more carefully;
+.CW wstat
+is implemented
+.IP \-
+.CW Conv
+structures are now unlocked on
+.CW close
+by
+.CW devip.c
+not by each protocol's implementation;
+the
+.CW car
+lock for connect/announce no longer exists, because the conversation itself is locked
+.IP \-
+some missing
+.CW waserror
+calls have been added
+.IP \-
+ensure local port is unique across existing conversations
+.IP \-
+.CW tos
+can be set for a converstation by a
+.CW tos
+control message, and is retained during routing
+.IP \-
+.CW qdiscard
+in
+.CW qio.c
+returns the number of bytes discarded
+.IP \-
+protocol handlers
+.CW esp.c ,
+.CW gre.c ,
+.CW icmp.c ,
+.CW ip.c ,
+.CW ipifc.c ,
+.CW ipmux.c ,
+.CW rudp.c
+and
+.CW tcp.c
+have consequentially changed;
+the TCP/IP implementation most extensively;
+.CW il.c
+and
+.CW udp.c
+have not yet been realigned with Plan 9
+.IP \-
+medium drivers use the structure-member initialisation extension of Plan 9 C,
+to insulate driver source text from changes in the layout of the
+.CW Medium
+structure
+.RE
+.IP \(bu
+The SA1100 UART driver now correctly pushes input up the stack when the FIFO empties.
+.RE
+.LP
+The remaining points are common to both hosted and native Inferno:
+.IP \(bu
+.I Cons (3)
+implements the file
+.CW kprint
+to capture Inferno console messages; and a file
+.CW jit
+that can be used to set the compile-on-the-fly option dynamically or read its current state.
+.IP \(bu
+There is a new kernel function:
+.RS
+.DS
+.ft 5
+char* seprint(char *buf, char *ebuf, char *fmt, ...);
+.ft P
+.DE
+which puts a formatted result into
+.CW buf
+never writing beyond
+.CW ebuf-1
+(including the trailing null byte).
+It returns the address of the next available byte in
+.I buf .
+.RE
+.IP \(bu
+.CW kfs 's
+.CW Eexist
+error has become
+.CW Eexists
+to remove a clash with the new
+.CW Eexist
+name in
+.CW error.h
+.IP \(bu
+.CW exportfs.c
+maintains offsets in exported directories correctly.
+.IP \(bu
+The undocumented
+.CW devaudit.c
+has been removed.
+.IP \(bu
+Some Limbo profiler bugs have been fixed.
+.IP \(bu
+A race for the use of a shared semaphore has been fixed in
+.CW devprog.c .
+.IP \(bu
+.CW devprog.c
+has a new debugging event:
+.CW load
+.I filename
+corresponds to the execution of a Dis
+.CW load
+instruction.
+.IP \(bu
+.CW devdraw.c
+implements
+.CW readpixels
+from a window
+.NH 1
+Updating the software
+.LP
+You should install the updates as the host operating system user who owns the Inferno files and directories
+on your system.
+You might like to take a backup copy of the existing tree, just in case.
+Do the following to update the installation.
+.IP 1.
+Fetch the update archives required, namely
+.CW inferno.tgz ,
+.CW src.tgz ,
+.CW utils.tgz
+and any platform-specific packages required for your installation.
+If you are running Windows, for instance, you will need
+.CW Nt.tgz ;
+if running Plan 9, you will need
+.CW Plan9.tgz .
+These are gzip'd tar files containing files starting with the directory
+name
+.CW updates/20011003 .
+Unpack each in your Inferno root directory.
+For instance, you can unpack
+.CW inferno.tgz
+using the Inferno commands:
+.RS
+.P1
+cd /
+gunzip <inferno.tgz | gettar
+.P2
+The following instructions assume they are visible in the Inferno hierarchy.
+Make sure there is sufficient space in the file system holding that hierarchy.
+Each archive can be removed after unpacking, and the
+.CW updates
+directory can be removed after installation.
+.RE
+.IP 2.
+After unpacking the archives,
+(re)start
+the existing Inferno
+.I emu ;
+it will be quicker if you use the
+.CW -c1
+option to force compiled mode.
+It is best to use only the Inferno console; do not start the window system, since
+the updates will change files in the running system.
+On the other hand, it is a good idea to make the window in the host
+operating system a scrolling one, so that you can scroll back to
+see any errors.
+All following commands are run in the Inferno environment.
+.IP 3.
+Change to the directory containing the updates:
+.RS
+.P1
+cd /updates/20011003
+.P2
+.RE
+.NE 1i
+.IP 4.
+Updated installation software was included in
+.CW inferno.tgz .
+You must first unpack that installation software, as follows:
+.RS
+.P1
+sh ./unpacktools
+.P2
+.RE
+.NE 1i
+.IP 5.
+Update the installed Inferno, source and utility source directories
+using the script
+.CW applybase :
+.RS
+.P1
+sh ./applybase
+.P2
+.LP
+That script updates the
+.CW inferno ,
+.CW src
+and
+.CW utils
+packages.
+You might see warnings if you have modified any non-configuration files from the original release.
+.RE
+.IP 6.
+Update one or more platform specific files for your platform(s).
+The directories are named after the platforms:
+.CW Solaris
+for Solaris,
+.CW Plan9
+for Plan 9,
+.CW Nt
+for all Windows systems,
+and so on.
+For each
+.I platform
+that you run, do:
+.RS
+.P1
+sh ./applyplat \fIplatform\fP
+.P2
+For instance, if you use Windows, run
+.P1
+sh ./applyplat Nt
+.P2
+The iPAQ distribution is installed the same way (it is just another platform):
+.P1
+sh ./applyplat ipaq
+.P2
+which populates
+.CW /os/ipaq
+in the Inferno tree.
+.RE
+.IP 6.
+Quit
+.I emu .
+The new version of
+.I emu
+will be called
+.CW emu.new
+in the platform-specific directory
+(eg,
+.CW Solaris/sparc/bin/emu.new ).
+Rename the old
+.CW emu
+file as
+.CW emu.old ,
+then rename the new
+.CW emu.new
+as
+.CW emu
+on Plan 9 and Unix systems,
+or
+.CW emu.exe
+on Windows.
+When run, it should announce itself as
+``Inferno Third Edition (3 October 2001)''.
binary files /dev/null b/doc/20011003.pdf differ
--- /dev/null
+++ b/doc/20020628.ms
@@ -1,0 +1,1030 @@
+.TL
+Inferno 3rd Edition \- 28 June 2002 Update
+.br
+Release Notes
+.AI
+Vita Nuova
+support@vitanuova.com
+.br
+28 June 2002
+.SP 4
+.NH 1
+Base for update
+.LP
+This set of updates applies to the 18 June 2001 base.
+The installed software must therefore be that of 18 June 2001, whether installed directly,
+or the result of updating the original July 2000 release with update packages to the
+18 June 2001 level.
+This set of updates can be applied, however, whether or not the previous update
+of 3 October 2001 was installed; this package includes all those changes too.
+.NH 1
+Contents
+.LP
+This update offers the following, compared to the 3 October 2001 release.
+.LP
+The following sections provide short
+summaries of the more interesting or important changes.
+There are many more minor or cosmetic changes.
+.SH
+.I "New commands and modules"
+.IP \(bu
+.I Fc (1)
+is a floating-point calculator.
+.IP \(bu
+A new page
+.I man (6)
+describes the formatting commands used in manual pages.
+.IP \(bu
+Support for system-level memory monitoring has been made available
+as an optional component of
+.CW emu ,
+with the interface provided by a new driver
+.CW /emu/devmem.c .
+It is not compiled in by default,
+since it is relatively intrusive.
+Details of how to enable it will be provided with the applications that use it.
+.IP \(bu
+.I Strings (1)
+extracts strings from a file.
+.IP \(bu
+.CW 9export
+(see
+.I export (4))
+serves a name space to a 9P client (mainly useful for
+interacting with Third Edition Plan 9 systems at the moment).
+.IP \(bu
+.CW cdfs ,
+which was described by
+.I dossrv (4)
+but not actually shipped is now included.
+.IP \(bu
+.CW csquery ,
+described in
+.I cs (8),
+queries the connection service and prints the result.
+.IP \(bu
+.CW newer ,
+described by
+.I ftest (1),
+is a shell predicate that compares the modification times on two files.
+.IP \(bu
+.I Print (2)
+is a new module that provides an interface to directly-driven printers.
+.SH
+.I "Repairs and changes"
+.IP \(bu
+.CW cp
+has been reworked extensively; amongst other things, it can now safely traverse
+arbitrary name spaces without becoming confused by
+complex mounts.
+.IP \(bu
+.I Listen (1)
+and
+.CW dial
+both accept a
+.CW -A
+option to cause it to authenticate a connection.
+.IP \(bu
+.I Diff (1)
+compares binary files and also does not quit (during recursive diffs) when it finds
+a file it cannot open.
+.IP \(bu
+.I Ls (1)
+implements the
+.CW -u
+and
+.CW -t
+sorting operations properly.
+A new
+.CW -e
+option prints the time as a decimal integer (seconds since the system Epoch).
+.IP \(bu
+.I Sh
+regards all of `../', `./', and `#' at the front of a command name as a request to use the name as-is.
+.IP \(bu
+.I Tail
+has been changed to avoid some boundary cases.
+.IP \(bu
+.I Touch
+uses standard argument processing and returns an error exit status if it fails.
+.IP \(bu
+.I Zeros
+accepts new options
+.CW -r
+to generate random bytes
+and
+.CW -v
+to produce blocks with a given value.
+.IP \(bu
+The network games software in
+.CW /appl/games
+uses port 6660 for its signer, not the standard Inferno signer's port.
+.IP \(bu
+.I Charon :
+disguises itself as Mozilla to satisfy agent-name probes; retries fetches on error; supports multiple windows;
+detects HTML vs plain text correctly; has many Javascript fixes, including fixing a day one bug
+in operator precedence (!).
+In general, it
+has undergone extensive changes,
+particularly to the cookies and Javascript implementation.
+It also insists that it be run under the window manager
+.I wm (1).
+It can be set to plumb schemes that it does not implement internally.
+.IP \(bu
+The installation software now uses the numeric time as-is to name output packages;
+the temporary fix introduced in Ocotober of converting  leading
+.CW 10
+to
+.CW A
+has been removed.
+.IP \(bu
+.CW /appl/lib/dis.b
+prints offsets from
+.CW MP
+correctly (it previously printed them
+as offsets from
+.CW FP ).
+.IP \(bu
+.CW /appl/lib/parseman.b
+accounts for enough extra
+.I troff
+commands to display
+.I man (6)
+correctly.
+.IP \(bu
+.CW /appl/lib/profile.b
+binds
+.CW #P
+only if needed.
+.IP \(bu
+.CW /appl/lib/translate.b
+.I translate (2)) (
+now computes the right hash value.
+.IP \(bu
+Several run-time checks that were missing or incomplete for array access and slicing have been added.
+.IP \(bu
+.CW lib/isrv
+no longer starts a new shell.
+.IP \(bu
+.I Wm-ftree (1)
+has several new options:
+.CW -E ,
+.CW -p
+and
+.CW -d .
+.IP \(bu
+.CW wm/rt
+now correctly updates stack size (if set).
+.IP \(bu
+.I Xd (1)
+correctly implements
+.CW -r
+to suppress repeated lines.
+.IP \(bu
+.I gettar (1)
+documents the
+.B lstar
+output format
+.IP \(bu
+.I man (6)
+describes the manual page documentation format
+.SH
+.I "Interface changes and extensions"
+.IP \(bu
+.I Security-password (2)
+provides a new entry
+.CW setpwfile
+to allow the default name
+.CW /keydb/password
+to be changed.
+.IP \(bu
+.I Dossrv (4)
+has changed extensively, to support rename and long names in FAT format correctly.
+It uses a smaller number of IO buffers.
+.IP \(bu
+.I Createsignerkey (8)
+has a completely different invocation, documented in that manual page,
+with a conventional option structure replacing a rather idiosyncratic chain
+of optional arguments.
+The old syntax is temporarily secretly still supported, but only
+for the benefit of any shell scripts that might so use it; if you have any,
+please change them to use the new syntax before the old usage finally vanishes in a later release.
+.IP \(bu
+.I Sum (1)
+documents the new
+.CW sha1sum
+command.
+.IP \(bu
+.I Bufio (2)
+returns an error if a seek fails rather than stopping the process(!).
+.IP \(bu
+.CW /lib/convcs
+has several more character sets:
+.CW koi8-r ,
+.CW windows-1250
+and
+.CW windows-1252 .
+.IP \(bu
+.I Keyring-sha (2)
+documents two new functions,
+.CW hmac_sha1
+and
+.CW hmac_md5 ,
+which are keyed versions of the corresponding secure hashing functions,
+as defined by RFC2104.
+The new definitions are in
+.CW /module/keyring.m .
+.IP \(bu
+.I Keyring-getstring (2)
+makes it clear that it does not
+.I provide
+delimited I/O but rather
+.I requires
+it (eg, as provided by
+.I ssl (3))
+for successful operation.
+.IP \(bu
+.I Security-ssl (2)
+no longer requires
+.CW #D
+to be bound into the name space (since it can only be used locally in any case).
+Consequently,
+.CW bind
+calls have been removed from several modules that used SSL.
+.IP \(bu
+.CW /appl/lib/crypt/ssl3.b
+has several critical bug fixes, allowing secure connections to work correctly in Charon;
+an important bug fix was also made to
+.CW /appl/lib/crypt/x509.b .
+.IP \(bu
+.I Imageremap
+has been changed to allow concurrent use.
+.IP \(bu
+.I Translate (6)
+and
+.CW /appl/lib/translate.b
+have changed as required to put the locale-specific dictionaries in directory
+\f(CW/locale/\fP\fIlocale\f(CW/dict\fP;
+the directory for a chosen
+.I locale
+is then normally bound onto
+.CW /locale/dict ,
+where
+.CW translate
+looks by default.
+.IP \(bu
+The documentation for
+.I button (9)
+no longer claims that
+.CW -padx
+and
+.CW -pady
+are supported options for that widget.
+.IP \(bu
+.CW sys.m
+has some new constants defined for use by a later Styx revision.
+.SH
+.I "Tk changes and extensions"
+.IP \(bu
+The canvas code provides extensions to Tk:
+.CW "grab set tag" ,
+.CW "grab release tag" ,
+and
+.CW "grab ifunset tag" .
+See
+.I canvas (9)
+for details.
+.IP \(bu
+Also in canvases, object-specific hit tests have been added, rather than using a bounding box
+in most cases.
+.IP \(bu
+Borderwidth defaults to zero in the entry widget.
+.IP \(bu
+Tk multiplexes the cursor amongst top-level windows.
+.IP \(bu
+Text and other items selected use foreground/background colours
+.SH
+.I "Limbo compiler"
+.IP \(bu
+Constant tuple and adt values can be used as values in
+.CW con
+constant declarations.
+.IP \(bu
+In an array value, the use of reference values for different
+.CW pick
+alternatives of the same adt no longer draws a diagnostic
+but causes the array value to be an array of
+.CW ref
+to the adt, not a particular pick alternative.
+.IP \(bu
+The C language stub declarations support
+.CW pick
+adts.
+.IP \(bu
+The alignment of
+.CW big
+and
+.CW real
+is now correct in C stubs.
+.IP \(bu
+The string escape
+.CW \ef
+is form-feed (to simplify translation of C programs).
+.SH
+.I "Compilers and utilities"
+.IP \(bu
+.I Iar 's
+source directory has been renamed from
+.CW ar
+to
+.CW iar .
+.IP \(bu
+.CW mk
+understands the long-name table in Windows' archive files, preventing
+spurious out-of-date status and other confusing results in builds.
+.IP \(bu
+.CW sqz
+and
+.CW zqs
+can compress larger ARM and PowerPC executables.
+.IP \(bu
+.CW kprof
+uses a table now provided by
+.CW /dev/kprof
+to provide profiling results to the resolution selected by a given platform.
+.SH
+.I "Hosted and Native Inferno"
+.LP
+Changes common to hosted and native kernels:
+.IP \(bu
+The
+.CW HOSTMODEL
+and
+.CW TARGMODEL
+for Plan 9 are now
+.CW Plan9
+not, rather confusingly,
+.CW Inferno .
+A good few source files have been renamed accordingly.
+.IP \(bu
+The memory allocation functions have been modified slightly to support the addition of
+memory monitoring and profiling.
+Some functions have also been added to the C library supporting
+.I emu
+and the kernels,
+with an eye to starting the revision of Styx, based on the current 9P2000.
+Consequently, the
+include file
+.CW lib9.h
+for all platforms has been modified:
+to add new functions such as
+.CW setmalloctag ;
+to make the types of parameters to the
+.CW malloc
+calls uniform (and reflect the documentation, as it happens),
+so that sizes are always unsigned;
+to change the type of a parameter to
+.CW strchr
+and
+.CW strrchr
+from
+.CW char
+to
+.CW int ;
+to remove obsolete definitions such as
+.CW UMFILE
+and
+.CW UMDIR ;
+and to add new functions for use inside the kernels.
+Several new functions are strictly for internal use
+(and thus might change in future), and
+they have not been added to section 10.
+One exception is the new function
+.CW tokenize ,
+documented in
+.I getfields (10.2)
+and used by
+.I parsecmd (10.2).
+.I Getfields
+replaces the function called
+.CW parsefields ,
+which has been removed, and all calls to it changed to use
+.CW getfields .
+The higher aim of some of these otherwise fussy changes is
+to work towards making Inferno and Plan 9 drivers interchangeable
+(as best we can).
+.IP \(bu
+To help decouple authentication methods from identity setting, two new files
+.CW caphash
+and
+.CW capuse
+have been added to
+.CW #c
+(a temporary location for them), supported by code in
+.CW auth.c
+.CW /os/port/auth.c ). (
+Their use will soon replace the
+.CW setid
+functionality of
+.I keyring-auth .
+They will not be documented until then.
+.IP \(bu
+.CW /emu/exception.c
+and
+.CW /os/port/exception.c
+no longer trap the use of the
+.CW exit
+statement (by accident of implementation).
+.CW \(bu
+.CW /emu/dis.c
+and
+.CW /os/port/dis.c
+do not leave a process in Broken state when it
+receives an exception because a kernel memory allocation failed.
+.IP \(bu
+The JIT compilation of case statements has fixed a day one bug
+that caused a degenerate form of
+.CW case
+(with only a default arm) to be compiled incorrectly.
+.IP \(bu
+The 386 JIT will allow rescheduling, and the scheduling is finer grained on the ARM.
+.IP \(bu
+ARM code generation produces correct code for some list accesses that were previously wrong
+(the Dis operator HEADM)
+.IP \(bu
+.I Emu
+has the following changes specific to it:
+.RS
+.IP \-
+The mouse event queue in
+.CW devcon.c
+is now a circular queue without locks as in the native kernel;
+this prevents a scheduling problem under Linux.
+.IP \-
+The
+.CW READSTR
+constant defined by the native kernels is now also defined by
+.CW emu .
+.IP \-
+The function previously called
+.CW rendezvous
+is now called
+.CW erendezvous
+to avoid a type clash with a library function on Plan 9
+(its `rendezvous' function takes an unsigned long as first parameter, not
+.CW void* ).
+.CW lib9.h
+has changed accordingly where required.
+.IP \-
+.CW devcon.c
+acquires
+.CW caphash
+and
+.CW capuse .
+.IP \-
+A new file
+.CW auth.c
+must be included in every build.
+.IP \-
+Several drivers in
+.CW emu
+have been changed to use
+.RS
+.P1
+	switch((ulong)c->qid.path ...)
+.P2
+.RE
+to force 32-bit operations to be used when
+.CW path
+eventually becomes 64 bits.
+.IP \-
+Also in
+.CW emu
+the function
+.CW oserrstr
+now takes a buffer length, rather than assuming
+.CW ERRLEN .
+.IP \-
+Obsolete code for time and directory mode conversions (!) has been removed from
+.CW os-*.c .
+.IP \-
+Obsolete code for `daemonize' has been removed from
+.CW os-*.c
+and
+.CW lib9 .
+.RE
+.IP \(bu
+For the native kernels:
+.RS
+.IP \-
+.CW /os/port/devprof.c
+has been added but is not yet supported (it is not configured in to any kernel,
+so no existing kernels are affected by its presence).
+.IP \-
+.CW /os/port/devcons.c
+has
+.CW caphash
+and
+.CW capuse
+.IP \-
+Every kernel configuration file must now include
+.CW auth
+in the
+.CW port
+section to include
+.CW /os/port/auth.c .
+.RE
+...#.bp
+...#.NH 1
+...#Description by source file
+...#.LP
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/appl/charon	T{
+...#plumbs schemes that aren't built-in, if on an authorised list
+...#.br
+...#retries on error (but not POST)
+...#.br
+...#identifies itself as Mozilla to pass agent-name tests.
+...#.br
+...#bug fix: doesn't loop (exhausting memory) if a file ends with bad data.
+...#.br
+...#private version of Url
+...#.br
+...#CCI removed
+...#.br
+...#charon_code and charon_guiwm removed
+...#.br
+...#multiple windows
+...#.br
+...#detects HTML vs text correctly
+...#.br
+...#separate layout and gui display
+...#.br
+...#T}
+...#/appl/cmd/diff.b	T{
+...#compare binary files as documented
+...#.br
+...#don't quit if files can't be opened
+...#.br
+...#T}
+...#/appl/cmd/strings.b	T{
+...#new command
+...#.br
+...#T}
+...#/appl/cmd/sh	T{
+...#../ / ./ and # starting a (command) name all cause it to be treated as absolute
+...#.br
+...#T}
+...#/appl/lib/auth.b	T{
+...#allow nobody even if setid is 0 provided it appears in the algorithm list
+...#.br
+...#don't bind #D
+...#.br
+...#T}
+...#/appl/lib/createsignerkey.b	T{
+...#arguments
+...#.br
+...#don't bother with random
+...#.br
+...#error status
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/appl/lib/crypt/ssl3.b	T{
+...#delete session id on alert
+...#.br
+...#T}
+...#/appl/lib/ecmascript	T{
+...#correct precedence for operators
+...#.br
+...#delete HTML comments
+...#.br
+...#T}
+...#/appl/lib/isrv.b	T{
+...#don't start a new shell
+...#.br
+...#T}
+...#/appl/lib/login.b	T{
+...#don't bind #D
+...#.br
+...#T}
+...#/appl/lib/logind.b	T{
+...#don't bind #D
+...#.br
+...#don't load (unused) Random
+...#.br
+...#minor internal changes.
+...#.br
+...#T}
+...#/appl/lib/profile.b	T{
+...#memory profiling
+...#.br
+...#T}
+...#/appl/lib/srv.b	T{
+...#be sure to FORKFD so file descriptors don't accumulate in parent
+...#.br
+...#T}
+...#/appl/lib/ssl.b	T{
+...#don't require #D to be bound since it can only be used locally
+...#.br
+...#T}
+...#/appl/lib/usb/*	T{
+...#see TI925 release
+...#.br
+...#T}
+...#/appl/lib/wmlib.b	T{
+...#calculate correct size of file browser (eg when full screen)
+...#.br
+...#don't mess with the cursor
+...#.br
+...#T}
+...#/appl/minicharon	T{
+...#moan if no window manager
+...#.br
+...#don't trap if module not yet loaded
+...#.br
+...#T}
+...#/appl/wm/bounce.b
+...#/appl/wm/man.b
+...#/appl/wm/mand.b
+...#/appl/wm/polyhedra.b
+...#/appl/wm/wm.b	T{
+...#correct window size in full screen mode
+...#.br
+...#T}
+...#/appl/wm/reversi.b	T{
+...#use fittoscreen(0)
+...#.br
+...#T}
+...#/appl/wm/polyhedra.b	T{
+...#sys->sleep(0) to yield
+...#.br
+...#T}
+...#/man/2/security-ssl	T{
+...#bind not required
+...#.br
+...#conventions documented accurately
+...#.br
+...#T}
+...#/man/2/keyring-getstring	T{
+...#makes it clear that it doesn't PROVIDE delimited i/o, but EXPECTS it (eg, via ssl(3))
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/crypt/jacobi.c	T{
+...#add missing return statement
+...#.br
+...#T}
+...#/emu/alloc.c	T{
+...#changes for monitoring
+...#.br
+...#long for size throughout
+...#.br
+...#poolrealloc, now used by malloc
+...#.br
+...#poolmsize
+...#.br
+...#malloc and realloc tagging data with pc of allocation
+...#.br
+...#ud -> lud etc
+...#.br
+...#T}
+...#/emu/chan.c	T{
+...#space isn't frog, experimentally
+...#.br
+...#T}
+...#/emu/dat.h	T{
+...#READSTR definition
+...#.br
+...#Rept definition (will change)
+...#.br
+...#add BusyGC
+...#.br
+...#remove support for %N
+...#.br
+...#T}
+...#/emu	T{
+...#oserrstr takes buffer size (consequential changes throughout)
+...#.br
+...#no %N
+...#.br
+...#Plan 9's HOSTMODEL -> Plan9 not Inferno (!)
+...#.br
+...#msize -> hmsize in some cases
+...#.br
+...#rendezvous -> erendezvous
+...#.br
+...#T}
+...#/emu/devcon.c	T{
+...#no %N, Nconv
+...#.br
+...#remove debugging memout file
+...#.br
+...#use of (ulong)c->qid.path ...
+...#.br
+...#remove logmsg calls
+...#.br
+...#T}
+...#/emu/devprof.c	T{
+...#memory profiling
+...#.br
+...#T}
+...#/emu/devprog.c	T{
+...#msize -> hmsize because malloc and heap addresses are different
+...#.br
+...#T}
+...#/emu/dis.c	T{
+...#instrument garbage collections
+...#.br
+...#force periodic garbage collection passes when not idle (BusyGC)
+...#.br
+...#T}
+...#/emu/discall.c	T{
+...#tag QLock structures with owner
+...#.br
+...#T}
+...#/emu/fns.h	T{
+...#oserrstr definition
+...#.br
+...#obsolete gsleep defn removed
+...#.br
+...#T}
+...#/emu/main.c	T{
+...#obsolete gsleep defn removed
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/emu/os-*	T{
+...#dflag becomes simply don't enable graphics terminal (ie, save/restore tty state)
+...#.br
+...#daemonize calls removed [do it from outside]
+...#.br
+...#rendezvous -> erendezvous
+...#.br
+...#some files had obsolete timeconv and dirmodconv code, now removed
+...#.br
+...#T}
+...#/emu/proc.c	T{
+...#provisional rpt code (will change, will move)
+...#.br
+...#T}
+...#/emu/vlrt-Nt.c	T{
+...#use dat.h not local definitions
+...#.br
+...#T}
+...#/include/interp.h	T{
+...#force HEAP_ALIGN to provide extra cell in heap header for heap profiling
+...#.br
+...#new functions: heapmonitor, hmsize
+...#.br
+...#utfnlen removed  (local to interp/runt.c)
+...#.br
+...#T}
+...#/include/pool.h	T{
+...#sizes are now unsigned
+...#.br
+...#poolcompact defn, new poolmsize, poolrealloc
+...#.br
+...#T}
+...#/include/tk.h	T{
+...#extra state to control cursor
+...#.br
+...#T}
+...#/interp/comp-386.c	T{
+...#implement and enable interpreter rescheduling when JIT enabled
+...#.br
+...#T}
+...#/interp/comp-arm.c
+...#/interp/comp-thumb.c	T{
+...#change arm rescheduling check to be similar to 386
+...#.br
+...#T}
+...#/interp/gc.c	T{
+...#instrument garbage collector
+...#.br
+...#add heapmonitor hook for devmem.c
+...#.br
+...#T}
+...#/interp/heap.c	T{
+...#define heapmonitor hook (default: nil)
+...#.br
+...#call it at appropriate places
+...#.br
+...#change // to /* comment
+...#.br
+...#add hmsize to account for alloc.c changes
+...#.br
+...#T}
+...#/interp/keyring.c	T{
+...#ensure keyring i/o functions return "failure" as intended (improves diagnostic of login/logind)
+...#.br
+...#T}
+...#/interp/math.c	T{
+...#min -> minimum (to avoid clash with C macro)
+...#.br
+...#T}
+...#/interp/runt.c	T{
+...#check for nil arrays in utf functions, and negative offsets
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/interp/string.c	T{
+...#msize -> hmsize
+...#.br
+...#T}
+...#/interp/tk.c	T{
+...#cursor switching between apps
+...#.br
+...#T}
+...#/interp/validstk.c	T{
+...#msize -> hmsize
+...#.br
+...#T}
+...#/interp/xec.c	T{
+...#check that slice offset isn't negative
+...#.br
+...#T}
+...#/kern	T{
+...#new function utfecpy, added to directory and mkfile
+...#.br
+...#strchr, strrchr argument -> int not char
+...#.br
+...#T}
+...#/kfs	T{
+...#replace DEBUG by KFSDEBUG
+...#.br
+...#remove obsolete malloc definition
+...#.br
+...#ensure HFILES includes emu dat.h and fns.h
+...#.br
+...#T}
+...#/lib9/errstr-*	T{
+...#add support for buffer limit to oserrstr
+...#.br
+...#T}
+...#/lib9	T{
+...#exits argument shouldn't be const
+...#.br
+...#add utfecpy
+...#.br
+...#remove log-* and logging stuff from print.c
+...#.br
+...#remove printcol from doprint.c
+...#.br
+...#T}
+...#/man/1/gettar	T{
+...#document lstar's format
+...#.br
+...#T}
+...#/man/*	T{
+...#extraneous/incorrect cross-references corrected
+...#.br
+...#T}
+...#/usr/inferno/mkfile	T{
+...#-Inferno -> -Plan9 for several things
+...#.br
+...#(because of HOSTMODEL/TARGMODEL change)
+...#.br
+...#mkfile-Plan9-* TARGMODEL -> Plan9 not Inferno
+...#.br
+...#T}
+...#/os/ip/ip.c	T{
+...#adjust length after options stripped
+...#.br
+...#T}
+...#/os/ip/kernel.h	T{
+...#strrchr char -> int
+...#.br
+...#T}
+...#/os/port/alloc.c	T{
+...#int -> ulong in sizes
+...#.br
+...#same memory allocation conventions as /emu/alloc.c (re sizing, quanta)
+...#.br
+...#strip last aspects of audit
+...#.br
+...#other changes similar to /emu/alloc.c
+...#.br
+...#T}
+...#/appl/acme	T{
+...#raise an non-nil exception, not empty string
+...#.br
+...#T}
+...#/appl/charon	T{
+...#error when no window manager running
+...#.br
+...#cookies code being added/improved
+...#.br
+...#java script fixes/enhancements
+...#.br
+...#T}
+...#/appl/cmd/install/install.b	global is default now
+...#/appl/cmd/install/wrap.b	extra package name check
+...#/appl/cmd/sh	code tidy up
+...#/appl/ebook	ongoing changes
+...#/appl/lib/dis.b	offset from fp to mp fix
+...#/appl/lib/dividers.b	extra bind command to fix dividers issue
+...#/appl/lib/ecmascript.b	T{
+...#parsing of '/' improved (division or start of
+...#regular expression)
+...#.br
+...#T}
+...#/appl/lib/parseman.b	extra troff commands accounted for
+...#/appl/lib/profile.b	bind of #P only if needed
+...#/appl/lib/translate.b	hash code fix
+...#/appl/wm/c4.b	evaluation function improvement
+...#/appl/wm/pen.b	namechan() call moved to fix bug
+...#/appl/wm/polyhedra.b	cosmetic changes
+...#/appl/wm/readmail.b	slight code improvements
+...#/appl/wm/sendmail.b	ditto
+...#/man/1/ebook	text improvements
+...#/man/1/sh-std	ditto
+...#/man/1/sum	sha1sum added
+...#/man/2/keyring	hmac_sha1, hmac_md5 added
+...#/man/3/kprof	slight rewrite
+...#/man/4/export	9export added
+...#/man/6/translate	new BUGS section comment
+...#/man/9/button	padx, pady removed
+...#/man/9/canvas	added grab commands
+...#/module/keyring.m	added hmac routines
+...#/module/sys.m	added DM* constants for future use
+...#/emu/devcon.c	T{
+...#caphash and capuse files added for future
+...#development
+...#.br
+...#T}
+...#/emu/dis.c	added Enomem check to broken progs
+...#/emu/exception.c	added couple of extra string checks
+...#/emu/exportfs.c	T{
+...#nexterror() replaced by return to give
+...#better error recovery
+...#.br
+...#T}
+...#/emu/os-Nt.c	prints on console when ran out of kernel processes
+...#image/bezier.c	getbezsplinepts() added
+...#interp/comp-arm.c	headm bug fix, removed dodgy code
+...#interp/comp-power.c	removed dodgy code
+...#interp/comp-thumb.c	headm bug fix, removed dodgy code
+...#interp/keyring.c	T{
+...#generalization of certain keyring functions
+...#.br
+...#addition of hmac routines
+...#.br
+...#T}
+...#interp/tk.c	tkcursorcmd() removed temporarily
+...#/os/ip/devip.c	ipremove() replaced by devremove()
+...#/os/ip/ip.c	fragoff now a ulong
+...#/os/ip/tcp.c	extra safety checks
+...#/os/port/devcons.c	caphash and capuse files added
+...#/os/port/devkprof.c	general improvements
+...#/os/port/dis.c	Enomem check on broken progs
+...#/os/port/exception.c	added couple of extra string checks
+...#/os/port/exportfs.c	T{
+...#nexterror() replaced by return to give
+...#better error recovery
+...#.br
+...#check against correct file offset when reading directories
+...#.br
+...#T}
+...#/os/port/utils.c	parsefields(), stroll() removed
+...#/tk/canvs.c	T{
+...#extensions to tk: grab set tag, grab release tag,
+...#.br
+...#grab ifunset tag
+...#.br
+...#T}
+...#/tk/ctext.c	T{
+...#text widget tag highlight fix
+...#text widget tag index fix
+...#.br
+...#T}
+...#/tk/entry.c	borderwidth default to 0 in entry widget
+...#/tk/menus.c	menu button release fix (off by the borderwidth bug)
+...#/tk/scrol.c	T{
+...#scrollbar selection fixes (off by 1 bugs)
+...#.br
+...#autorepeat code added but disabled
+...#.br
+...#T}
+...#/tk/utils.c	tkinsidepoly() function
+...#/tk/xdata.c	unused globals removed
+...#/tk/*	T{
+...#draw methods take extra parameter
+...#.br
+...#hit methods added
+...#.br
+...#tkcfirsttag(), tkclasttag() fixes
+...#.br
+...#tkrunpack() argument type change
+...#.br
+...#T}
+...#.TE
binary files /dev/null b/doc/20020628.pdf differ
--- /dev/null
+++ b/doc/20020715.ms
@@ -1,0 +1,1033 @@
+.TL
+Inferno 3rd Edition \- 15 July 2002 Experimental Update
+.br
+Release Notes
+.AI
+Vita Nuova
+support@vitanuova.com
+.br
+15 July 2002
+.SP 4
+.NH 1
+Base for update
+.LP
+This experimental set of updates applies to the 18 June 2001 base.
+The installed software must therefore be that of 18 June 2001, whether installed directly,
+or the result of updating the original July 2000 release with update packages to the
+18 June 2001 level.
+This set of updates can be applied, however, whether or not the previous updates
+of 3 October 2001 and 28 June 2002 were installed; this package includes all those changes too.
+.NH 1
+Contents
+.LP
+This update offers the following, compared to the 28 June 2002 update.
+.LP
+The main change is that the Plan 9 hosted implementation supports Plan9 Fourth Edition.
+This has affected the portability interface for both hosted and native software.
+That, and the introduction of `lexical names' into
+.I emu
+causes this update to be classified as `experimental'.
+.LP
+The following sections provide short
+summaries of the more interesting or important changes.
+There are many more minor or cosmetic changes.
+.SH
+.I "New commands and modules"
+.SH
+.I "Repairs and changes"
+.IP \(bu
+.CW cp
+has been reworked extensively; amongst other things, it can now safely traverse
+arbitrary name spaces without becoming confused by
+complex mounts.
+.IP \(bu
+.I Listen (1)
+and
+.CW dial
+both accept a
+.CW -A
+option to cause it to authenticate a connection.
+.IP \(bu
+.I Diff (1)
+compares binary files and also does not quit (during recursive diffs) when it finds
+a file it cannot open.
+.IP \(bu
+.I Ls (1)
+implements the
+.CW -u
+and
+.CW -t
+sorting operations properly.
+A new
+.CW -e
+option prints the time as a decimal integer (seconds since the system Epoch).
+.IP \(bu
+.I Sh
+regards all of `../', `./', and `#' at the front of a command name as a request to use the name as-is.
+.IP \(bu
+.I Tail
+has been changed to avoid some boundary cases.
+.IP \(bu
+.I Touch
+uses standard argument processing and returns an error exit status if it fails.
+.IP \(bu
+.I Zeros
+accepts new options
+.CW -r
+to generate random bytes
+and
+.CW -v
+to produce blocks with a given value.
+.IP \(bu
+The network games software in
+.CW /appl/games
+uses port 6660 for its signer, not the standard Inferno signer's port.
+.IP \(bu
+.I Charon :
+disguises itself as Mozilla to satisfy agent-name probes; retries fetches on error; supports multiple windows;
+detects HTML vs plain text correctly; has many Javascript fixes, including fixing a day one bug
+in operator precedence (!).
+In general, it
+has undergone extensive changes,
+particularly to the cookies and Javascript implementation.
+It also insists that it be run under the window manager
+.I wm (1).
+It can be set to plumb schemes that it does not implement internally.
+.IP \(bu
+The installation software now uses the numeric time as-is to name output packages;
+the temporary fix introduced in Ocotober of converting  leading
+.CW 10
+to
+.CW A
+has been removed.
+.IP \(bu
+.CW /appl/lib/dis.b
+prints offsets from
+.CW MP
+correctly (it previously printed them
+as offsets from
+.CW FP ).
+.IP \(bu
+.CW /appl/lib/parseman.b
+accounts for enough extra
+.I troff
+commands to display
+.I man (6)
+correctly.
+.IP \(bu
+.CW /appl/lib/profile.b
+binds
+.CW #P
+only if needed.
+.IP \(bu
+.CW /appl/lib/translate.b
+.I translate (2)) (
+now computes the right hash value.
+.IP \(bu
+Several run-time checks that were missing or incomplete for array access and slicing have been added.
+.IP \(bu
+.CW lib/isrv
+no longer starts a new shell.
+.IP \(bu
+.I Wm-ftree (1)
+has several new options:
+.CW -E ,
+.CW -p
+and
+.CW -d .
+.IP \(bu
+.CW wm/rt
+now correctly updates stack size (if set).
+.IP \(bu
+.I Xd (1)
+correctly implements
+.CW -r
+to suppress repeated lines.
+.IP \(bu
+.I gettar (1)
+documents the
+.B lstar
+output format
+.IP \(bu
+.I man (6)
+describes the manual page documentation format
+.SH
+.I "Interface changes and extensions"
+.IP \(bu
+.I Security-password (2)
+provides a new entry
+.CW setpwfile
+to allow the default name
+.CW /keydb/password
+to be changed.
+.IP \(bu
+.I Dossrv (4)
+has changed extensively, to support rename and long names in FAT format correctly.
+It uses a smaller number of IO buffers.
+.IP \(bu
+.I Createsignerkey (8)
+has a completely different invocation, documented in that manual page,
+with a conventional option structure replacing a rather idiosyncratic chain
+of optional arguments.
+The old syntax is temporarily secretly still supported, but only
+for the benefit of any shell scripts that might so use it; if you have any,
+please change them to use the new syntax before the old usage finally vanishes in a later release.
+.IP \(bu
+.I Sum (1)
+documents the new
+.CW sha1sum
+command.
+.IP \(bu
+.I Bufio (2)
+returns an error if a seek fails rather than stopping the process(!).
+.IP \(bu
+.CW /lib/convcs
+has several more character sets:
+.CW koi8-r ,
+.CW windows-1250
+and
+.CW windows-1252 .
+.IP \(bu
+.I Keyring-sha (2)
+documents two new functions,
+.CW hmac_sha1
+and
+.CW hmac_md5 ,
+which are keyed versions of the corresponding secure hashing functions,
+as defined by RFC2104.
+The new definitions are in
+.CW /module/keyring.m .
+.IP \(bu
+.I Keyring-getstring (2)
+makes it clear that it does not
+.I provide
+delimited I/O but rather
+.I requires
+it (eg, as provided by
+.I ssl (3))
+for successful operation.
+.IP \(bu
+.I Security-ssl (2)
+no longer requires
+.CW #D
+to be bound into the name space (since it can only be used locally in any case).
+Consequently,
+.CW bind
+calls have been removed from several modules that used SSL.
+.IP \(bu
+.CW /appl/lib/crypt/ssl3.b
+has several critical bug fixes, allowing secure connections to work correctly in Charon;
+an important bug fix was also made to
+.CW /appl/lib/crypt/x509.b .
+.IP \(bu
+.I Imageremap
+has been changed to allow concurrent use.
+.IP \(bu
+.I Translate (6)
+and
+.CW /appl/lib/translate.b
+have changed as required to put the locale-specific dictionaries in directory
+\f(CW/locale/\fP\fIlocale\f(CW/dict\fP;
+the directory for a chosen
+.I locale
+is then normally bound onto
+.CW /locale/dict ,
+where
+.CW translate
+looks by default.
+.IP \(bu
+The documentation for
+.I button (9)
+no longer claims that
+.CW -padx
+and
+.CW -pady
+are supported options for that widget.
+.IP \(bu
+.CW sys.m
+has some new constants defined for use by a later Styx revision.
+.SH
+.I "Tk changes and extensions"
+.IP \(bu
+The canvas code provides extensions to Tk:
+.CW "grab set tag" ,
+.CW "grab release tag" ,
+and
+.CW "grab ifunset tag" .
+See
+.I canvas (9)
+for details.
+.IP \(bu
+Also in canvases, object-specific hit tests have been added, rather than using a bounding box
+in most cases.
+.IP \(bu
+Borderwidth defaults to zero in the entry widget.
+.IP \(bu
+Tk multiplexes the cursor amongst top-level windows.
+.IP \(bu
+Text and other items selected use foreground/background colours
+.SH
+.I "Limbo compiler"
+.IP \(bu
+Constant tuple and adt values can be used as values in
+.CW con
+constant declarations.
+.IP \(bu
+In an array value, the use of reference values for different
+.CW pick
+alternatives of the same adt no longer draws a diagnostic
+but causes the array value to be an array of
+.CW ref
+to the adt, not a particular pick alternative.
+.IP \(bu
+The C language stub declarations support
+.CW pick
+adts.
+.IP \(bu
+The alignment of
+.CW big
+and
+.CW real
+is now correct in C stubs.
+.IP \(bu
+The string escape
+.CW \ef
+is form-feed (to simplify translation of C programs).
+.SH
+.I "Compilers and utilities"
+.IP \(bu
+.I Iar 's
+source directory has been renamed from
+.CW ar
+to
+.CW iar .
+.IP \(bu
+.CW mk
+understands the long-name table in Windows' archive files, preventing
+spurious out-of-date status and other confusing results in builds.
+.IP \(bu
+.CW sqz
+and
+.CW zqs
+can compress larger ARM and PowerPC executables.
+.IP \(bu
+.CW kprof
+uses a table now provided by
+.CW /dev/kprof
+to provide profiling results to the resolution selected by a given platform.
+.SH
+.I "Hosted and Native Inferno"
+.LP
+Changes common to hosted and native kernels:
+.IP \(bu
+The
+.CW HOSTMODEL
+and
+.CW TARGMODEL
+for Plan 9 are now
+.CW Plan9
+not, rather confusingly,
+.CW Inferno .
+A good few source files have been renamed accordingly.
+.IP \(bu
+The memory allocation functions have been modified slightly to support the addition of
+memory monitoring and profiling.
+Some functions have also been added to the C library supporting
+.I emu
+and the kernels,
+with an eye to starting the revision of Styx, based on the current 9P2000.
+Consequently, the
+include file
+.CW lib9.h
+for all platforms has been modified:
+to add new functions such as
+.CW setmalloctag ;
+to make the types of parameters to the
+.CW malloc
+calls uniform (and reflect the documentation, as it happens),
+so that sizes are always unsigned;
+to change the type of a parameter to
+.CW strchr
+and
+.CW strrchr
+from
+.CW char
+to
+.CW int ;
+to remove obsolete definitions such as
+.CW UMFILE
+and
+.CW UMDIR ;
+and to add new functions for use inside the kernels.
+Several new functions are strictly for internal use
+(and thus might change in future), and
+they have not been added to section 10.
+One exception is the new function
+.CW tokenize ,
+documented in
+.I getfields (10.2)
+and used by
+.I parsecmd (10.2).
+.I Getfields
+replaces the function called
+.CW parsefields ,
+which has been removed, and all calls to it changed to use
+.CW getfields .
+The higher aim of some of these otherwise fussy changes is
+to work towards making Inferno and Plan 9 drivers interchangeable
+(as best we can).
+.IP \(bu
+To help decouple authentication methods from identity setting, two new files
+.CW caphash
+and
+.CW capuse
+have been added to
+.CW #c
+(a temporary location for them), supported by code in
+.CW auth.c
+.CW /os/port/auth.c ). (
+Their use will soon replace the
+.CW setid
+functionality of
+.I keyring-auth .
+They will not be documented until then.
+.IP \(bu
+.CW /emu/exception.c
+and
+.CW /os/port/exception.c
+no longer trap the use of the
+.CW exit
+statement (by accident of implementation).
+.CW \(bu
+.CW /emu/dis.c
+and
+.CW /os/port/dis.c
+do not leave a process in Broken state when it
+receives an exception because a kernel memory allocation failed.
+.IP \(bu
+The JIT compilation of case statements has fixed a day one bug
+that caused a degenerate form of
+.CW case
+(with only a default arm) to be compiled incorrectly.
+.IP \(bu
+The 386 JIT will allow rescheduling, and the scheduling is finer grained on the ARM.
+.IP \(bu
+ARM code generation produces correct code for some list accesses that were previously wrong
+(the Dis operator HEADM)
+.IP \(bu
+.I Emu
+has the following changes specific to it:
+.RS
+.IP \-
+The mouse event queue in
+.CW devcon.c
+is now a circular queue without locks as in the native kernel;
+this prevents a scheduling problem under Linux.
+.IP \-
+The
+.CW READSTR
+constant defined by the native kernels is now also defined by
+.CW emu .
+.IP \-
+The function previously called
+.CW rendezvous
+is now called
+.CW erendezvous
+to avoid a type clash with a library function on Plan 9
+(its `rendezvous' function takes an unsigned long as first parameter, not
+.CW void* ).
+.CW lib9.h
+has changed accordingly where required.
+.IP \-
+.CW devcon.c
+acquires
+.CW caphash
+and
+.CW capuse .
+.IP \-
+A new file
+.CW auth.c
+must be included in every build.
+.IP \-
+Several drivers in
+.CW emu
+have been changed to use
+.RS
+.P1
+	switch((ulong)c->qid.path ...)
+.P2
+.RE
+to force 32-bit operations to be used when
+.CW path
+eventually becomes 64 bits.
+.IP \-
+Also in
+.CW emu
+the function
+.CW oserrstr
+now takes a buffer length, rather than assuming
+.CW ERRLEN .
+.IP \-
+Obsolete code for time and directory mode conversions (!) has been removed from
+.CW os-*.c .
+.IP \-
+Obsolete code for `daemonize' has been removed from
+.CW os-*.c
+and
+.CW lib9 .
+.RE
+.IP \(bu
+For the native kernels:
+.RS
+.IP \-
+.CW /os/port/devprof.c
+has been added but is not yet supported (it is not configured in to any kernel,
+so no existing kernels are affected by its presence).
+.IP \-
+.CW /os/port/devcons.c
+has
+.CW caphash
+and
+.CW capuse
+.IP \-
+Every kernel configuration file must now include
+.CW auth
+in the
+.CW port
+section to include
+.CW /os/port/auth.c .
+.RE
+...#.bp
+...#.NH 1
+...#Description by source file
+...#.LP
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/appl/charon	T{
+...#plumbs schemes that aren't built-in, if on an authorised list
+...#.br
+...#retries on error (but not POST)
+...#.br
+...#identifies itself as Mozilla to pass agent-name tests.
+...#.br
+...#bug fix: doesn't loop (exhausting memory) if a file ends with bad data.
+...#.br
+...#private version of Url
+...#.br
+...#CCI removed
+...#.br
+...#charon_code and charon_guiwm removed
+...#.br
+...#multiple windows
+...#.br
+...#detects HTML vs text correctly
+...#.br
+...#separate layout and gui display
+...#.br
+...#T}
+...#/appl/cmd/diff.b	T{
+...#compare binary files as documented
+...#.br
+...#don't quit if files can't be opened
+...#.br
+...#T}
+...#/appl/cmd/strings.b	T{
+...#new command
+...#.br
+...#T}
+...#/appl/cmd/sh	T{
+...#../ / ./ and # starting a (command) name all cause it to be treated as absolute
+...#.br
+...#T}
+...#/appl/lib/auth.b	T{
+...#allow nobody even if setid is 0 provided it appears in the algorithm list
+...#.br
+...#don't bind #D
+...#.br
+...#T}
+...#/appl/lib/createsignerkey.b	T{
+...#arguments
+...#.br
+...#don't bother with random
+...#.br
+...#error status
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/appl/lib/crypt/ssl3.b	T{
+...#delete session id on alert
+...#.br
+...#T}
+...#/appl/lib/ecmascript	T{
+...#correct precedence for operators
+...#.br
+...#delete HTML comments
+...#.br
+...#T}
+...#/appl/lib/isrv.b	T{
+...#don't start a new shell
+...#.br
+...#T}
+...#/appl/lib/login.b	T{
+...#don't bind #D
+...#.br
+...#T}
+...#/appl/lib/logind.b	T{
+...#don't bind #D
+...#.br
+...#don't load (unused) Random
+...#.br
+...#minor internal changes.
+...#.br
+...#T}
+...#/appl/lib/profile.b	T{
+...#memory profiling
+...#.br
+...#T}
+...#/appl/lib/srv.b	T{
+...#be sure to FORKFD so file descriptors don't accumulate in parent
+...#.br
+...#T}
+...#/appl/lib/ssl.b	T{
+...#don't require #D to be bound since it can only be used locally
+...#.br
+...#T}
+...#/appl/lib/usb/*	T{
+...#see TI925 release
+...#.br
+...#T}
+...#/appl/lib/wmlib.b	T{
+...#calculate correct size of file browser (eg when full screen)
+...#.br
+...#don't mess with the cursor
+...#.br
+...#T}
+...#/appl/minicharon	T{
+...#moan if no window manager
+...#.br
+...#don't trap if module not yet loaded
+...#.br
+...#T}
+...#/appl/wm/bounce.b
+...#/appl/wm/man.b
+...#/appl/wm/mand.b
+...#/appl/wm/polyhedra.b
+...#/appl/wm/wm.b	T{
+...#correct window size in full screen mode
+...#.br
+...#T}
+...#/appl/wm/reversi.b	T{
+...#use fittoscreen(0)
+...#.br
+...#T}
+...#/appl/wm/polyhedra.b	T{
+...#sys->sleep(0) to yield
+...#.br
+...#T}
+...#/man/2/security-ssl	T{
+...#bind not required
+...#.br
+...#conventions documented accurately
+...#.br
+...#T}
+...#/man/2/keyring-getstring	T{
+...#makes it clear that it doesn't PROVIDE delimited i/o, but EXPECTS it (eg, via ssl(3))
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/crypt/jacobi.c	T{
+...#add missing return statement
+...#.br
+...#T}
+...#/emu/alloc.c	T{
+...#changes for monitoring
+...#.br
+...#long for size throughout
+...#.br
+...#poolrealloc, now used by malloc
+...#.br
+...#poolmsize
+...#.br
+...#malloc and realloc tagging data with pc of allocation
+...#.br
+...#ud -> lud etc
+...#.br
+...#T}
+...#/emu/chan.c	T{
+...#space isn't frog, experimentally
+...#.br
+...#T}
+...#/emu/dat.h	T{
+...#READSTR definition
+...#.br
+...#Rept definition (will change)
+...#.br
+...#add BusyGC
+...#.br
+...#remove support for %N
+...#.br
+...#T}
+...#/emu	T{
+...#oserrstr takes buffer size (consequential changes throughout)
+...#.br
+...#no %N
+...#.br
+...#Plan 9's HOSTMODEL -> Plan9 not Inferno (!)
+...#.br
+...#msize -> hmsize in some cases
+...#.br
+...#rendezvous -> erendezvous
+...#.br
+...#T}
+...#/emu/devcon.c	T{
+...#no %N, Nconv
+...#.br
+...#remove debugging memout file
+...#.br
+...#use of (ulong)c->qid.path ...
+...#.br
+...#remove logmsg calls
+...#.br
+...#T}
+...#/emu/devprof.c	T{
+...#memory profiling
+...#.br
+...#T}
+...#/emu/devprog.c	T{
+...#msize -> hmsize because malloc and heap addresses are different
+...#.br
+...#T}
+...#/emu/dis.c	T{
+...#instrument garbage collections
+...#.br
+...#force periodic garbage collection passes when not idle (BusyGC)
+...#.br
+...#T}
+...#/emu/discall.c	T{
+...#tag QLock structures with owner
+...#.br
+...#T}
+...#/emu/fns.h	T{
+...#oserrstr definition
+...#.br
+...#obsolete gsleep defn removed
+...#.br
+...#T}
+...#/emu/main.c	T{
+...#obsolete gsleep defn removed
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/emu/os-*	T{
+...#dflag becomes simply don't enable graphics terminal (ie, save/restore tty state)
+...#.br
+...#daemonize calls removed [do it from outside]
+...#.br
+...#rendezvous -> erendezvous
+...#.br
+...#some files had obsolete timeconv and dirmodconv code, now removed
+...#.br
+...#T}
+...#/emu/proc.c	T{
+...#provisional rpt code (will change, will move)
+...#.br
+...#T}
+...#/emu/vlrt-Nt.c	T{
+...#use dat.h not local definitions
+...#.br
+...#T}
+...#/include/interp.h	T{
+...#force HEAP_ALIGN to provide extra cell in heap header for heap profiling
+...#.br
+...#new functions: heapmonitor, hmsize
+...#.br
+...#utfnlen removed  (local to interp/runt.c)
+...#.br
+...#T}
+...#/include/pool.h	T{
+...#sizes are now unsigned
+...#.br
+...#poolcompact defn, new poolmsize, poolrealloc
+...#.br
+...#T}
+...#/include/tk.h	T{
+...#extra state to control cursor
+...#.br
+...#T}
+...#/interp/comp-386.c	T{
+...#implement and enable interpreter rescheduling when JIT enabled
+...#.br
+...#T}
+...#/interp/comp-arm.c
+...#/interp/comp-thumb.c	T{
+...#change arm rescheduling check to be similar to 386
+...#.br
+...#T}
+...#/interp/gc.c	T{
+...#instrument garbage collector
+...#.br
+...#add heapmonitor hook for devmem.c
+...#.br
+...#T}
+...#/interp/heap.c	T{
+...#define heapmonitor hook (default: nil)
+...#.br
+...#call it at appropriate places
+...#.br
+...#change // to /* comment
+...#.br
+...#add hmsize to account for alloc.c changes
+...#.br
+...#T}
+...#/interp/keyring.c	T{
+...#ensure keyring i/o functions return "failure" as intended (improves diagnostic of login/logind)
+...#.br
+...#T}
+...#/interp/math.c	T{
+...#min -> minimum (to avoid clash with C macro)
+...#.br
+...#T}
+...#/interp/runt.c	T{
+...#check for nil arrays in utf functions, and negative offsets
+...#.br
+...#T}
+...#.TE
+...#.TS
+...#lf(CW)w(2.5i) lf(R)w(4i) .
+...#/interp/string.c	T{
+...#msize -> hmsize
+...#.br
+...#T}
+...#/interp/tk.c	T{
+...#cursor switching between apps
+...#.br
+...#T}
+...#/interp/validstk.c	T{
+...#msize -> hmsize
+...#.br
+...#T}
+...#/interp/xec.c	T{
+...#check that slice offset isn't negative
+...#.br
+...#T}
+...#/kern	T{
+...#new function utfecpy, added to directory and mkfile
+...#.br
+...#strchr, strrchr argument -> int not char
+...#.br
+...#T}
+...#/kfs	T{
+...#replace DEBUG by KFSDEBUG
+...#.br
+...#remove obsolete malloc definition
+...#.br
+...#ensure HFILES includes emu dat.h and fns.h
+...#.br
+...#T}
+...#/lib9/errstr-*	T{
+...#add support for buffer limit to oserrstr
+...#.br
+...#T}
+...#/lib9	T{
+...#exits argument shouldn't be const
+...#.br
+...#add utfecpy
+...#.br
+...#remove log-* and logging stuff from print.c
+...#.br
+...#remove printcol from doprint.c
+...#.br
+...#T}
+...#/man/1/gettar	T{
+...#document lstar's format
+...#.br
+...#T}
+...#/man/*	T{
+...#extraneous/incorrect cross-references corrected
+...#.br
+...#T}
+...#/usr/inferno/mkfile	T{
+...#-Inferno -> -Plan9 for several things
+...#.br
+...#(because of HOSTMODEL/TARGMODEL change)
+...#.br
+...#mkfile-Plan9-* TARGMODEL -> Plan9 not Inferno
+...#.br
+...#T}
+...#/os/ip/ip.c	T{
+...#adjust length after options stripped
+...#.br
+...#T}
+...#/os/ip/kernel.h	T{
+...#strrchr char -> int
+...#.br
+...#T}
+...#/os/port/alloc.c	T{
+...#int -> ulong in sizes
+...#.br
+...#same memory allocation conventions as /emu/alloc.c (re sizing, quanta)
+...#.br
+...#strip last aspects of audit
+...#.br
+...#other changes similar to /emu/alloc.c
+...#.br
+...#T}
+...#/appl/acme	T{
+...#raise an non-nil exception, not empty string
+...#.br
+...#T}
+...#/appl/charon	T{
+...#error when no window manager running
+...#.br
+...#cookies code being added/improved
+...#.br
+...#java script fixes/enhancements
+...#.br
+...#T}
+...#/appl/cmd/install/install.b	global is default now
+...#/appl/cmd/install/wrap.b	extra package name check
+...#/appl/cmd/sh	code tidy up
+...#/appl/ebook	ongoing changes
+...#/appl/lib/dis.b	offset from fp to mp fix
+...#/appl/lib/dividers.b	extra bind command to fix dividers issue
+...#/appl/lib/ecmascript.b	T{
+...#parsing of '/' improved (division or start of
+...#regular expression)
+...#.br
+...#T}
+...#/appl/lib/parseman.b	extra troff commands accounted for
+...#/appl/lib/profile.b	bind of #P only if needed
+...#/appl/lib/translate.b	hash code fix
+...#/appl/wm/c4.b	evaluation function improvement
+...#/appl/wm/pen.b	namechan() call moved to fix bug
+...#/appl/wm/polyhedra.b	cosmetic changes
+...#/appl/wm/readmail.b	slight code improvements
+...#/appl/wm/sendmail.b	ditto
+...#/man/1/ebook	text improvements
+...#/man/1/sh-std	ditto
+...#/man/1/sum	sha1sum added
+...#/man/2/keyring	hmac_sha1, hmac_md5 added
+...#/man/3/kprof	slight rewrite
+...#/man/4/export	9export added
+...#/man/6/translate	new BUGS section comment
+...#/man/9/button	padx, pady removed
+...#/man/9/canvas	added grab commands
+...#/module/keyring.m	added hmac routines
+...#/module/sys.m	added DM* constants for future use
+...#/emu/devcon.c	T{
+...#caphash and capuse files added for future
+...#development
+...#.br
+...#T}
+...#/emu/dis.c	added Enomem check to broken progs
+...#/emu/exception.c	added couple of extra string checks
+...#/emu/exportfs.c	T{
+...#nexterror() replaced by return to give
+...#better error recovery
+...#.br
+...#T}
+...#/emu/os-Nt.c	prints on console when ran out of kernel processes
+...#image/bezier.c	getbezsplinepts() added
+...#interp/comp-arm.c	headm bug fix, removed dodgy code
+...#interp/comp-power.c	removed dodgy code
+...#interp/comp-thumb.c	headm bug fix, removed dodgy code
+...#interp/keyring.c	T{
+...#generalization of certain keyring functions
+...#.br
+...#addition of hmac routines
+...#.br
+...#T}
+...#interp/tk.c	tkcursorcmd() removed temporarily
+...#/os/ip/devip.c	ipremove() replaced by devremove()
+...#/os/ip/ip.c	fragoff now a ulong
+...#/os/ip/tcp.c	extra safety checks
+...#/os/port/devcons.c	caphash and capuse files added
+...#/os/port/devkprof.c	general improvements
+...#/os/port/dis.c	Enomem check on broken progs
+...#/os/port/exception.c	added couple of extra string checks
+...#/os/port/exportfs.c	T{
+...#nexterror() replaced by return to give
+...#better error recovery
+...#.br
+...#check against correct file offset when reading directories
+...#.br
+...#T}
+...#/os/port/utils.c	parsefields(), stroll() removed
+...#/tk/canvs.c	T{
+...#extensions to tk: grab set tag, grab release tag,
+...#.br
+...#grab ifunset tag
+...#.br
+...#T}
+...#/tk/ctext.c	T{
+...#text widget tag highlight fix
+...#text widget tag index fix
+...#.br
+...#T}
+...#/tk/entry.c	borderwidth default to 0 in entry widget
+...#/tk/menus.c	menu button release fix (off by the borderwidth bug)
+...#/tk/scrol.c	T{
+...#scrollbar selection fixes (off by 1 bugs)
+...#.br
+...#autorepeat code added but disabled
+...#.br
+...#T}
+...#/tk/utils.c	tkinsidepoly() function
+...#/tk/xdata.c	unused globals removed
+...#/tk/*	T{
+...#draw methods take extra parameter
+...#.br
+...#hit methods added
+...#.br
+...#tkcfirsttag(), tkclasttag() fixes
+...#.br
+...#tkrunpack() argument type change
+...#.br
+...#T}
+...#.TE
+.ig
+lib9.h all changed
+Storeinc and IEEE FP parameters default in math/dtoa.c
+Fconv -> Fmt
+doprint -> vseprint
+errstr -> add int size
+icossin, icossin2 -> image.h
+with ICOSSCALE
+Plan9 hosted include files different structure:
+Dir9p1 and Qid9p1
+#define	Dir	Dir9p1
+Fourth Edition system call interface
+except for Dir* functions
+under ifdef Inferno4, Qid -> Qid9p1, dirstat -> v3dirstat, etc.
+and those map
+Dir.length -> vlong
+Plan9 hosted include files quite different.
+#endif
+Styx module (styx(2)), dossrv, cdfs, acme all use it
+getcallerpc-$SYSTARG-$OBJTYPE.$O
+getwd-posix.$O
+lock-*.$O
+some types long -> int, some int ->long
+all conversion functions change
+detachscreen
+null if-else body
+main should call quotefmtinstall()
+..
+pc: draw screen; screen.$O removed from mkfile
+pc/mouse.c -> pc/ps2mouse.c
+pc config files updated to new ip stack
+dbg references removed/commented out.
+ether2114x driver provided
+env added
+fault removed
+emu and port print.c
+bug in native/hosted directory reading
+lexical names
+pctl etc more efficient for non-blocking ones
+solaris sets sa_handler not sa_sigaction for sigILL
--- /dev/null
+++ b/doc/INSTALL1.ms
@@ -1,0 +1,148 @@
+.\" this is an extract of port.ms: change that too if needed
+.pl 9999
+.SH
+Installing hosted Inferno from source
+.SH
+Overview
+.PP
+Like the native kernels
+.CW emu
+relies on several auxiliary libraries (the source of which
+it often shares with the native kernels).
+Emu itself is built by the
+.CW mkfile
+in the
+.CW emu
+subdirectory containing the platform-specific source for the host platform.
+Each library has its own
+.CW mkfile ;
+the various components are made in the right order by the
+.CW mkfile
+at the root of the Inferno tree.
+The
+.CW mkfile
+for each platform will also invoke
+.CW mk
+recursively to make the appropriate libraries
+for a given configuration.
+.PP
+The Unix emu variant generally is covered by `POSIX' (with common extensions)
+but each Unix port has one file that differs considerably for each port,
+namely \f5emu/\fP\fIplatform\fP\f5/os.c\fP, the differences
+corresponding to the different ways under Unix of implementing kernel-scheduled
+threads efficiently.
+.PP
+There are working emu versions
+for
+FreeBSD/386,
+Irix/mips,
+Linux/386,
+NetBSD/386,
+MacOSX/386,
+MacOSX/power,
+Plan 9,
+Solaris/sparc,
+and Windows (NT, 2000 and Explorer plug-in).
+Each platform typically uses mechanisms specific to the host operating
+system to implement Inferno's internal thread/process structure.
+POSIX threads have often been found to be insufficient (poorly implemented)
+on some platforms, and if so are avoided.
+See
+.CW kproc
+in
+.CW emu/*/os.c .
+.PP
+Source is included for ports to HP/UX (S800 architecture),
+Solaris/386, and Unixware, in case someone wishes to take them up now,
+but we have not determined their fitness.
+.PP
+The Plan 9 hosted implementation is unusual in that it supports
+several processor types:
+.CW 386 ,
+.CW mips ,
+.CW power
+(Power PC)
+and
+.CW sparc .
+Furthermore, all versions of
+.CW emu
+can be built on any processor type, in the usual way for Plan 9.
+.PP
+Otherwise, as distributed,
+.CW emu
+for a platform can only be built when running on that platform.
+.PP
+One unusual variant makes the whole of Inferno a plug-in for Microsoft's
+Internet Explorer, giving the same environment for Inferno applications
+running in an HTML page as is provided by hosted or native Inferno.
+That is, there is not a distinct `applet' environment with special programming interfaces.
+The source for the various plug-in components is found in
+.CW /tools/plugin
+and
+.CW /usr/internet
+within the Inferno tree; they use the version of
+.I emu
+defined by the configuration file
+.CW /emu/Nt/ie .
+.SH
+Build steps
+.PP
+All the libraries and executables can be built in a tree containing only the source code.
+To do that for a supported variant of hosted Inferno, on Unix or Plan 9, do the following
+in the root of the Inferno tree:
+.nr Ci 0 +1
+.de Xx
+.IP \\n+(Ci
+..
+.Xx
+Edit
+.CW mkconfig
+to reflect your host environment,
+specifically ROOT (which must be an absolute path name), SYSHOST and OBJTYPE.
+The comments in the file should help you choose.
+.Xx
+Run
+.CW makemk.sh
+to rebuild the
+.CW mk
+command, which is used to build everything else.
+.Xx
+Set
+.CW PATH
+(or
+.CW path
+on Plan 9)
+to include the
+.CW bin
+directory for the platform, which will now contain the
+.CW mk
+binary just built.
+On Unix, export
+.CW PATH .
+.Xx
+Then
+.CW "mk nuke"
+to remove any extraneous object files.
+.Xx
+Finally,
+.CW "mk install"
+to create and install the libraries,
+.CW limbo
+compiler,
+.CW emu
+for hosted Inferno, and auxiliary commands.
+The rules do that in an order that ensures that the commands or libraries
+needed by a later stage are built and installed first.
+(Note that a plain
+.CW mk
+will not suffice, because it does not put the results in the search path.)
+.LP
+Doing something similar on Windows or Plan 9 currently requires the executable for
+.CW mk
+to be available in the search path,
+since there is no equivalent of
+.CW makemk.sh .
+Otherwise the procedure is the same.
+On Plan 9, of course, the host system's normal version of
+.CW mk
+should be adequate.
--- /dev/null
+++ b/doc/acid.ms
@@ -1,0 +1,2519 @@
+.am DS
+.ft I
+..
+.am DE
+.ft R
+..
+.ta 1i 2.3i 4.5i  (optional to set tabs)
+.TL
+Acid Reference Manual
+.AU
+Phil Winterbottom
+philw@plan9.bell-labs.com
+.FS
+\l'1i'
+.br
+Previously appeared with minor differences as the
+``Acid Manual'' in
+.I "Plan 9 Programmer's Manual, Volume 2 (Second Edition)".
+.FE
+.SH
+Introduction
+.PP
+Acid is a general purpose, source level symbolic debugger.
+The debugger is built around a simple command language. 
+The command language, distinct from the language of the program being debugged,
+provides a flexible user interface that allows the debugger
+interface to be customized for a specific application or architecture.
+Moreover, it provides an opportunity to write test and
+verification code independently of a program's source code.
+Acid is able to debug multiple
+processes provided they share a common set of symbols, such as the processes in
+a threaded program.
+.PP
+Like other language-based solutions, Acid presents a poor user interface but
+provides a powerful debugging tool.
+Application of Acid to hard problems is best approached by writing functions off-line
+(perhaps loading them with the
+.CW include
+function or using the support provided by
+.I acme (1)),
+rather than by trying to type intricate Acid operations
+at the interactive prompt.
+.PP
+Acid allows the execution of a program to be controlled by operating on its
+state while it is stopped and by monitoring and controlling its execution
+when it is running. Each program action that causes a change 
+of execution state is reflected by the execution
+of an Acid function, which may be user defined.
+A library of default functions provides the functionality of a normal debugger.
+.PP
+On Plan 9, a process is controlled by writing messages to a control file in the
+.I proc (3)
+file system. Each control message has a corresponding Acid function, which
+sends the message to the process. These functions take a process id
+.I pid ) (
+as an
+argument. The memory and text file of the program may be manipulated using
+the indirection operators. The symbol table, including source cross reference,
+is available to an Acid program. The combination allows complex operations
+to be performed both in terms of control flow and data manipulation.
+.SH
+Input format and \f(CWwhatis\fP
+.PP
+Comments start with
+.CW //
+and continue to the end of the line.
+Input is a series of statements and expressions separated by semicolons.
+At the top level of the interpreter, the builtin function
+.CW print
+is called automatically to display the result of all expressions except function calls.
+A unary
+.CW +
+may be used as a shorthand to force the result of a function call to be printed.
+.PP
+Also at the top level, newlines are treated as semicolons
+by the parser, so semicolons are unnecessary when evaluating expressions.
+.PP
+When Acid starts, it loads the default program modules,
+enters interactive mode, and prints a prompt. In this state Acid accepts
+either function definitions or statements to be evaluated.
+In this interactive mode
+statements are evaluated immediately, while function definitions are
+stored for later invocation.
+.PP
+The
+.CW whatis
+operator can be used to report the state of identifiers known to the interpreter.
+With no argument,
+.CW whatis
+reports the name of all defined Acid functions; when supplied with an identifier
+as an argument it reports any variable, function, or type definition
+associated with the identifier.
+Because of the way the interpreter handles semicolons,
+the result of a
+.CW whatis
+statement can be returned directly to Acid without adding semicolons.
+A syntax error or interrupt returns Acid to the normal evaluation
+mode; any partially evaluated definitions are lost.
+.SH
+Using the Library Functions
+.PP
+After loading the program binary, Acid loads the portable and architecture-specific
+library functions  that form the standard debugging environment.
+These files are Acid source code and are human-readable.
+The following example uses the standard debugging library to show how
+language and program interact:
+.P1
+% acid /bin/ls
+/bin/ls:mips plan 9 executable
+
+/sys/lib/acid/port
+/sys/lib/acid/mips
+acid: new()
+75721: system call  _main ADD  $-0x14,R29
+75721: breakpoint   main+0x4   MOVW  R31,0x0(R29)
+acid: bpset(ls)
+acid: cont()
+75721: breakpoint   ls    ADD  $-0x16c8,R29
+acid: stk()
+At pc:0x0000141c:ls /sys/src/cmd/ls.c:87
+ls(s=0x0000004d,multi=0x00000000) /sys/src/cmd/ls.c:87
+    called from main+0xf4 /sys/src/cmd/ls.c:79
+main(argc=0x00000000,argv=0x7ffffff0) /sys/src/cmd/ls.c:48
+    called from _main+0x20 /sys/src/libc/mips/main9.s:10
+acid: PC
+0xc0000f60
+acid: *PC
+0x0000141c
+acid: ls
+0x0000141c
+.P2
+The function
+.CW new()
+creates a new process and stops it at the first instruction.
+This change in state is reported by a call to the
+Acid function
+.CW stopped ,
+which is called by the interpreter whenever the debugged program stops.
+.CW Stopped
+prints the status line giving the pid, the reason the program stopped
+and the address and instruction at the current PC.
+The function
+.CW bpset
+makes an entry in the breakpoint table and plants a breakpoint in memory.
+The
+.CW cont
+function continues the process, allowing it to run until some condition
+causes it to stop. In this case the program hits the breakpoint placed on
+the function
+.CW ls
+in the C program. Once again the
+.CW stopped
+routine is called to print the status of the program. The function
+.CW stk
+prints a C stack trace of the current process. It is implemented using
+a builtin Acid function that returns the stack trace as a list; the code
+that formats the information is all written in Acid. 
+The Acid variable
+.CW PC
+holds the address of the 
+cell where the current value of the processor register
+.CW PC
+is stored. By indirecting through
+the value of
+.CW PC
+the address where the program is stopped can be found.
+All of the processor registers are available by the same mechanism.
+.SH
+Types
+.PP
+An Acid variable has one of four types:
+.I integer ,
+.I float ,
+.I list ,
+or
+.I string .
+The type of a variable is inferred from the type of the right-hand
+side of the assignment expression which last set its value.
+Referencing a variable that has not yet
+been assigned draws a "used but not set" error. Many of the operators may
+be applied to more than
+one type; for these operators the action of the operator is determined by
+the types of its operands. The action of each operator is defined in the
+.I Expressions
+section of this manual.
+.SH
+Variables
+.PP
+Acid has three kinds of variables: variables defined by the symbol table
+of the debugged program, variables that are defined and maintained
+by the interpreter as the debugged program changes state, and variables
+defined and used by Acid programs.
+.PP
+Some examples of variables maintained by the interpreter are the register
+pointers listed by name in the Acid list variable
+.CW registers ,
+and the symbol table listed by name and contents in the Acid variable
+.CW symbols .
+.PP
+The variable
+.CW pid
+is updated by the interpreter to select the most recently created process
+or the process selected by the
+.CW setproc
+builtin function.
+.SH 1
+Formats
+.PP
+In addition to a type, variables have formats. The format is a code
+letter that determines the printing style and the effect of some of the
+operators on that variable. The format codes are derived from the format
+letters used by
+.I db (1).
+By default, symbol table variables and numeric constants
+are assigned the format code
+.CW X ,
+which specifies 32-bit hexadecimal.
+Printing a variable with this code yields the output
+.CW 0x00123456 .
+The format code of a variable may be changed from the default by using the 
+builtin function
+.CW fmt .
+This function takes two arguments, an expression and a format code. After
+the expression is evaluated the new format code is attached to the result
+and forms the return value from
+.CW fmt .
+The backslash operator is a short form of
+.CW fmt .
+The format supplied by the backslash operator must be the format character
+rather than an expression.
+If the result is assigned to a variable the new format code is maintained
+in the variable. For example:
+.P1
+acid: x=10
+acid: print(x)
+0x0000000a 
+acid: x = fmt(x, 'D')
+acid: print(x, fmt(x, 'X'))
+10 0x0000000a
+acid: x
+10
+acid: x\eo
+12
+.P2
+The supported format characters are:
+.RS
+.IP \f(CWo\fP
+Print two-byte integer in octal.
+.IP \f(CWO\fP
+Print four-byte integer in octal.
+.IP \f(CWq\fP
+Print two-byte integer in signed octal.
+.IP \f(CWQ\fP
+Print four-byte integer in signed octal.
+.IP \f(CWB\fP
+Print four-byte integer in binary.
+.IP \f(CWd\fP
+Print two-byte integer in signed decimal.
+.IP \f(CWD\fP
+Print four-byte integer in signed decimal.
+.IP \f(CWY\fP
+Print eight-byte integer in signed decimal.
+.IP \f(CWx\fP
+Print two-byte integer in hexadecimal.
+.IP \f(CWX\fP
+Print four-byte integer in hexadecimal.
+.IP \f(CWu\fP
+Print two-byte integer in unsigned decimal.
+.IP \f(CWU\fP
+Print four-byte integer in unsigned decimal.
+.IP \f(CWZ\fP
+Print eight-byte integer in unsigned decimal.
+.IP \f(CWf\fP
+Print single-precision floating point number.
+.IP \f(CWF\fP
+Print double-precision floating point number.
+.IP \f(CWg\fP
+Print a single precision floating point number in string format.
+.IP \f(CWG\fP
+Print a double precision floating point number in string format.
+.IP \f(CWb\fP
+Print byte in hexadecimal.
+.IP \f(CWc\fP
+Print byte as an ASCII character.
+.IP \f(CWC\fP
+Like
+.CW c ,
+with
+printable ASCII characters represented normally and
+others printed in the form \f(CW\ex\fInn\fR.
+.IP \f(CWs\fP
+Interpret the addressed bytes as UTF characters
+and print successive characters until a zero byte is reached.
+.IP \f(CWr\fP
+Print a two-byte integer as a rune.
+.IP \f(CWR\fP
+Print successive two-byte integers as runes
+until a zero rune is reached.
+.IP \f(CWY\fP
+Print successive eight-byte integers in hexadecimal.
+.IP \f(CWi\fP
+Print as machine instructions.
+.IP \f(CWI\fP
+As
+.CW i
+above, but print the machine instructions in
+an alternate form if possible:
+.CW sunsparc
+and
+.CW mipsco
+reproduce the manufacturers' syntax.
+.IP \f(CWa\fP
+Print the value in symbolic form.
+.RE
+.SH
+Complex types
+.PP
+Acid permits the definition of the layout of memory.
+The usual method is to use the
+.CW -a
+flag of the compilers to produce Acid-language descriptions of data structures (see
+.I 2c (1))
+although such definitions can be typed interactively.
+The keywords
+.CW complex ,
+.CW adt ,
+.CW aggr ,
+and
+.CW union
+are all equivalent; the compiler uses the synonyms to document the declarations.
+A complex type is described as a set of members, each containing a format letter,
+an offset in the structure, and a name.  For example, the C structure
+.P1
+struct List {
+	int         type;
+	struct List *next;
+};
+.P2
+is described by the Acid statement
+.P1
+complex List {
+	'D'	0	type;
+	'X'	4	next;
+};
+.P2
+.SH
+Scope
+.PP
+Variables are global unless they are either parameters to functions
+or are declared as
+.CW local
+in a function body. Parameters and local variables are available only in
+the body of the function in which they are instantiated.
+Variables are dynamically bound: if a function declares a local variable
+with the same name as a global variable, the global variable will be hidden
+whenever the function is executing.
+For example, if a function
+.CW f
+has a local called
+.CW main ,
+any function called below
+.CW f
+will see the local version of
+.CW main ,
+not the external symbol.
+.SH 1
+Addressing
+.PP
+Since the symbol table specifies addresses,
+to access the value of program variables
+an extra level of indirection
+is required relative to the source code.
+For consistency, the registers are maintained as pointers as well; Acid variables with the names
+of processor registers point to cells holding the saved registers.
+.PP
+The location in a file or memory image associated with
+an address is calculated from a map
+associated with the file.
+Each map contains one or more quadruples (\c
+.I t ,
+.I b ,
+.I e ,
+.I f \|),
+defining a segment named
+.I t
+(usually 
+.CW text ,
+.CW data ,
+.CW regs ,
+or
+.CW fpregs )
+mapping addresses in the range
+.I b
+through
+.I e
+to the part of the file
+beginning at
+offset
+.I f .
+The memory model of a Plan 9 process assumes
+that segments are disjoint.  There
+can be more than one segment of a given type (e.g., a process
+may have more than one text segment) but segments
+may not overlap.
+An address
+.I a
+is translated
+to a file address
+by finding a segment
+for which
+.I b
++
+.I a
+<
+.I e ;
+the location in the file
+is then
+.I address
++
+.I f
+\-
+.I b .
+.PP
+Usually,
+the text and initialized data of a program
+are mapped by segments called 
+.CW text
+and
+.CW data .
+Since a program file does not contain bss, stack, or register data,
+these data are
+not mapped by the data segment.
+The text segment is mapped similarly in the memory image of
+a normal (i.e., non-kernel) process.
+However, the segment called 
+.CW *data
+maps memory from the beginning to the end of the program's data space.
+This region contains the program's static data, the bss, the
+heap and the stack.  A segment
+called
+.CW *regs
+maps the registers;
+.CW *fpregs
+maps the floating point registers (if they exist).
+.PP
+Sometimes it is useful to define a map with a single segment
+mapping the region from 0 to 0xFFFFFFFF; such a map
+allows the entire file to be examined
+without address translation.  The builtin function
+.CW map
+examines and modifies Acid's map for a process.
+.SH 1
+Name Conflicts
+.PP
+Name conflicts between keywords in the Acid language, symbols in the program,
+and previously defined functions are resolved when the interpreter starts up.
+Each name is made unique by prefixing enough
+.CW $
+characters to the front of the name to make it unique. Acid reports
+a list of each name change at startup. The report looks like this:
+.P1
+/bin/sam: mips plan 9 executable
+/lib/acid/port
+/lib/acid/mips
+Symbol renames:
+	append=$append T/0xa4e40
+acid:
+.P2
+The symbol
+.CW append
+is both a keyword and a text symbol in the program. The message reports
+that the text symbol is now named
+.CW $append .
+.SH
+Expressions
+.PP
+Operators have the same
+binding and precedence as in C.
+For operators of equal precedence, expressions are evaluated from left to right. 
+.SH 1
+Boolean expressions
+.PP
+If an expression is evaluated for a boolean condition the test
+performed depends on the type of the result. If the result is of
+.I integer
+or
+.I floating
+type the result is true if the value is non-zero. If the expression is a
+.I list
+the result is true if there are any members in the list.
+If the expression is a
+.I string
+the result is true if there are any characters in the string.
+.DS
+	primary-expression:
+		identifier
+		identifier \f(CW:\fP identifier
+		constant
+		\f(CW(\fP expression \f(CW)\fP
+		\f(CW{\fP elist \f(CW}\fP
+
+	elist:
+		expression
+		elist , expression
+.DE
+An identifier may be any legal Acid variable. The colon operator returns the
+address of parameters or local variables in the current stack of a program.
+For example:
+.P1
+*main:argc
+.P2
+prints the number of arguments passed into main. Local variables and parameters
+can only be referenced after the frame has been established. It may be necessary to
+step a program over the first few instructions of a breakpointed function to properly set
+the frame.
+.PP
+Constants follow the same lexical rules as C.
+A list of expressions delimited by braces forms a list constructor.
+A new list is produced by evaluating each expression when the constructor is executed.
+The empty list is formed from
+.CW {} .
+.P1
+acid: x = 10
+acid: l = { 1, x, 2\eD }
+acid: x = 20
+acid: l
+{0x00000001 , 0x0000000a , 2 }
+.P2
+.SH 1
+Lists
+.PP
+Several operators manipulate lists.
+.DS
+	list-expression:
+		primary-expression
+		\f(CWhead\fP primary-expression
+		\f(CWtail\fP primary-expression
+		\f(CWappend\fP expression \f(CW,\fP primary-expression
+		\f(CWdelete\fP expression \f(CW,\fP primary-expression
+.DE
+The
+.I primary-expression
+for
+.CW head
+and
+.CW tail
+must yield a value of type
+.I list .
+If there are no elements in the list the value of
+.CW head
+or
+.CW tail
+will be the empty list. Otherwise
+.CW head
+evaluates to the first element of the list and
+.CW tail
+evaluates to the rest.
+.P1
+acid: head {}
+{}
+acid: head {1, 2, 3, 4}
+0x00000001 
+acid: tail {1, 2, 3, 4}
+{0x00000002 , 0x00000003 , 0x00000004 }
+.P2
+The first operand of
+.CW append 
+and
+.CW delete
+must be an expression that yields a
+.I list .
+.CW Append
+places the result of evaluating
+.I primary-expression
+at the end of the list.
+The
+.I primary-expression
+supplied to
+.CW delete
+must evaluate to an integer;
+.CW delete
+removes the 
+.I n 'th
+item from the list, where
+.I n
+is integral value of
+.I primary-expression.
+List indices are zero-based.
+.P1
+	acid: append {1, 2}, 3
+	{0x00000001 , 0x00000002 , 0x00000003 }
+	acid: delete {1, 2, 3}, 1
+	{0x00000001 , 0x00000003 }
+.P2
+.PP
+Assigning a list to a variable copies a reference to the list; if a list variable
+is copied it still points at the same list.  To copy a list, the elements must
+be copied piecewise using
+.CW head
+and
+.CW append .
+.SH 1
+Operators
+.PP
+.DS
+	postfix-expression:
+		list-expression
+		postfix-expression \f(CW[\fP expression \f(CW]\fP
+		postfix-expression \f(CW(\fP argument-list \f(CW)\fP
+		postfix-expression \f(CW.\fP tag
+		postfix-expression \f(CW->\fP tag 
+		postfix-expression \f(CW++\fP
+		postfix-expression \f(CW--\fP
+
+	argument-list:
+		expression
+		argument-list , expression
+.DE
+The
+.CW [
+.I expression
+.CW ]
+operator performs indexing.
+The indexing expression must result in an expression of
+.I integer
+type, say
+.I n .
+The operation depends on the type of
+.I postfix-expression .
+If the
+.I postfix-expression
+yields an
+.I integer
+it is assumed to be the base address of an array in the memory image.
+The index offsets into this array; the size of the array members is
+determined by the format associated with the
+.I postfix-expression .
+If the 
+.I postfix-expression
+yields a
+.I string
+the index operator fetches the
+.I n 'th
+character
+of the string. If the index points beyond the end
+of the string, a zero is returned.
+If the
+.I postfix-expression
+yields a
+.I list
+then the indexing operation returns the
+.I n 'th
+item of the list.
+If the list contains less than
+.I n
+items the empty list
+.CW {}
+is returned.
+.PP
+The
+.CW ++
+and
+.CW --
+operators increment and decrement integer variables.
+The amount of increment or decrement depends on the format code. These postfix
+operators return the value of the variable before the increment or decrement
+has taken place.
+.DS
+	unary-expression:
+		postfix-expression
+		\f(CW++\fP unary-expression
+		\f(CW--\fP unary-expression
+
+	unary-operator: one of
+		\f(CW*\fP \f(CW@\fP \f(CW+\fP \f(CW-\fP ~ \f(CW!\fP
+.DE
+The operators
+.CW *
+and
+.CW @
+are the indirection operators.
+.CW @
+references a value from the text file of the program being debugged.
+The size of the value depends on the format code. The
+.CW *
+operator fetches a value from the memory image of a process. If either
+operator appears on the left-hand side of an assignment statement, either the file
+or memory will be written. The file can only be modified when Acid is invoked
+with the
+.CW -w
+option.
+The prefix
+.CW ++
+and
+.CW --
+operators perform the same operation as their postfix counterparts but
+return the value after the increment or decrement has been performed. Since the
+.CW ++
+and
+.CW *
+operators fetch and increment the correct amount for the specified format,
+the following function prints correct machine instructions on a machine with
+variable length instructions, such as the 68020 or 386:
+.P1
+	defn asm(addr)
+	{
+		addr = fmt(addr, 'i');
+		loop 1, 10 do
+			print(*addr++, "\en");
+	}
+.P2
+The operators
+.CW ~
+and
+.CW !
+perform bitwise and logical negation respectively. Their operands must be of
+.I integer
+type.
+.DS
+	cast-expression:
+		unary-expression
+		unary-expression \f(CW\e\fP format-char
+		\f(CW(\fP complex-name \f(CW)\fP unary-expression		
+.DE
+A unary expression may be preceded by a cast. The cast has the effect of
+associating the value of 
+.I unary-expression
+with a complex type structure.
+The result may then be dereferenced using the
+.CW .
+and
+.CW ->
+operators.
+.PP
+An Acid variable may be associated with a complex type
+to enable accessing the type's members:
+.P1
+acid: complex List {
+	'D'	0	type;
+	'X'	4	next;
+};
+acid: complex List lhead
+acid: lhead.type
+10
+acid: lhead = ((List)lhead).next
+acid: lhead.type
+-46
+.P2
+Note that the
+.CW next
+field cannot be given a complex type automatically.
+.PP
+When entered at the top level of the interpreter,
+an expression of complex type
+is treated specially.
+If the type is called
+.CW T
+and an Acid function also called
+.CW T
+exists,
+then that function will be called with the expression as its argument.
+The compiler options
+.CW -a
+and
+.CW -aa
+will generate Acid source code defining such complex types and functions; see
+.I 2c (1).
+.PP
+A
+.I unary-expression
+may be qualified with a format specifier using the
+.CW \e
+operator. This has the same effect as passing the expression to the
+.CW fmt
+builtin function.
+.DS
+	multiplicative-expression:
+		cast-expression
+		multiplicative-expression \f(CW*\fP multiplicative-expression
+		multiplicative-expression \f(CW/\fP multiplicative-expression
+		multiplicative-expression \f(CW%\fP multiplicative-expression
+.DE
+These operate on
+.I integer
+and 
+.I float
+types and perform the expected operations:
+.CW *
+multiplication,
+.CW /
+division,
+.CW %
+modulus.
+.DS
+	additive-expression:
+		multiplicative-expression
+		additive-expression \f(CW+\fP multiplicative-expression
+		additive-expression \f(CW-\fP multiplicative-expression
+.DE
+These operators perform as expected for
+.I integer
+and 
+.I float
+operands.
+Unlike in C,
+.CW +
+and
+.CW -
+do not scale the addition based on the format of the expression.
+This means that
+.CW i=i+1
+will always add 1 but
+.CW i++
+will add the size corresponding to the format stored with
+.CW i .
+If both operands are of either
+.I string
+or
+.I list
+type then addition is defined as concatenation. 
+Adding a string and an integer is treated as concatenation
+with the Unicode character corresponding to the integer.
+Subtraction is undefined for strings and lists.
+.DS
+	shift-expression:
+		additive-expression
+		shift-expression \f(CW<<\fP additive-expression
+		shift-expression \f(CW>>\fP additive-expression
+.DE
+The
+.CW >>
+and
+.CW <<
+operators perform bitwise right and left shifts respectively. Both
+require operands of
+.I integer
+type.
+.DS
+	relational-expression:
+		relational-expression \f(CW<\fP shift-expression
+		relational-expression \f(CW>\fP shift-expression
+		relational-expression \f(CW<=\fP shift-expression
+		relational-expression \f(CW>=\fP shift-expression
+
+	equality-expression:
+		relational-expression
+		relational-expression \f(CW==\fP equality-expression
+		relational-expression \f(CW!=\fP equality-expression
+.DE
+The comparison operators are
+.CW <
+(less than),
+.CW >
+(greater than),
+.CW <=
+(less than or equal to),
+.CW >=
+(greater than or equal to),
+.CW ==
+(equal to) and
+.CW !=
+(not equal to). The result of a comparison is 0
+if the condition is false, otherwise 1. The relational operators can only be
+applied to operands of
+.I integer
+and
+.I float
+type. The equality operators apply to all types.  Comparing mixed types is legal.
+Mixed integer and float compare on the integral value.  Other mixtures are always unequal.
+Two lists are equal if they
+have the same number of members and a pairwise comparison of the members results
+in equality.
+.DS
+	AND-expression:
+		equality-expression
+		AND-expression \f(CW&\fP equality-expression
+
+	XOR-expression:
+		AND-expression
+		XOR-expression \f(CW^\fP AND-expression
+
+	OR-expression:
+		XOR-expression
+		OR-expression \f(CW|\fP XOR-expression
+.DE
+These operators perform bitwise logical operations and apply only to the
+.I integer
+type.
+The operators are
+.CW &
+(logical and),
+.CW ^
+(exclusive or) and
+.CW |
+(inclusive or).
+.DS
+	logical-AND-expression:
+		OR-expression
+		logical-AND-expression \f(CW&&\fP OR-expression
+
+	logical-OR-expression:
+		logical-AND-expression
+		logical-OR-expression \f(CW||\fP logical-AND-expression
+.DE
+The
+.CW &&
+operator returns 1 if both of its operands evaluate to boolean true, otherwise 0.
+The
+.CW ||
+operator returns 1 if either of its operands evaluates to boolean true,
+otherwise 0.
+.SH
+Statements
+.PP
+.DS
+	\f(CWif\fP expression \f(CWthen\fP statement \f(CWelse\fP statement
+	\f(CWif\fP expression \f(CWthen\fP statement
+.DE
+The
+.I expression
+is evaluated as a boolean. If its value is true the statement after
+the
+.CW then
+is executed, otherwise the statement after the
+.CW else
+is executed. The 
+.CW else
+portion may be omitted.
+.DS
+	\f(CWwhile\fP expression \f(CWdo\fP statement
+.DE
+In a while loop, the
+.I statement
+is executed while the boolean
+.I expression
+evaluates
+true.
+.DS
+	\f(CWloop\fP startexpr, endexpr \f(CWdo\fP statement
+.DE
+The two expressions
+.I startexpr
+and
+.I endexpr
+are evaluated prior to loop entry.
+.I Statement
+is evaluated while the value of
+.I startexpr
+is less than or equal to
+.I endexpr .
+Both expressions must yield
+.I integer
+values. The value of
+.I startexpr
+is
+incremented by one for each loop iteration.
+Note that there is no explicit loop variable; the
+.I expressions
+are just values.
+.DS
+	\f(CWreturn\fP expression
+.DE
+.CW return
+terminates execution of the current function and returns to its caller.
+The value of the function is given by expression. Since
+.CW return
+requires an argument, nil-valued functions should return the empty list
+.CW {} .
+.DS
+	\f(CWlocal\fP variable
+.DE
+The
+.CW local
+statement creates a local instance of
+.I variable ,
+which exists for the duration
+of the instance of the function in which it is declared. Binding is dynamic: the local variable,
+rather than the previous value of
+.I variable ,
+is visible to called functions.
+After a return from the current function the previous value of
+.I variable
+is
+restored.
+.PP
+If Acid is interrupted, the values of all local variables are lost,
+as if the function returned.
+.DS
+	\f(CWdefn\fP function-name \f(CW(\fP parameter-list \f(CW)\fP body
+
+	parameter-list:
+		variable
+		parameter-list , variable
+
+	body:
+		\f(CW{\fP statement \f(CW}\fP
+.DE
+Functions are introduced by the
+.CW defn
+statement. The definition of parameter names suppresses any variables
+of the same name until the function returns. The body of a function is a list
+of statements enclosed by braces.
+.SH
+Code variables
+.PP
+Acid permits the delayed evaluation of a parameter to a function.  The parameter
+may then be evaluated at any time with the
+.CW eval
+operator.  Such parameters are called
+.I "code variables
+and are defined by prefixing their name with an asterisk in their declaration.
+.PP
+For example, this function wraps up an expression for later evaluation:
+.P1
+acid: defn code(*e) { return e; }
+acid: x = code(v+atoi("100")\eD)
+acid: print(x)
+(v+atoi("100"))\eD;
+acid: eval x
+<stdin>:5: (error) v used but not set
+acid: v=5
+acid: eval x
+105
+.P2
+.SH
+Source Code Management
+.PP
+Acid provides the means to examine source code. Source code is
+represented by lists of strings. Builtin functions provide mapping
+from address to lines and vice-versa. The default debugging environment
+has the means to load and display source files.
+.SH
+Builtin Functions
+.PP
+The Acid interpreter has a number of builtin functions, which cannot be redefined.
+These functions perform machine- or operating system-specific functions such as
+symbol table and process management.
+The following section presents a description of each builtin function.
+The notation
+.CW {}
+is used to denote the empty list, which is the default value of a function that
+does not execute a
+.CW return 
+statement.
+The type and number of parameters for each function are specified in the
+description; where a parameter can be of any type it is specified as type
+.I item .
+.de Ip
+.KS
+.LP
+.tl '\f2\\$1\fP\ \ \f(CW\\$2(\f2\\$3\f(CW)\f1''\\$4'
+.IP
+..
+.de Ex
+.KE
+.KS
+.IP
+.ft CW
+.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n
+.nf
+.in +4n
+.br
+..
+.de Ee
+.fi
+.ft 1
+.br
+.KE
+..
+.\"
+.\"
+.\"
+.Ip integer access string "Check if a file can be read
+.CW Access
+returns the integer 1 if the file name in
+.I string
+can be read by the builtin functions
+.CW file ,
+.CW readfile ,
+or
+.CW include ,
+otherwise 0. A typical use of this function is to follow
+a search path looking for a source file; it is used by
+.CW findsrc .
+.Ex
+if access("main.c") then
+	return file("main.c");
+.Ee
+.\"
+.\"
+.\"
+.Ip float atof string "Convert a string to float
+.CW atof
+converts the string supplied as its argument into a floating point
+number. The function accepts strings in the same format as the C
+function of the same name. The value returned has the format code
+.CW f .
+.CW atof
+returns the value 0.0 if it is unable to perform the conversion.
+.Ex
+acid: +atof("10.4e6")
+1.04e+07
+.Ee
+.\"
+.\"
+.\"
+.Ip integer atoi string "Convert a string to an integer
+.CW atoi
+converts the argument
+.i string
+to an integer value.
+The function accepts strings in the same format as the C function of the
+same name. The value returned has the format code
+.CW D .
+.CW atoi
+returns the integer 0 if it is unable to perform a conversion.
+.Ex
+acid: +atoi("-1255")
+-1255
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP error string "Generate an interpreter error
+.CW error
+generates an error message and returns the interpreter to interactive
+mode. If an Acid program is running, it is aborted.
+Processes being debugged are not affected. The values of all local variables are lost.
+.CW error
+is commonly used to stop the debugger when some interesting condition arises
+in the debugged program.
+.Ex
+while 1 do {
+	step();
+	if *main != @main then
+		error("memory corrupted");
+}
+.Ee
+.\"
+.\"
+.\"
+.Ip list file string "Read the contents of a file into a list
+.CW file
+reads the contents of the file specified by
+.I string
+into a list.
+Each element in the list is a string corresponding to a line in the file.
+.CW file
+breaks lines at the newline character, but the newline
+characters are not returned as part each string.
+.CW file
+returns the empty list if it encounters an error opening or reading the data.
+.Ex
+acid: print(file("main.c")[0])
+#include	<u.h>
+.Ee
+.\"
+.\"
+.\"
+.Ip integer filepc string "Convert source address to text address
+.CW filepc
+interprets its
+.I string
+argument as a source file address in the form of a file name and line offset.
+.CW filepc
+uses the symbol table to map the source address into a text address
+in the debugged program. The
+.I integer
+return value has the format
+.CW X .
+.CW filepc
+returns an address of -1 if the source address is invalid.
+The source file address uses the same format as
+.I acme (1).
+This function is commonly used to set breakpoints from the source text.
+.Ex
+acid: bpset(filepc("main:10"))
+acid: bptab()
+	0x00001020 usage  ADD	$-0xc,R29
+.Ee
+.\"
+.\"
+.\"
+.Ip item fmt item,fmt "Set print, \f(CW@\fP and \f(CW*\fP formats
+.CW fmt
+evaluates the expression
+.I item
+and sets the format of the result to
+.I fmt .
+The format of a value determines how it will be printed and
+what kind of object will be fetched by the
+.CW *
+and
+.CW @
+operators. The
+.CW \e
+operator is a short-hand form of the
+.CW fmt
+builtin function. The
+.CW fmt
+function leaves the format of the
+.I item
+unchanged.
+.Ex
+acid: main=fmt(main, 'i') // as instructions
+acid: print(main\eX, "\et", *main)
+0x00001020 ADD	$-64,R29
+.Ee
+.\"
+.\"
+.\"
+.Ip list fnbound integer "Find start and end address of a function
+.CW fnbound
+interprets its
+.I integer
+argument as an address in the text of the debugged program.
+.CW fnbound
+returns a list containing two integers corresponding to
+the start and end addresses of the function containing the supplied address.
+If the
+.I integer
+address is not in the text segment of the program then the empty list is returned.
+.CW fnbound
+is used by
+.CW next
+to detect stepping into new functions.
+.Ex
+acid: print(fnbound(main))
+{0x00001050, 0x000014b8}
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP follow integer "Compute follow set
+The follow set is defined as the set of program counter values that could result
+from executing an instruction.
+.CW follow
+interprets its
+.I integer
+argument as a text address, decodes the instruction at
+that address and, with the current register set, builds a list of possible
+next program counter values. If the instruction at the specified address
+cannot be decoded
+.CW follow
+raises an error.
+.CW follow
+is used to plant breakpoints on
+all potential paths of execution. The following code fragment
+plants breakpoints on top of all potential following instructions.
+.Ex
+lst = follow(*PC);
+while lst do
+{
+	*head lst = bpinst;
+	lst = tail lst;
+}
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP include string "Take input from a new file
+.CW include
+opens the file specified by
+.I string
+and uses its contents as command input to the interpreter.
+The interpreter restores input to its previous source when it encounters
+either an end of file or an error.
+.CW include
+can be used to incrementally load symbol table information without
+leaving the interpreter.
+.Ex
+acid: include("/sys/src/cmd/acme/syms")
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP interpret string "Take input from a string
+.CW interpret
+evaluates the
+.I string
+expression and uses its result as command input for the interpreter.
+The interpreter restores input to its previous source when it encounters
+either the end of string or an error. The
+.CW interpret
+function allows Acid programs to write Acid code for later evaluation.
+.Ex
+acid: interpret("main+10;")
+0x0000102a
+.Ee
+.\"
+.\"
+.\"
+.Ip string itoa integer "Convert integer to string
+.CW itoa
+takes an integer argument and converts it into an ASCII string
+in the
+.CW D
+format. This function is commonly used to build
+.CW rc
+command lines.
+.Ex
+acid: rc("cat /proc/"+itoa(pid)+"/segment")
+Stack    7fc00000 80000000    1
+Data     00001000 00009000    1
+Data     00009000 0000a000    1
+Bss      0000a000 0000c000    1
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP kill integer "Kill a process
+.CW kill
+writes a kill control message into the control file of the process
+specified by the
+.I integer
+pid.
+If the process was previously installed by
+.CW setproc
+it will be removed from the list of active processes.
+If the
+.I integer
+has the same value as
+.CW pid ,
+then
+.CW pid
+will be set to 0.
+To continue debugging, a new process must be selected using
+.CW setproc .
+For example, to kill all the active processes:
+.Ex
+while proclist do {
+	kill(head proclist);
+	proclist = tail proclist;
+}
+.Ee
+.\"
+.\"
+.\"
+.Ip list map list "Set or retrieve process memory map
+.CW map
+either retrieves all the mappings associated with a process or sets a single
+map entry to a new value.
+If the
+.I list
+argument is omitted then
+.CW map
+returns a list of lists. Each sublist has four values and describes a
+single region of contiguous addresses in the
+memory or file image of the debugged program. The first entry is the name of the
+mapping. If the name begins with
+.CW *
+it denotes a map into the memory of an active process.
+The second and third values specify the base and end
+address of the region and the fourth number specifies the offset in the file
+corresponding to the first location of the region.
+A map entry may be set by supplying a list in the same format as the sublist
+described above. The name of the mapping must match a region already defined
+by the current map.
+Maps are set automatically for Plan 9 processes and some kernels; they may
+need to be set by hand for other kernels and programs that run on bare hardware.
+.Ex
+acid: map({"text", _start, end, 0x30})
+.Ee
+.\"
+.\"
+.\"
+.Ip integer match item,list "Search list for matching value
+.CW match
+compares each item in
+.I list
+using the equality operator
+.CW ==
+with
+.I item .
+The
+.I item
+can be of any type. If the match succeeds the result is the integer index
+of the matching value, otherwise -1.
+.Ex
+acid: list={8,9,10,11}
+acid: print(list[match(10, list)]\eD)
+10
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP newproc string "Create a new process
+.CW newproc
+starts a new process with an argument vector constructed from
+.I string .
+The argument vector excludes the name of the program to execute and
+each argument in
+.I string
+must be space separated. A new process can accept no more
+than 512 arguments. The internal variable
+.CW pid
+is set to the pid of the newly created process. The new pid
+is also appended to the list of active processes stored in the variable
+.CW proclist .
+The new process is created then halted at the first instruction, causing
+the debugger to call
+.CW stopped .
+The library functions
+.CW new
+and
+.CW win
+should be used to start processes when using the standard debugging
+environment.
+.Ex
+acid: newproc("-l .")
+56720: system call	_main	ADD	$-0x14,R29
+.Ee
+.\"
+.\"
+.\"
+.Ip string pcfile integer "Convert text address to source file name
+.CW pcfile
+interprets its
+.I integer
+argument as a text address in the debugged program. The address and symbol table
+are used to generate a string containing the name of the source file
+corresponding to the text address. If the address does not lie within the
+program the string
+.CW ?file?
+is returned.
+.Ex
+acid: print("Now at ", pcfile(*PC), ":", pcline(*PC))
+Now at ls.c:46 
+.Ee
+.\"
+.\"
+.\"
+.Ip integer pcline integer "Convert text address to source line number
+.CW pcline
+interprets its
+.I integer
+argument as a text address in the debugged program. The address and symbol table
+are used to generate an integer containing the line number in the source file
+corresponding to the text address. If the address does not lie within the
+program the integer 0 is returned.
+.Ex
+acid: +file("main.c")[pcline(main)]
+main(int argc, char *argv[])
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP print item,item,... "Print expressions
+.CW print
+evaluates each
+.I item
+supplied in its argument list and prints it to standard output. Each
+argument will be printed according to its associated format character.
+When the interpreter is executing, output is buffered and flushed every
+5000 statements or when the interpreter returns to interactive mode.
+.CW print
+accepts a maximum of 512 arguments.
+.Ex
+acid: print(10, "decimal ", 10\eD, "octal ", 10\eo)
+0x0000000a decimal 10 octal 000000000012 
+acid: print({1, 2, 3})
+{0x00000001 , 0x00000002 , 0x00000003 }
+acid: print(main, main\ea, "\et", @main\ei)
+0x00001020 main	ADD	$-64,R29
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP printto string,item,item,... "Print expressions to file
+.CW printto
+offers a limited form of output redirection. The first
+.I string
+argument is used as the path name of a new file to create.
+Each
+.I item
+is then evaluated and printed to the newly created file. When all items
+have been printed the file is closed.
+.CW printto
+accepts a maximum of 512 arguments.
+.Ex
+acid: printto("/env/foo", "hello")
+acid: rc("echo -n $foo")
+hello
+.Ee
+.\"
+.\"
+.\"
+.Ip string rc string "Execute a shell command
+.CW rc
+evaluates
+.I string
+to form a shell command. A new command interpreter is started
+to execute the command. The Acid interpreter blocks until the command
+completes. The return value is the empty string
+if the command succeeds, otherwise the exit status of the failed command.
+.Ex
+acid: rc("B "+itoa(-pcline(addr))+" "+pcfile(addr));
+.Ee
+.\"
+.\"
+.\"
+.Ip string readfile string "Read file contents into a string
+.CW readfile
+takes the contents of the file specified by
+.I string
+and returns its contents as a new string.
+If
+.CW readfile
+encounters a zero byte in the file, it terminates.
+If
+.CW readfile
+encounters an error opening or reading the file then the empty list
+is returned.
+.CW readfile
+can be used to read the contents of device files whose lines are not
+terminated with newline characters.
+.Ex
+acid: ""+readfile("/dev/label")
+helix
+.Ee
+.\"
+.\"
+.\"
+.Ip string reason integer "Print cause of program stoppage
+.CW reason
+uses machine-dependent information to generate a string explaining
+why a process has stopped. The
+.I integer
+argument is the value of an architecture dependent status register,
+for example
+.CW CAUSE
+on the MIPS.
+.Ex
+acid: print(reason(*CAUSE))
+system call
+.Ee
+.\"
+.\"
+.\"
+.Ip integer regexp pattern,string "Regular expression match
+.CW regexp
+matches the
+.I pattern
+string supplied as its first argument with the 
+.I string
+supplied as its second.
+If the pattern matches the result is the value 1, otherwise 0.
+.Ex
+acid: print(regexp(".*bar", "foobar"))
+1
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP setproc integer "Set debugger focus
+.CW setproc
+selects the default process used for memory and control operations. It effectively
+shifts the focus of control between processes. The 
+.I integer
+argument specifies the pid of the process to look at.
+The variable
+.CW pid
+is set to the pid of the selected process. If the process is being
+selected for the first time its pid is added to the list of active
+processes
+.CW proclist .
+.Ex
+acid: setproc(68382)
+acid: procs()
+>68382: Stopped at main+0x4 setproc(68382)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP start integer "Restart execution
+.CW start
+writes a
+.CW start
+message to the control file of the process specified by the pid
+supplied as its
+.I integer
+argument.
+.CW start
+draws an error if the process is not in the
+.CW Stopped
+state.
+.Ex
+acid: start(68382)
+acid: procs()
+>68382: Running at main+0x4 setproc(68382)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP startstop integer "Restart execution, block until stopped
+.CW startstop
+performs the same actions as a call to
+.CW start
+followed by a call to
+.CW stop .
+The
+.I integer
+argument specifies the pid of the process to control. The process
+must be in the
+.CW Stopped
+state.
+Execution is restarted, the debugger then waits for the process to
+return to the
+.CW Stopped
+state. A process will stop if a startstop message has been written to its control
+file and any of the following conditions becomes true: the process executes or returns from
+a system call, the process generates a trap or the process receives a note.
+.CW startstop
+is used to implement single stepping.
+.Ex
+acid: startstop(pid)
+75374: breakpoint	ls	ADD	$-0x16c8,R29
+.Ee
+.\"
+.\"
+.\"
+.Ip string status integer "Return process state
+.CW status
+uses the pid supplied by its
+.I integer
+argument to generate a string describing the state of the process.
+The string corresponds to the state returned by the
+sixth column of the
+.I ps (1)
+command.
+A process must be in the
+.CW Stopped
+state to modify its memory or registers.
+.Ex
+acid: ""+status(pid)
+Stopped
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP stop integer "Wait for a process to stop
+.CW stop
+writes a
+.CW stop
+message to the control file of the process specified by the
+pid supplied as its
+.I integer
+argument.
+The interpreter blocks until the debugged process enters the
+.CW Stopped
+state.
+A process will stop if a stop message has been written to its control
+file and any of the following conditions becomes true: the process executes or returns from
+a system call, the process generates a trap, the process is scheduled or the
+process receives a note.
+.CW stop
+is used to wait for a process to halt before planting a breakpoint since Plan 9
+only allows a process's memory to be written while it is in the
+.CW Stopped
+state.
+.Ex
+defn bpset(addr) {
+	if (status(pid)!="Stopped") then {
+		print("Waiting...\en");
+		stop(pid);
+	}
+	...
+}
+.Ee
+.\"
+.\"
+.\"
+.Ip list strace pc,sp,linkreg "Stack trace
+.CW strace
+generates a list of lists corresponding to procedures called by the debugged
+program. Each sublist describes a single stack frame in the active process.
+The first element is an
+.I integer
+of format
+.CW X
+specifying the address of the called function. The second element is the value
+of the program counter when the function was called. The third and fourth elements
+contain lists of parameter and automatic variables respectively.
+Each element of these lists
+contains a string with the name of the variable and an
+.I integer
+value of format
+.CW X
+containing the current value of the variable.
+The arguments to
+.CW strace
+are the current value of the program counter, the current value of the
+stack pointer, and the address of the link register. All three parameters
+must be integers.
+The setting of 
+.I linkreg
+is architecture dependent. On the MIPS linkreg is set to the address of saved
+.CW R31 ,
+on the SPARC to the address of saved
+.CW R15 .
+For the other architectures
+.I linkreg
+is not used, but must point to valid memory.
+.Ex
+acid: print(strace(*PC, *SP, linkreg))
+{{0x0000141c, 0xc0000f74,
+{{"s", 0x0000004d}, {"multi", 0x00000000}}, 
+{{"db", 0x00000000}, {"fd", 0x000010a4},
+{"n", 0x00000001}, {"i", 0x00009824}}}}
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP waitstop integer "Wait for a process to stop
+.CW waitstop
+writes a waitstop message to the control file of the process specified by the
+pid supplied as its
+.I integer
+argument.
+The interpreter will remain blocked until the debugged process enters the
+.CW Stopped
+state.
+A process will stop if a waitstop message has been written to its control
+file and any of the following conditions becomes true: the process generates a trap
+or receives a note. Unlike
+.CW stop ,
+the
+.CW waitstop
+function is passive; it does not itself cause the program to stop.
+.Ex
+acid: waitstop(pid)
+75374: breakpoint	ls	ADD	$-0x16c8,R29
+.Ee
+.\"
+.\"
+.\"
+.SH
+Library Functions
+.PP
+A standard debugging environment is provided by modules automatically
+loaded when
+Acid is started.
+These modules are located in the directory
+.CW /sys/lib/acid .
+These functions may be overridden, personalized, or added to by code defined in
+.CW $home/lib/acid .
+The implementation of these functions can be examined using the
+.CW whatis
+operator and then modified during debugging sessions.
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP Bsrc integer "Load text editor with source
+.CW Bsrc
+interprets the
+.I integer
+argument as a text address. The text address is used to produce a pathname
+and line number suitable for the external
+.CW B
+command
+of the text editor
+(eg,
+.I acme (1)).
+.CW Bsrc
+builds a shell
+command to invoke
+.CW B ,
+which either selects an existing source file or loads a new source file into
+the editor.
+The line of source corresponding to the text address is then selected.
+In the following example
+.CW stopped
+is redefined so that
+the editor
+follows and displays the source line currently being executed.
+.Ex
+defn stopped(pid) {
+	pstop(pid);
+	Bsrc(*PC);
+}
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP Fpr "" "Display double precision floating registers
+For machines equipped with floating point,
+.CW Fpr
+displays the contents of the floating point registers as double precision
+values.
+.Ex
+acid: Fpr()
+F0   0.	F2   0.
+F4   0.	F6   0.
+F8   0.	F10  0.
+\&...
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP Ureg integer "Display contents of Ureg structure
+.CW Ureg
+interprets the integer passed as its first argument as the address of a
+kernel
+.CW Ureg
+structure. Each element of the structure is retrieved and printed.
+The size and contents of the
+.CW Ureg
+structure are architecture dependent.
+This function can be used to decode the first argument passed to a
+.I notify (2)
+function after a process has received a note.
+.Ex
+acid: Ureg(*notehandler:ur)
+	status	0x3000f000
+	pc	0x1020
+	sp	0x7ffffe00
+	cause	0x00004002
+\&...
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP acidinit "" "Interpreter startup
+.CW acidinit
+is called by the interpreter after all
+modules have been loaded at initialization time.
+It is used to set up machine specific variables and the default source path.
+.CW acidinit
+should not be called by user code.
+.KE
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP addsrcdir string "Add element to source search path
+.CW addsrcdir
+interprets its string argument as a new directory
+.CW findsrc
+should search when looking for source code files.
+.CW addsrcdir
+draws an error if the directory is already in the source search path. The search
+path may be examined by looking at the variable
+.CW srcpath .
+.Ex
+acid: rc("9fs fornax")
+acid: addsrcpath("/n/fornax/sys/src/cmd")
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP asm integer "Disassemble machine instructions
+.CW asm
+interprets its integer argument as a text address from which to disassemble
+machine instructions.
+.CW asm
+prints the instruction address in symbolic and hexadecimal form, then prints
+the instructions with addressing modes. Up to twenty instructions will
+be disassembled.
+.CW asm
+stops disassembling when it reaches the end of the current function.
+Instructions are read from the file image using the
+.CW @
+operator.
+.Ex
+acid: asm(main)
+main     0x00001020 ADD    $-0x64,R29
+main+0x4 0x00001024 MOVW   R31,0x0(R29)
+main+0x8 0x00001028 MOVW   R1,argc+4(FP)
+main+0xc 0x0000102c MOVW   $bin(SB),R1
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP bpdel integer "Delete breakpoint
+.CW bpdel
+removes a previously set breakpoint from memory.
+The
+.I integer
+supplied as its argument must be the address of a previously set breakpoint.
+The breakpoint address is deleted from the active breakpoint list
+.CW bplist ,
+then the original instruction is copied from the file image to the memory
+image so that the breakpoint is removed.
+.Ex
+acid: bpdel(main+4)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP bpset integer "Set a breakpoint
+.CW bpset
+places a breakpoint instruction at the address specified
+by its
+.I integer
+argument, which must be in the text segment.
+.CW bpset
+draws an error if a breakpoint has already been set at the specified address.
+A list of current breakpoints is maintained in the variable
+.CW bplist .
+Unlike in
+.I db (1),
+breakpoints are left in memory even when a process is stopped, and
+the process must exist, perhaps by being
+created by either
+.CW new
+or
+.CW win ,
+in order to place a breakpoint.
+.CW Db "" (
+accepts breakpoint commands before the process is started.)
+On the
+MIPS and SPARC architectures,
+breakpoints at function entry points should be set 4 bytes into the function
+because the
+instruction scheduler may fill
+.CW JAL
+branch delay slots with the first instruction of the function.
+.Ex
+acid: bpset(main+4)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP bptab "" "List active breakpoints
+.CW bptab
+prints a list of currently installed breakpoints. The list contains the
+breakpoint address in symbolic and hexadecimal form as well as the instruction
+the breakpoint replaced. Breakpoints are not maintained across process creation
+using
+.CW new
+and
+.CW win .
+They are maintained across a fork, but care must be taken to keep control of
+the child process.
+.Ex
+acid: bpset(ls+4)
+acid: bptab()
+	0x00001420 ls+0x4  MOVW	R31,0x0(R29)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP casm "" "Continue disassembly
+.CW casm
+continues to disassemble instructions from where the last
+.CW asm
+or
+.CW casm
+command stopped. Like
+.CW asm ,
+this command stops disassembling at function boundaries.
+.Ex
+acid: casm()
+main+0x10 0x00001030	MOVW	$0x1,R3
+main+0x14 0x00001034	MOVW	R3,0x8(R29)
+main+0x18 0x00001038	MOVW	$0x1,R5
+main+0x1c 0x0000103c	JAL	Binit(SB)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP cont "" "Continue program execution
+.CW cont
+restarts execution of the currently active process.
+If the process is stopped on a breakpoint, the breakpoint is first removed,
+the program is single stepped, the breakpoint is replaced and the program
+is then set executing. This may cause
+.CW stopped()
+to be called twice.
+.CW cont
+causes the interpreter to block until the process enters the
+.CW Stopped
+state.
+.Ex
+acid: cont()
+95197: breakpoint	ls+0x4	MOVW	R31,0x0(R29)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP dump integer,integer,string "Formatted memory dump
+.CW dump
+interprets its first argument as an address, its second argument as a
+count and its third as a format string.
+.CW dump
+fetches an object from memory at the current address and prints it according
+to the format. The address is incremented by the number of bytes specified by
+the format and the process is repeated count times. The format string is any
+combination of format characters, each preceded by an optional count.
+For each object,
+.CW dump
+prints the address in hexadecimal, a colon, the object and then a newline.
+.CW dump
+uses
+.CW mem
+to fetch each object.
+.Ex
+acid: dump(main+35, 4, "X2bi")
+0x00001043: 0x0c8fa700 108 143 lwc2 r0,0x528f(R4) 
+0x0000104d: 0xa9006811   0   0 swc3 r0,0x0(R24) 
+0x00001057: 0x2724e800   4  37 ADD  $-0x51,R23,R31 
+0x00001061: 0xa200688d   6   0 NOOP
+0x0000106b: 0x2710c000   7   0 BREAK
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP findsrc string "Use source path to load source file
+.CW findsrc
+interprets its
+.I string
+argument as a source file. Each directory in the source path is searched
+in turn for the file. If the file is found, the source text is loaded using
+.CW file
+and stored in the list of active source files called
+.CW srctext .
+The name of the file is added to the source file name list
+.CW srcfiles .
+Users are unlikely to call
+.CW findsrc
+from the command line, but may use it from scripts to preload source files
+for a debugging session. This function is used by
+.CW src
+and
+.CW line
+to locate and load source code. The default search path for the MIPS
+is
+.CW ./ ,
+.CW /sys/src/libc/port ,
+.CW /sys/src/libc/9sys ,
+.CW /sys/src/libc/mips .
+.Ex
+acid: findsrc(pcfile(main));
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP fpr "" "Display single precision floating registers
+For machines equipped with floating point,
+.CW fpr
+displays the contents of the floating point registers as single precision
+values. When the interpreter stores or manipulates floating point values
+it converts into double precision values.
+.Ex
+acid: fpr()
+F0   0.	F1   0.
+F2   0.	F3   0.
+F4   0.	F5   0.
+\&...
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP func "" "Step while in function
+.CW func
+single steps the active process until it leaves the current function
+by either calling another function or returning to its caller.
+.CW func
+will execute a single instruction after leaving the current function.
+.Ex
+acid: func()
+95197: breakpoint	ls+0x8	MOVW	R1,R8
+95197: breakpoint	ls+0xc	MOVW	R8,R1
+95197: breakpoint	ls+0x10	MOVW	R8,s+4(FP)
+95197: breakpoint	ls+0x14	MOVW	$0x2f,R5
+95197: breakpoint	ls+0x18	JAL	utfrrune(SB)
+95197: breakpoint	utfrrune	ADD	$-0x18,R29
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP gpr "" "Display general purpose registers
+.CW gpr
+prints the values of the general purpose processor registers.
+.Ex
+acid: gpr()
+R1	0x00009562 R2	0x000010a4 R3	0x00005d08
+R4	0x0000000a R5	0x0000002f R6	0x00000008
+\&...
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP labstk integer "Print stack trace from label
+.CW labstk
+performs a stack trace from a Plan 9
+.I label.
+The kernel
+and C compilers store continuations in a common format. Since the
+compilers all use caller save conventions a continuation may be saved by
+storing a
+.CW PC
+and
+.CW SP
+pair. This data structure is called a label and is used by the
+C function
+.CW longjmp
+and the kernel to schedule threads and processes.
+.CW labstk
+interprets its
+.I integer
+argument as the address of a label and produces a stack trace for
+the thread of execution. The value of the function
+.CW ALEF_tid
+is a suitable argument for
+.CW labstk .
+.Ex
+acid: labstk(*mousetid)
+At pc:0x00021a70:Rendez_Sleep+0x178 rendez.l:44
+Rendez_Sleep(r=0xcd7d8,bool=0xcd7e0,t=0x0) rendez.l:5
+	called from ALEF_rcvmem+0x198 recvmem.l:45
+ALEF_rcvmem(c=0x000cd764,l=0x00000010) recvmem.l:6
+\&...
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP lstk "" "Stack trace with local variables
+.CW lstk
+produces a long format stack trace.
+The stack trace includes each function in the stack,
+where it was called from, and the value of the parameters and automatic
+variables for each function.
+.CW lstk
+displays the value rather than the address of each variable and all
+variables are assumed to be an integer in format
+.CW X .
+To print a variable in its correct format use the
+.CW :
+operator to find the address and apply the appropriate format before indirection
+with the
+.CW *
+operator. It may be necessary to single step a couple of instructions into
+a function to get a correct stack trace because the frame pointer adjustment
+instruction may get scheduled down into the body of the function.
+.Ex
+acid: lstk()
+At pc:0x00001024:main+0x4 ls.c:48
+main(argc=0x00000001,argv=0x7fffefec) ls.c:48
+	called from _main+0x20 main9.s:10
+	_argc=0x00000000
+	_args=0x00000000
+	fd=0x00000000
+	buf=0x00000000
+	i=0x00000000
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP mem integer,string "Print memory object
+.CW mem
+interprets its first
+.I integer
+argument as the address of an object to be printed according to the
+format supplied in its second
+.I string
+argument.
+The format string can be any combination of format characters, each preceded
+by an optional count.
+.Ex
+acid: mem(bdata+0x326, "2c2Xb")
+P = 0xa94bc464 0x3e5ae44d  19 
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP new "" "Create new process
+.CW new
+starts a new copy of the debugged program. The new program is started
+with the program arguments set by the variable
+.CW progargs .
+The new program is stopped in the second instruction of
+.CW main .
+The breakpoint list is reinitialized.
+.CW new
+may be used several times to instantiate several copies of a program
+simultaneously. The user can rotate between the copies using
+.CW setproc .
+.Ex
+acid: progargs="-l"
+acid: new()
+60: external interrupt	_main	ADD	$-0x14,R29
+60: breakpoint	main+0x4	MOVW	R31,0x0(R29)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP next "" "Step through language statement
+.CW next
+steps through a single language level statement without tracing down
+through each statement in a called function. For each statement,
+.CW next
+prints the machine instructions executed as part of the statement. After
+the statement has executed, source lines around the current program
+counter are displayed.
+.Ex
+acid: next()
+60: breakpoint	Binit+0x4 MOVW	R31,0x0(R29)
+60: breakpoint	Binit+0x8 MOVW	f+8(FP),R4
+binit.c:93
+ 88	
+ 89	int
+ 90	Binit(Biobuf *bp, int f, int mode)
+ 91	{
+>92		return Binits(bp, f, mode, bp->b, BSIZE);
+ 93	}
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP notestk integer "Stack trace after receiving a note
+.CW notestk
+interprets its
+.I integer
+argument as the address of a
+.CW Ureg
+structure passed by the kernel to a
+.I notify (2)
+function during note processing.
+.CW notestk
+uses the
+.CW PC ,
+.CW SP ,
+and link register from the
+.CW Ureg
+to print a stack trace corresponding to the point in the program where the note
+was received.
+To get a valid stack trace on the MIPS and SPARC architectures from a notify
+routine, the program must stop in a new function called from the notify routine
+so that the link register is valid and the notify routine's parameters are
+addressable.
+.Ex
+acid: notestk(*notify:ur)
+Note pc:0x00001024:main+0x4 ls.c:48
+main(argc=0x00000001,argv=0x7fffefec) ls.c:48
+	called from _main+0x20 main9.s:10
+	_argc=0x00000000
+	_args=0x00000000
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP pfl integer "Print source file and line
+.CW pfl
+interprets its argument as a text address and uses it to print
+the source file and line number corresponding to the address. The output
+has the same format as file addresses in
+.I acme (1).
+.Ex
+acid: pfl(main)
+ls.c:48
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP procs "" "Print active process list
+.CW procs
+prints a list of active process attached to the debugger. Each process
+produces a single line of output giving the pid, process state, the address
+the process is currently executing, and the
+.CW setproc
+command required to make that process current.
+The current process is marked in the first column with a
+.CW >
+character. The debugger maintains a list of processes in the variable
+.CW proclist .
+.Ex
+acid: procs()
+>62: Stopped at main+0x4 setproc(62)
+ 60: Stopped at Binit+0x8 setproc(60)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP pstop integer "Print reason process stopped
+.CW pstop
+prints the status of the process specified by the
+.I integer
+pid supplied as its argument.
+.CW pstop
+is usually called from
+.CW stopped
+every time a process enters the
+.CW Stopped
+state.
+.Ex
+acid: pstop(62)
+0x0000003e: breakpoint	main+0x4	MOVW	R31,0x0(R29)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP regs "" "Print registers
+.CW regs
+prints the contents of both the general and special purpose registers.
+.CW regs
+calls
+.CW spr
+then
+.CW gpr
+to display the contents of the registers.
+.KE
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP source "" "Summarize source data base
+.CW source
+prints the directory search path followed by a list of currently loaded
+source files. The source management functions
+.CW src
+and
+.CW findsrc
+use the search path to locate and load source files. Source files are
+loaded incrementally into a source data base during debugging. A list
+of loaded files is stored in the variable
+.CW srcfiles
+and the contents of each source file in the variable
+.CW srctext .
+.Ex
+acid: source()
+/n/bootes/sys/src/libbio/
+./
+/sys/src/libc/port/
+/sys/src/libc/9sys/
+/sys/src/libc/mips/
+	binit.c
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP spr "" "Print special purpose registers
+.CW spr
+prints the contents of the processor control and memory management
+registers. Where possible, the contents of the registers are decoded
+to provide extra information; for example the
+.CW CAUSE
+register on the MIPS is
+printed both in hexadecimal and using the
+.CW reason
+function.
+.Ex
+acid: spr()
+PC	0x00001024 main+0x4  ls.c:48
+SP	0x7fffef68 LINK	0x00006264 _main+0x28 main9.s:12
+STATUS	0x0000ff33 CAUSE	0x00000024 breakpoint
+TLBVIR	0x000000d3 BADVADR	0x00001020
+HI	0x00000004 LO		0x00001ff7
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP src integer "Print lines of source
+.CW src
+interprets its
+.I integer
+argument as a text address and uses this address to print 5 lines
+of source before and after the address. The current line is marked with a
+.CW >
+character.
+.CW src
+uses the source search path maintained by
+.CW source
+and
+.CW addsrcdir
+to locate the required source files.
+.Ex
+acid: src(*PC)
+ls.c:47
+ 42	Biobuf	bin;
+ 43	
+ 44	#define		HUNK	50
+ 45	
+ 46	void
+>47	main(int argc, char *argv[])
+ 48	{
+ 49		int i, fd;
+ 50		char buf[64];
+ 51	
+ 52		Binit(&bin, 1, OWRITE);
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP step "" "Single step process
+.CW step
+causes the debugged process to execute a single machine level instruction.
+If the program is stopped on a breakpoint set by
+.CW bpset
+it is first removed, the single step executed, and the breakpoint replaced.
+.CW step
+uses
+.CW follow
+to predict the address of the program counter after the current instruction
+has been executed. A breakpoint is placed at each of these predicted addresses
+and the process is started. When the process stops the breakpoints are removed.
+.Ex
+acid: step()
+62: breakpoint	main+0x8	MOVW	R1,argc+4(FP)
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP stk "" "Stack trace
+.CW stk
+produces a short format stack trace. The stack trace includes each function
+in the stack, where it was called from, and the value of the parameters.
+The short format omits the values of automatic variables.
+Parameters are assumed to be integer values in the format
+.CW X ;
+to print a parameter in the correct format use the
+.CW :
+to obtain its address, apply the correct format, and use the
+.CW *
+indirection operator to find its value.
+It may be necessary to single step a couple of instructions into
+a function to get a correct stack trace because the frame pointer adjustment
+instruction may get scheduled down into the body of the function.
+.Ex
+acid: stk()
+At pc:0x00001028:main+0x8 ls.c:48
+main(argc=0x00000002,argv=0x7fffefe4) ls.c:48
+	called from _main+0x20 main9.s:10
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP stmnt "" "Execute a single statement
+.CW stmnt
+executes a single language level statement.
+.CW stmnt
+displays each machine level instruction as it is executed. When the executed
+statement is completed the source for the next statement is displayed.
+Unlike
+.CW next ,
+the
+.CW stmnt
+function will trace down through function calls.
+.Ex
+acid: stmnt()
+62: breakpoint	main+0x18 MOVW	R5,0xc(R29)
+62: breakpoint	main+0x1c JAL	Binit(SB)
+62: breakpoint	Binit     ADD	$-0x18,R29
+binit.c:91
+ 89	int
+ 90	Binit(Biobuf *bp, int f, int mode)
+>91	{
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP stopped integer "Report status of stopped process
+.CW stopped
+is called automatically by the interpreter
+every time a process enters the
+.CW Stopped
+state, such as when it hits a breakpoint.
+The pid is passed as the
+.I integer
+argument.  The default implementation just calls
+.CW pstop ,
+but the function may be changed to provide more information or perform fine control
+of execution.  Note that
+.CW stopped
+should return; for example, calling
+.CW step
+in
+.CW stopped
+will recur until the interpreter runs out of stack space.
+.Ex
+acid: defn stopped(pid) {
+	if *lflag != 0 then error("lflag modified");
+	}
+acid: progargs = "-l"
+acid: new();
+acid: while 1 do step();
+<stdin>:7: (error) lflag modified
+acid: stk()
+At pc:0x00001220:main+0x200 ls.c:54
+main(argc=0x00000001,argv=0x7fffffe8) ls.c:48
+	called from _main+0x20 main9.s:10
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP symbols string "Search symbol table
+.CW symbols
+uses the regular expression supplied by
+.I string
+to search the symbol table for symbols whose name matches the
+regular expression.
+.Ex
+acid: symbols("main")
+main	T	0x00001020
+_main	T	0x0000623c
+.Ee
+.\"
+.\"
+.\"
+.Ip \f(CW{}\fP win "" "Start new process in a window
+.CW win
+performs exactly the same function as
+.CW new
+but uses the window system to create a new window for the debugged process.
+The variable
+.CW progargs
+supplies arguments to the new process.
+The environment variable
+.CW $8½srv
+must be set to allow the interpreter to locate the mount channel for the
+window system.
+The window is created in the top left corner of the screen and is
+400x600 pixels in size. The
+.CW win
+function may be modified to alter the geometry.
+The window system will not be able to deliver notes in the new window
+since the pid of the created process is not passed when the server is
+mounted to create a new window.
+.Ex
+acid: win()
+.Ee
binary files /dev/null b/doc/acid.pdf differ
--- /dev/null
+++ b/doc/acidpaper.ms
@@ -1,0 +1,1327 @@
+.TL
+Acid: A Debugger Built From A Language
+.AU
+.I "Phil Winterbottom"
+.AI
+.I "Lucent Technologies Inc"
+.AB
+.FS
+\l'1i'
+.br
+Originally appeared in
+.I
+Proc. of the Winter 1994 USENIX Conf.,
+.R
+pp. 211-222,
+San Francisco, CA;
+and subsequently in the
+.I "Plan 9 Programmer's Manual, Volume 2 (Second Edition)" .
+.FE
+Acid is an unusual source-level symbolic debugger for Plan 9. It is implemented
+as a language interpreter with specialized primitives that provide
+debugger support.  Programs written in the language manipulate
+one or more target processes; variables in the language represent the
+symbols, state, and resources of those processes. 
+This structure allows complex
+interaction between the debugger and the target program and
+provides a convenient method of parameterizing differences between
+machine architectures.
+Although some effort is required to learn
+the debugging language, the richness and flexibility of the
+debugging environment encourages new ways of reasoning about the way
+programs run and the conditions under which they fail.
+.AE
+.NH
+Introduction
+.PP
+The size and complexity
+of programs have increased in proportion to processor speed and memory but
+the interface between debugger and programmer has changed little.
+Graphical user interfaces have eased some of the tedious
+aspects of the interaction. A graphical interface is a convenient
+means for navigating through source and data structures but provides
+little benefit for process control.
+The introduction of a new concurrent language, Alef [Win93], emphasized the
+inadequacies of the existing Plan 9 [Pike90] debugger
+.I db ,
+a distant relative of
+.I adb ,
+and made it clear that a new debugger was required.
+.PP
+Current debuggers like
+.I dbx ,
+.I sdb ,
+and
+.I gdb
+are limited to answering only the questions their authors
+envisage.  As a result, they supply a plethora
+of specialized commands, each attempting to anticipate
+a specific question a user may ask.
+When a debugging situation arises that is beyond the scope
+of the command set, the tool is useless.
+Further,
+it is often tedious or impossible to reproduce an anomalous state
+of the program, especially when
+the state is embedded in the program's data structures.
+.PP
+Acid applies some ideas found in CAD software used for
+hardware test and simulation.
+It is based on the notion that the state and resources of a program
+are best represented and manipulated by a language. The state and resources,
+such as memory, registers, variables, type information and source code
+are represented by variables in the language.
+Expressions provide a computation mechanism and control
+statements allow repetitive or selective interpretation based
+on the result of expression evaluation.
+The heart of the Acid debugger is an interpreter for a small typeless
+language whose operators mirror the operations
+of C and Alef, which in turn correspond well to the basic operations of
+the machine. The interpreter itself knows nothing of the underlying
+hardware; it deals with the program state and resources
+in the abstract.
+Fundamental routines to control
+processes, read files, and interface to the system are implemented
+as builtin functions available to the interpreter.
+The actual debugger functionality is coded
+in Acid; commands are implemented as Acid functions.
+.PP
+This language-based approach has several advantages.
+Most importantly, programs written in Acid, including most of the
+debugger itself, are inherently portable.
+Furthermore, Acid avoids the limitations other debuggers impose when
+debugging parallel programs.  Instead of embedding a fixed
+process model in the debugger, Acid allows the
+programmer to adapt the debugger to handle an
+arbitrary process partitioning or program structure. 
+The ability to
+interact dynamically with an executing process provides clear advantages
+over debuggers constrained to probe a static image.
+Finally, the Acid language is a powerful vehicle for expressing
+assertions about logic, process state, and the contents of data structures.
+When combined with dynamic interaction it allows a
+limited form of automated program verification without requiring
+modification or recompilation of the source code.
+The language is also an
+excellent vehicle for preserving a test suite for later regression testing.
+.PP
+The debugger may be customized by its users; standard
+functions may be modified or extended to suit a particular application
+or preference.
+For example, the kernel developers in our group require a
+command set supporting assembler-level debugging while the application
+programmers prefer source-level functionality.
+Although the default library is biased toward assembler-level debugging,
+it is easily modified to provide a convenient source-level interface.
+The debugger itself does not change; the user combines primitives
+and existing Acid functions in different ways to
+implement the desired interface.
+.NH
+Related Work
+.PP
+DUEL [Gol93], an extension to
+.I gdb
+[Stal91], proposes using a high level expression evaluator to solve
+some of these problems. The evaluator provides iterators to loop over data
+structures and conditionals to control evaluation of expressions.
+The author shows that complex state queries can be formulated
+by combining concise expressions but this only addresses part of the problem.
+A program is a dynamic entity; questions asked when the program is in
+a static state are meaningful only after the program has been `caught' in
+that state. The framework for manipulating the program is still as
+primitive as the underlying debugger. While DUEL provides a means to
+probe data structures it entirely neglects the most beneficial aspect
+of debugging languages: the ability to control processes. Acid is structured
+around a thread of control that passes between the interpreter and the
+target program.
+.PP
+The NeD debugger [May92] is a set of extensions to TCL [Ous90] that provide
+debugging primitives. The resulting language, NeDtcl, is used to implement
+a portable interface between a conventional debugger, pdb [May90], and
+a server that executes NeDtcl programs operating on the target program.
+Execution of the NeDtcl programs implements the debugging primitives
+that pdb expects.
+NeD is targeted at multi-process debugging across a network,
+and proves the flexibility of a language as a means of
+communication between debugging tools. Whereas NeD provides an interface
+between a conventional debugger and the process it debugs, Acid is the
+debugger itself. While NeD has some of the ideas
+found in Acid it is targeted toward a different purpose. Acid seeks to
+integrate the manipulation of a program's resources into the debugger
+while NeD provides a flexible interconnect between components of
+the debugging environment. The choice of TCL is appropriate for its use
+in NeD but is not suitable for Acid. Acid relies on the coupling of the type
+system with expression evaluation, which are the root of its design,
+to provide the debugging primitives.
+.PP
+Dalek [Ols90] is an event based language extension to gdb. State transitions
+in the target program cause events to be queued for processing by the
+debugging language.
+.PP
+Acid has many of the advantages of same process or
+.I local
+.I agent
+debuggers, like Parasight [Aral], without the need for dynamic linking or
+shared memory.
+Acid improves on the ideas of these other systems by completely integrating
+all aspects of the debugging process into the language environment. Of
+particular importance is the relationship between Acid variables,
+program symbols, source code, registers and type information. This
+integration is made possible by the design of the Acid language.
+.PP
+Interpreted languages such as Lisp and Smalltalk are able to provide
+richer debugging environments through more complete information than
+their compiled counterparts. Acid is a means to gather and represent
+similar information about compiled programs through cooperation
+with the compilation tools and library implementers.
+.NH
+Acid the Language
+.PP
+Acid is a small interpreted language targeted to its debugging task.
+It focuses on representing program state and addressing data rather than
+expressing complex computations. Program state is
+.I addressable
+from an Acid program.
+In addition to parsing and executing expressions and providing
+an architecture-independent interface to the target process,
+the interpreter supplies a mark-and-scan garbage collector
+to manage storage.
+.PP
+Every Acid session begins with the loading of the Acid libraries.
+These libraries contain functions, written in Acid, that provide
+a standard debugging environment including breakpoint management,
+stepping by instruction or statement, stack tracing, and
+access to variables, memory, and registers.
+The library contains 600 lines of Acid code and provides
+functionality similar to
+.I dbx .
+Following the loading of the system library, Acid loads
+user-specified libraries; this load sequence allows the
+user to augment or override the standard commands
+to customize the debugging environment.  When all libraries
+are loaded, Acid issues an interactive prompt and begins
+evaluating expressions entered by the user.  The Acid `commands'
+are actually invocations of builtin primitives or previously defined
+Acid functions. Acid evaluates each expression as it is entered and
+prints the result.
+.NH
+Types and Variables
+.PP
+Acid variables are of four basic types:
+.I integer ,
+.I string ,
+.I float ,
+and
+.I list .
+The type of a variable is inferred by the type of the right-hand side of
+an assignment expression.
+Many of the operators can be applied to more than
+one type; for these operators the action of the operator is determined
+by the type of its operands.
+For example,
+the
+.CW +
+operator adds
+.I integer
+and
+.I float
+operands, and concatenates
+.I string
+and
+.I list
+operands.
+Lists are the only complex type in Acid; there are no arrays, structures
+or pointers. Operators provide
+.CW head ,
+.CW tail ,
+.CW append
+and
+.CW delete
+operations.
+Lists can also be indexed like arrays.
+.PP
+Acid has two levels of scope: global and local.
+Function parameters and variables declared in a function body
+using the
+.CW local
+keyword are created at entry to the function and
+exist for the lifetime of a function.
+Global variables are created by assignment and need not be declared.
+All variables and functions in the program
+being debugged are entered in the Acid symbol table as global
+variables during Acid initialization.
+Conflicting variable names are resolved by prefixing enough `$' characters
+to make them unique.
+Syntactically, Acid variables and target program
+symbols are referenced identically.
+However, the variables are managed differently in the Acid
+symbol table and the user must be aware of this distinction.
+The value of an Acid variable is stored in the symbol
+table; a reference returns the value.
+The symbol table entry for a variable or function in the target
+program contains the address of that symbol in the image
+of the program.  Thus, the value of a program variable is
+accessed by indirect reference through the Acid
+variable that has the same name; the value of an Acid variable is the
+address of the corresponding program variable.
+.NH
+Control Flow
+.PP
+The
+.CW while
+and
+.CW loop
+statements implement looping.
+The former
+is similar to the same statement in C.
+The latter evaluates starting and ending expressions yielding
+integers and iterates while an incrementing loop index
+is within the bounds of those expressions.
+.P1
+acid: i = 0; loop 1,5 do print(i=i+1)
+0x00000001
+0x00000002
+0x00000003
+0x00000004
+0x00000005
+acid:
+.P2
+The traditional
+.CW if-then-else 
+statement implements conditional execution.
+.NH
+Addressing
+.PP
+Two indirection operators allow Acid to access values in
+the program being debugged.
+The
+.CW *
+operator fetches a value from the memory image of an
+executing process;
+the
+.CW @
+operator fetches a value from the text file of the process.
+When either operator appears on the left side of an assignment, the value
+is written rather than read.
+.PP
+The indirection operator must know the size of the object
+referenced by a variable.
+The Plan 9 compilers neglect to include this
+information in the program symbol table, so Acid cannot
+derive this information implicitly.
+Instead Acid variables have formats.
+The format is a code
+letter specifying the printing style and the effect of some of the
+operators on that variable.
+The indirection operators look at the format code to determine the
+number of bytes to read or write.
+The format codes are derived from the format letters used by
+.I db .
+By default, symbol table variables and numeric constants
+are assigned the format code
+.CW 'X'
+which specifies 32-bit hexadecimal.
+Printing such a variable yields output of the form
+.CW 0x00123456 .
+An indirect reference through the variable fetches 32 bits
+of data at the address indicated by the variable.
+Other formats specify various data types, for example
+.CW i
+an instruction,
+.CW D
+a signed 32 bit decimal,
+.CW s
+a null-terminated string.
+The
+.CW fmt
+function
+allows the user to change the format code of a variable
+to control the printing format and
+operator side effects.
+This function evaluates the expression supplied as the first
+argument, attaches the format code supplied as the second
+argument to the result and returns that value.
+If the result is assigned to a variable,
+the new format code applies to
+that variable.  For convenience, Acid provides the
+.CW \e
+operator as a shorthand infix form of
+.CW fmt .
+For example:
+.P1
+acid: x=10
+acid: x				 // print x in hex
+0x0000000a 
+acid: x = fmt(x, 'D')		 // make x type decimal
+acid: print(x, fmt(x, 'X'), x\eX) // print x in decimal & hex
+10 0x0000000a 0x0000000a
+acid: x				 // print x in decimal
+10
+acid: x\eo			 // print x in octal
+000000000012
+.P2
+The 
+.CW ++
+and
+.CW --
+operators increment or decrement a variable by an amount
+determined by its format code.  Some formats imply a non-fixed size.
+For example, the
+.CW i
+format code disassembles an instruction into a string.
+On a 68020, which has variable length instructions:
+.P1
+acid: p=main\ei                     // p=addr(main), type INST
+acid: loop 1,5 do print(p\eX, @p++) // disassemble 5 instr's
+0x0000222e LEA	0xffffe948(A7),A7
+0x00002232 MOVL	s+0x4(A7),A2
+0x00002236 PEA	0x2f($0)
+0x0000223a MOVL	A2,-(A7)
+0x0000223c BSR	utfrrune
+acid:
+.P2
+Here,
+.CW main
+is the address of the function of the same name in the program under test.
+The loop retrieves the five instructions beginning at that address and
+then prints the address and the assembly language representation of each.
+Notice that the stride of the increment operator varies with the size of
+the instruction: the
+.CW MOVL
+at 
+.CW 0x0000223a
+is a two byte instruction while all others are four bytes long.
+.PP
+Registers are treated as normal program variables referenced
+by their symbolic assembler language names.
+When a
+process stops, the register set is saved by the kernel
+at a known virtual address in the process memory map.
+The Acid variables associated with the registers point
+to the saved values and the
+.CW *
+indirection operator can then be used to read and write the register set.
+Since the registers are accessed via Acid variables they may
+be used in arbitrary expressions.
+.P1
+acid: PC                            // addr of saved PC
+0xc0000f60 
+acid: *PC
+0x0000623c                          // contents of PC
+acid: *PC\ea
+main
+acid: *R1=10                        // modify R1
+acid: asm(*PC+4)                    // disassemble @ PC+4
+main+0x4 0x00006240 	MOVW	R31,0x0(R29)
+main+0x8 0x00006244 	MOVW	$setR30(SB),R30
+main+0x10 0x0000624c 	MOVW	R1,_clock(SB)
+.P2
+Here, the saved
+.CW PC
+is stored at address
+.CW 0xc0000f60 ;
+its current content is
+.CW 0x0000623c .
+The
+.CW a ' `
+format code converts this value to a string specifying
+the address as an offset beyond the nearest symbol.
+After setting the value of register
+.CW 1 ,
+the example uses the
+.CW asm
+command to disassemble a short section of code beginning
+at four bytes beyond the current value of the
+.CW PC .
+.NH
+Process Interface
+.PP
+A program executing under Acid is monitored through the
+.I proc
+file system interface provided by Plan 9.
+Textual messages written to the
+.CW ctl
+file control the execution of the process.
+For example writing
+.CW waitstop
+to the control file causes the write to block until the target
+process enters the kernel and is stopped. When the process is stopped
+the write completes. The
+.CW startstop
+message starts the target process and then does a
+.CW waitstop
+action.
+Synchronization between the debugger and the target process is determined
+by the actions of the various messages. Some operate asynchronously to the
+target process and always complete immediately, others block until the
+action completes. The asynchronous messages allow Acid to control
+several processes simultaneously.
+.PP
+The interpreter has builtin functions named after each of the control
+messages. The functions take a process id as argument.
+Any time a control message causes the program to execute instructions 
+the interpreter performs two actions when the control operation has completed.
+The Acid variables pointing at the register set are fixed up to point
+at the saved registers, and then
+the user defined function
+.CW stopped
+is executed.
+The 
+.CW stopped
+function may print the current address,
+line of source or instruction and return to interactive mode. Alternatively
+it may traverse a complex data structure, gather statistics and then set
+the program running again.
+.PP
+Several Acid variables are maintained by the debugger rather than the
+programmer.
+These variables allow generic Acid code to deal with the current process,
+architecture specifics or the symbol table.
+The variable
+.CW pid
+is the process id of the current process Acid is debugging.
+The variable
+.CW symbols
+contains a list of lists where each sublist contains the symbol
+name, its type and the value of the symbol.
+The variable
+.CW registers
+contains a list of the machine-specific register names. Global symbols in the target program
+can be referenced directly by name from Acid. Local variables
+are referenced using the colon operator as \f(CWfunction:variable\fP.
+.NH
+Source Level Debugging
+.PP
+Acid provides several builtin functions to manipulate source code.
+The
+.CW file
+function reads a text file, inserting each line into a list.
+The
+.CW pcfile
+and
+.CW pcline
+functions each take an address as an argument.
+The first
+returns a string containing the name of the source file
+and the second returns an integer containing the line number
+of the source line containing the instruction at the address.
+.P1
+acid: pcfile(main)		// file containing main
+main.c
+acid: pcline(main)		// line # of main in source
+11
+acid: file(pcfile(main))[pcline(main)]	// print that line
+main(int argc, char *argv[])
+acid: src(*PC)			// print statements nearby
+ 9
+ 10 void
+>11 main(int argc, char *argv[])
+ 12 {
+ 13	int a;
+.P2
+In this example, the three primitives are combined in an expression to print
+a line of source code associated with an address.
+The
+.CW src
+function prints a few lines of source
+around the address supplied as its argument. A companion routine,
+.CW Bsrc ,
+communicates with the external editor
+.CW sam .
+Given an address, it loads the corresponding source file into the editor
+and highlights the line containing the address.  This simple interface
+is easily extended to more complex functions.
+For example, the
+.CW step
+function can select the current file and line in the editor
+each time the target program stops, giving the user a visual
+trace of the execution path of the program. A more complete interface
+allowing two way communication between Acid and the
+.CW acme
+user interface [Pike93] is under construction. A filter between the debugger
+and the user interface provides interpretation of results from both
+sides of the interface. This allows the programming environment to
+interact with the debugger and vice-versa, a capability missing from the
+.CW sam
+interface.
+The
+.CW src
+and
+.CW Bsrc
+functions are both written in Acid code using the file and line primitives.
+Acid provides library functions to step through source level
+statements and functions. Furthermore, addresses in Acid expressions can be
+specified by source file and line.
+Source code is manipulated in the Acid
+.I list
+data type.
+.NH
+The Acid Library
+.PP
+The following examples define some useful commands and
+illustrate the interaction of the debugger and the interpreter.
+.P1
+defn bpset(addr)                          // set breakpoint
+{
+	if match(addr, bplist) >= 0 then
+		print("bkpoint already set:", addr\ea, "\en");
+	else {
+		*fmt(addr, bpfmt) = bpinst;   // plant it
+		bplist = append bplist, addr; // add to list
+	}
+}
+.P2
+The
+.CW bpset
+function plants a break point in memory. The function starts by
+using the
+.CW match
+builtin to
+search the breakpoint list to determine if a breakpoint is already
+set at the address.
+The indirection operator, controlled by the format code returned
+by the
+.CW fmt
+primitive, is used to plant the breakpoint in memory.
+The variables
+.CW bpfmt
+and
+.CW bpinst
+are Acid global variables containing the format code specifying
+the size of the breakpoint instruction and the breakpoint instruction
+itself.
+These
+variables are set by architecture-dependent library code
+when the debugger first attaches to the executing image.
+Finally the address of the breakpoint is
+appended to the breakpoint list,
+.CW bplist .
+.P1
+defn step()				// single step
+{
+	local lst, lpl, addr, bput;
+
+	bput = 0;			// sitting on bkpoint
+	if match(*PC, bplist) >= 0 then {	
+		bput = fmt(*PC, bpfmt);	// save current addr
+		*bput = @bput;		// replace it
+	}
+
+	lst = follow(*PC);		// get follow set
+
+	lpl = lst;
+	while lpl do {			// place breakpoints
+		*(head lpl) = bpinst;
+		lpl = tail lpl;
+	}
+
+	startstop(pid);			// do the step
+
+	while lst do {			// remove breakpoints
+		addr = fmt(head lst, bpfmt);
+		*addr = @addr;		// replace instr.
+		lst = tail lst;
+	}
+	if bput != 0 then
+		*bput = bpinst;		// restore breakpoint
+}
+.P2
+The
+.CW step
+function executes a single assembler instruction.
+If the
+.CW PC
+is sitting
+on a breakpoint, the address and size of
+the breakpoint are saved.
+The breakpoint instruction
+is then removed using the
+.CW @
+operator to fetch
+.CW bpfmt
+bytes from the text file and to place it into the memory
+of the executing process using the
+.CW *
+operator.
+The
+.CW follow
+function is an Acid
+builtin which returns a follow-set: a list of instruction addresses which
+could be executed next.
+If the instruction stored at the
+.CW PC
+is a branch instruction, the
+list contains the addresses of the next instruction and
+the branch destination; otherwise, it contains only the
+address of the next instruction.
+The follow-set is then used to replace each possible following
+instruction with a breakpoint instruction.  The original
+instructions need not be saved; they remain
+in their unaltered state in the text file.
+The
+.CW startstop
+builtin writes the `startstop' message to the
+.I proc
+control file for the process named
+.CW pid .
+The target process executes until some condition causes it to
+enter the kernel, in this case, the execution of a breakpoint.
+When the process blocks, the debugger regains control and invokes the
+Acid library function
+.CW stopped
+which reports the address and cause of the blockage.
+The
+.CW startstop
+function completes and returns to the
+.CW step
+function where
+the follow-set is used to replace the breakpoints placed earlier.
+Finally, if the address of the original
+.CW PC
+contained a breakpoint, it is replaced.
+.PP
+Notice that this approach to process control is inherently portable;
+the Acid code is shared by the debuggers for all architectures.
+Acid variables and builtin functions provide a transparent interface
+to architecture-dependent values and functions.  Here the breakpoint
+value and format are referenced through Acid variables and the
+.CW follow
+primitive masks the differences in the underlying instruction set.
+.PP
+The
+.CW next
+function, similar to the
+.I dbx
+command of the same name,
+is a simpler example.
+This function steps through
+a single source statement but steps over function calls.
+.P1
+defn next()
+{
+	local sp, bound;
+
+	sp = *SP;			// save starting SP
+	bound = fnbound(*PC);		// begin & end of fn.
+	stmnt();			// step 1 statement
+	pc = *PC;
+	if pc >= bound[0] && pc < bound[1] then
+		return {};
+
+	while (pc<bound[0] || pc>bound[1]) && sp>=*SP do {
+		step();
+		pc = *PC;
+	}
+	src(*PC);
+}
+.P2
+The
+.CW next
+function
+starts by saving the current stack pointer in a local variable.
+It then uses the Acid library function
+.CW fnbound
+to return the addresses of the first and last instructions in
+the current function in a list.
+The
+.CW stmnt
+function executes a single source statement and then uses
+.CW src
+to print a few lines of source around the new
+.CW PC .
+If the new value of the
+.CW PC
+remains in the current function,
+.CW next
+returns.
+When the executed statement is a function call or a return
+from a function, the new value of the
+.CW PC
+is outside the bounds calculated by
+.CW fnbound 
+and the test of the
+.CW while
+loop is evaluated.
+If the statement was a return, the new value of the stack pointer
+is greater than the original value and the loop completes without
+execution.
+Otherwise, the loop is entered and instructions are continually
+executed until the value of the
+.CW PC
+is between the bounds calculated earlier.  At that point, execution
+ceases and a few lines of source in the vicinity of the
+.CW PC
+are printed.
+.PP
+Acid provides concise and elegant expression for control and
+manipulation of target programs. These examples demonstrate how a
+few well-chosen primitives can be combined to create a rich debugging environment.
+.NH
+Dealing With Multiple Architectures
+.PP
+A single binary of Acid may be used to debug a program running on any
+of the five processor architectures supported by Plan 9.  For example,
+Plan 9 allows a user on a MIPS to import the
+.I proc
+file system from an i486-based PC and remotely debug a program executing
+on that processor.
+.PP
+Two levels of abstraction provide this architecture independence.
+On the lowest level, a Plan 9 library supplies functions to
+decode the file header of the program being debugged and
+select a table of system parameters
+and a jump vector of architecture-dependent
+functions based on the magic number.
+Among these functions are byte-order-independent
+access to memory and text files, stack manipulation, disassembly,
+and floating point number interpretation.
+The second level of abstraction is supplied by Acid.
+It consists of primitives and approximately 200 lines
+of architecture-dependent Acid library code that interface the
+interpreter to the architecture-dependent library.
+This layer performs functions such as mapping register names to
+memory locations, supplying breakpoint values and sizes,
+and converting processor specific data to Acid data types.
+An example of the latter is the stack trace function
+.CW strace ,
+which uses the stack traversal functions in the
+architecture-dependent library to construct a list of lists describing
+the context of a process.  The first level of list selects
+each function in the trace; subordinate lists contain the
+names and values of parameters and local variables of
+the functions.  Acid commands and library functions that
+manipulate and display process state information operate
+on the list representation and are independent of the
+underlying architecture.
+.NH
+Alef Runtime
+.PP
+Alef is a concurrent programming language,
+designed specifically for systems programming, which supports both
+shared variable and message passing paradigms.
+Alef borrows the C expression syntax but implements
+a substantially different type system.
+The language provides a rich set of 
+exception handling, process management, and synchronization
+primitives, which rely on a runtime system.
+Alef program bugs are often deadlocks, synchronization failures,
+or non-termination caused by locks being held incorrectly.
+In such cases, a process stalls deep
+in the runtime code and it is clearly
+unreasonable to expect a programmer using the language
+to understand the detailed
+internal semantics of the runtime support functions.
+.PP
+Instead, there is an Alef support library, coded in Acid, that
+allows the programmer to interpret the program state in terms of
+Alef operations.  Consider the example of a multi-process program
+stalling because of improper synchronization.  A stack trace of
+the program indicates that it is waiting for an event in some
+obscure Alef runtime
+synchronization function.
+The function itself is irrelevant to the
+programmer; of greater importance is the identity of the
+unfulfilled event.
+Commands in the Alef support library decode
+the runtime data structures and program state to report the cause
+of the blockage in terms of the high-level operations available to
+the Alef programmer.  
+Here, the Acid language acts
+as a communications medium between Alef implementer and Alef user.
+.NH
+Parallel Debugging
+.PP
+The central issue in parallel debugging is how the debugger is
+multiplexed between the processes comprising
+the program.
+Acid has no intrinsic model of process partitioning; it
+only assumes that parallel programs share a symbol table,
+though they need not share memory.
+The
+.CW setproc
+primitive attaches the debugger to a running process
+associated with the process ID supplied as its argument
+and assigns that value to the global variable
+.CW pid ,
+thereby allowing simple rotation among a group of processes.
+Further, the stack trace primitive is driven by parameters
+specifying a unique process context, so it is possible to
+examine the state of cooperating processes without switching
+the debugger focus from the process of interest.
+Since Acid is inherently extensible and capable of
+dynamic interaction with subordinate processes, the
+programmer can define Acid commands to detect and control
+complex interactions between processes.
+In short, the programmer is free to specify how the debugger reacts
+to events generated in specific threads of the program.
+.PP
+The support for parallel debugging in Acid depends on a crucial kernel
+modification: when the text segment of a program is written (usually to
+place a breakpoint), the segment is cloned to prevent other threads
+from encountering the breakpoint.  Although this incurs a slight performance
+penalty, it is of little importance while debugging.
+.NH
+Communication Between Tools
+.PP
+The Plan 9 Alef and C compilers do not
+embed detailed type information in the symbol table of an
+executable file.
+However, they do accept a command line option causing them to
+emit descriptions of complex data types
+(e.g., aggregates and abstract data types)
+to an auxiliary file.
+The vehicle for expressing this information is Acid source code.
+When an Acid debugging session is 
+subsequently started, that file is loaded with the other Acid libraries.
+.PP
+For each complex object in the program the compiler generates
+three pieces of Acid code.
+The first is a table describing the size and offset of each
+member of the complex data type.  Following is an Acid function,
+named the same as the object, that formats and prints each member.
+Finally, Acid declarations associate the
+Alef or C program variables of a type with the functions
+to print them.
+The three forms of declaration are shown in the following example:
+.P1
+struct Bitmap {
+	Rectangle    0 r;
+	Rectangle   16 clipr;
+	'D'   32 ldepth;
+	'D'   36 id;
+	'X'   40 cache;
+};
+.P2
+.P1
+defn
+Bitmap(addr) {
+	complex Bitmap addr;
+	print("Rectangle r {\en");
+	Rectangle(addr.r);
+	print("}\en");
+	print("Rectangle clipr {\en");
+	Rectangle(addr.clipr);
+	print("}\en");
+	print("	ldepth	", addr.ldepth, "\en");
+	print("	id	", addr.id, "\en");
+	print("	cache	", addr.cache, "\en");
+};
+
+complex Bitmap darkgrey;
+complex Bitmap Window_settag:b;
+.P2
+The
+.CW struct
+declaration specifies decoding instructions for the complex type named
+.CW Bitmap .
+Although the syntax is superficially similar to a C structure declaration,
+the semantics differ markedly: the C declaration specifies a layout, while
+the Acid declaration tells how to decode it.
+The declaration specifies a type, an offset, and name for each
+member of the complex object. The type is either the name of another
+complex declaration, for example,
+.CW Rectangle ,
+or a format code.
+The offset is the number of bytes from the start
+of the object to the member
+and the name is the member's name in the Alef or C declaration.
+This type description is a close match for C and Alef, but is simple enough
+to be language independent.
+.PP
+The
+.CW Bitmap
+function expects the address of a
+.CW Bitmap
+as its only argument.
+It uses the decoding information contained in the
+.CW Bitmap
+structure declaration to extract, format, and print the
+value of each member of the complex object pointed to by
+the argument.
+The Alef compiler emits code to call other Acid functions
+where a member is another complex type; here,
+.CW Bitmap
+calls
+.CW Rectangle
+to print its contents.
+.PP
+The
+.CW complex
+declarations associate Alef variables with complex types.
+In the example,
+.CW darkgrey
+is the name of a global variable of type
+.CW Bitmap
+in the program being debugged.
+Whenever the name
+.CW darkgrey
+is evaluated by Acid, it automatically calls the
+.CW Bitmap
+function with the address of
+.CW darkgrey
+as the argument.
+The second
+.CW complex
+declaration associates a local variable or parameter named
+.CW b
+in function
+.CW Window_settag
+with the
+.CW Bitmap
+complex data type.
+.PP
+Acid borrows the C operators
+.CW .
+and
+.CW ->
+to access the decoding parameters of a member of a complex type.
+Although this representation is sufficiently general for describing
+the decoding of both C and Alef complex data types, it may
+prove too restrictive for target languages with more complicated
+type systems.
+Further, the assumption that the compiler can select the proper
+Acid format code for each basic type in the language is somewhat
+naive.  For example, when a member of a complex type is a pointer,
+it is assigned a hexadecimal type code; integer members are always 
+assigned a decimal type code.
+This heuristic proves inaccurate when an integer field is a
+bit mask or set of bit flags which are more appropriately displayed
+in hexadecimal or octal.
+.NH
+Code Verification
+.PP
+Acid's ability to interact dynamically with
+an executing program allows passive test and
+verification of the target program.  For example,
+a common concern is leak detection in programs using
+.CW malloc .
+Of interest are two items: finding memory that was allocated
+but never freed and detecting bad pointers passed to
+.CW free .
+An auxiliary Acid library contains Acid functions to
+monitor the execution of a program and detect these
+faults, either as they happen or in the automated
+post-mortem analysis of the memory arena.
+In the following example, the
+.CW sort
+command is run under the control of the
+Acid memory leak library.
+.P1
+helix% acid -l malloc /bin/sort
+/bin/sort: mips plan 9 executable
+/lib/acid/port
+/lib/acid/mips
+/lib/acid/malloc
+acid: go()
+now
+is
+the
+time
+<ctrl-d>
+is
+now
+the
+time
+27680 : breakpoint	_exits+0x4	MOVW	$0x8,R1
+acid: 
+.P2
+The
+.CW go
+command creates a process and plants
+breakpoints at the entry to
+.CW malloc
+and
+.CW free .
+The program is then started and continues until it
+exits or stops.  If the reason for stopping is anything
+other than the breakpoints in
+.CW malloc
+and
+.CW free ,
+Acid prints the usual status information and returns to the
+interactive prompt.
+.PP
+When the process stops on entering
+.CW malloc ,
+the debugger must capture and save the address that
+.CW malloc
+will return.
+After saving a stack
+trace so the calling routine can be identified, it places
+a breakpoint at the return address and restarts the program.
+When
+.CW malloc
+returns, the breakpoint stops the program,
+allowing the debugger
+to grab the address of the new memory block from the return register.
+The address and stack trace are added to the list of outstanding
+memory blocks, the breakpoint is removed from the return point, and
+the process is restarted.
+.PP
+When the process stops at the beginning of
+.CW free ,
+the memory address supplied as the argument is compared to the list
+of outstanding memory blocks.  If it is not found an error message
+and a stack trace of the call is reported; otherwise, the
+address is deleted from the list.
+.PP
+When the program exits, the list of outstanding memory blocks contains
+the addresses of all blocks that were allocated but never freed.
+The
+.CW leak
+library function traverses the list producing a report describing
+the allocated blocks.
+.P1 1m
+acid: leak()
+Lost a total of 524288 bytes from:
+    malloc() malloc.c:32 called from dofile+0xe8 sort.c:217 
+    dofile() sort.c:190 called from main+0xac sort.c:161 
+    main() sort.c:128 called from _main+0x20 main9.s:10 
+Lost a total of 64 bytes from:
+    malloc() malloc.c:32 called from newline+0xfc sort.c:280 
+    newline() sort.c:248 called from dofile+0x110 sort.c:222 
+    dofile() sort.c:190 called from main+0xac sort.c:161 
+    main() sort.c:128 called from _main+0x20 main9.s:10 
+Lost a total of 64 bytes from:
+    malloc() malloc.c:32 called from realloc+0x14 malloc.c:129 
+    realloc() malloc.c:123 called from bldkey+0x358 sort.c:1388 
+    buildkey() sort.c:1345 called from newline+0x150 sort.c:285 
+    newline() sort.c:248 called from dofile+0x110 sort.c:222 
+    dofile() sort.c:190 called from main+0xac sort.c:161 
+    main() sort.c:128 called from _main+0x20 main9.s:10
+acid: refs()
+data...bss...stack...
+acid: leak()
+acid: 
+.P2
+The presence of a block in the allocation list does not imply
+it is there because of a leak; for instance, it may have been
+in use when the program terminated.
+The
+.CW refs()
+library function scans the
+.I data ,
+.I bss ,
+and
+.I stack
+segments of the process looking for pointers
+into the allocated blocks.  When one is found, the block is deleted from
+the outstanding block list.
+The
+.CW leak
+function is used again to report the
+blocks remaining allocated and unreferenced.
+This strategy proves effective in detecting
+disconnected (but non-circular) data structures.
+.PP
+The leak detection process is entirely passive.
+The program is not
+specially compiled and the source code is not required.
+As with the Acid support functions for the Alef runtime environment,
+the author of the library routines has encapsulated the
+functionality of the library interface
+in Acid code.
+Any programmer may then check a program's use of the
+library routines without knowledge of either implementation.
+The performance impact of running leak detection is great
+(about 10 times slower),
+but it has not prevented interactive programs like
+.CW sam
+and the
+.CW 8½
+window system from being tested.
+.NH
+Code Coverage
+.PP
+Another common component of software test uses 
+.I coverage 
+analysis.
+The purpose of the test is to determine which paths through the code have
+not been executed while running the test suite.
+This is usually
+performed by a combination of compiler support and a reporting tool run
+on the output generated by statements compiled into the program.
+The compiler emits code that
+logs the progress of the program as it executes basic blocks and writes the
+results to a file. The file is then processed by the reporting tool 
+to determine which basic blocks have not been executed.
+.PP
+Acid can perform the same function in a language independent manner without
+modifying the source, object or binary of the program. The following example
+shows
+.CW ls
+being run under the control of the Acid coverage library.
+.P1
+philw-helix% acid -l coverage /bin/ls
+/bin/ls: mips plan 9 executable
+/lib/acid/port
+/lib/acid/mips
+/lib/acid/coverage
+acid: coverage()
+acid
+newstime
+profile
+tel
+wintool
+2: (error) msg: pid=11419 startstop: process exited
+acid: analyse(ls)
+ls.c:102,105
+	102:     return 1;
+	103: }
+	104: if(db[0].qid.path&CHDIR && dflag==0){
+	105:     output();
+ls.c:122,126
+	122:     memmove(dirbuf+ndir, db, sizeof(Dir));
+	123:     dirbuf[ndir].prefix = 0;
+	124:     p = utfrrune(s, '/');
+	125:     if(p){
+	126:         dirbuf[ndir].prefix = s;
+.P2
+The
+.CW coverage
+function begins by looping through the text segment placing
+breakpoints at the entry to each basic block. The start of each basic
+block is found using the Acid builtin function
+.CW follow .
+If the list generated by
+.CW follow 
+contains more than one
+element, then the addresses mark the start of basic blocks. A breakpoint
+is placed at each address to detect entry into the block. If the result
+of
+.CW follow
+is a single address then no action is taken, and the next address is
+considered. Acid maintains a list of
+breakpoints already in place and avoids placing duplicates (an address may be
+the destination of several branches).
+.PP
+After placing the breakpoints the program is set running.
+Each time a breakpoint is encountered
+Acid deletes the address from the breakpoint list, removes the breakpoint
+from memory and then restarts the program.
+At any instant the breakpoint list contains the addresses of basic blocks
+which have not been executed. 
+The
+.CW analyse
+function reports the lines of source code bounded by basic blocks
+whose addresses are have not been deleted from the breakpoint list.
+These are the basic blocks which have not been executed.
+Program performance is almost unaffected since each breakpoint is executed
+only once and then removed.
+.PP
+The library contains a total of 128 lines of Acid code.
+An obvious extension of this algorithm could be used to provide basic block
+profiling.
+.NH
+Conclusion
+.PP
+Acid has two areas of weakness. As with
+other language-based tools like
+.I awk ,
+a programmer must learn yet another language to step beyond the normal
+debugging functions and use the full power of the debugger.
+Second, the command line interface supplied by the
+.I yacc
+parser is inordinately clumsy.
+Part of the problem relates directly to the use of
+.I yacc
+and could be circumvented with a custom parser.
+However, structural problems would remain: Acid often requires
+too much typing to execute a simple
+command.
+A debugger should prostitute itself to its users, doing whatever
+is wanted with a minimum of encouragement; commands should be
+concise and obvious. The language interface is more consistent than
+an ad hoc command interface but is clumsy to use.
+Most of these problems are addressed by an Acme interface
+which is under construction. This should provide the best of
+both worlds: graphical debugging and access to the underlying acid
+language when required.
+.PP
+The name space clash between Acid variables, keywords, program variables,
+and functions is unavoidable.
+Although it rarely affects a debugging session, it is annoying
+when it happens and is sometimes difficult to circumvent.
+The current renaming scheme
+is too crude; the new names are too hard to remember.
+.PP
+Acid has proved to be a powerful tool whose applications
+have exceeded expectations.
+Of its strengths, portability, extensibility and parallel debugging support
+were by design and provide the expected utility.
+In retrospect,
+its use as a tool for code test and verification and as
+a medium for communicating type information and encapsulating
+interfaces has provided unanticipated benefits and altered our
+view of the debugging process.
+.NH
+Acknowledgments
+.PP
+Bob Flandrena was the first user and helped prepare the paper.
+Rob Pike endured three buggy Alef compilers and a new debugger
+in a single sitting.
+.NH
+References
+.LP
+[Pike90] R. Pike, D. Presotto, K. Thompson, H. Trickey,
+``Plan 9 from Bell Labs'',
+.I
+UKUUG Proc. of the Summer 1990 Conf.,
+.R
+London, England,
+1990.
+.LP
+[Gol93] M. Golan, D. Hanson,
+``DUEL -- A Very High-Level Debugging Language'',
+.I
+USENIX Proc. of the Winter 1993 Conf.,
+.R
+San Diego, CA,
+1993.
+.LP
+[Lin90] M. A. Linton,
+``The Evolution of DBX'',
+.I
+USENIX Proc. of the Summer 1990 Conf.,
+.R
+Anaheim, CA,
+1990.
+.LP
+[Stal91] R. M. Stallman, R. H. Pesch,
+``Using GDB: A guide to the GNU source level debugger'',
+Technical Report, Free Software Foundation,
+Cambridge, MA,
+1991.
+.LP
+[Win93] P. Winterbottom,
+``Alef reference Manual'',
+reprinted in this volume.
+.LP
+[Pike93] Rob Pike,
+``Acme: A User Interface for Programmers'',
+.I
+USENIX Proc. of the Winter 1994 Conf.,
+.R
+San Francisco, CA,
+reprinted in this volume.
+.LP
+[Ols90] Ronald A. Olsson, Richard H. Crawford, and W. Wilson Ho,
+``Dalek: A GNU, improved programmable debugger'',
+.I
+USENIX Proc. of the Summer 1990 Conf.,
+.R
+Anaheim, CA.
+.LP
+[May92] Paul Maybee,
+``NeD: The Network Extensible Debugger''
+.I
+USENIX Proc. of the Summer 1992 Conf.,
+.R
+San Antonio, TX.
+.LP
+[Aral] Ziya Aral, Ilya Gertner, and Greg Schaffer,
+``Efficient debugging primitives for multiprocessors'',
+.I
+Proceedings of the Third International Conference on Architectural
+Support for Programming Languages and Operating Systems,
+.R
+SIGPLAN notices Nr. 22, May 1989.
binary files /dev/null b/doc/acidpaper.pdf differ
--- /dev/null
+++ b/doc/acidtut.ms
@@ -1,0 +1,1062 @@
+.de d0
+.nr dP +1
+.nr dV +1p
+..
+.de d1
+.nr dP -1
+.nr dV -1p
+..
+.nr dT 4
+.de Af	\" acid function
+.CW "\\$1(" "\fI\\$2\fP\f(CW)\fP"
+..
+.TL
+Native Kernel Debugging with Acid
+.AU
+Tad Hunt
+tad@plan9.bell-labs.com
+.br
+Lucent Technologies Inc
+.br
+(Revised 22 May 2000 by Vita Nuova)
+.SH
+Introduction
+.PP
+This tutorial provides an introduction to the Acid debugger. It assumes that you are familiar with the features of a typical source-level debugger. The Acid debugger is built round a command language with a syntax similar to C.
+This tutorial is not an
+introduction to Acid as a whole, but
+offers a brief tour
+of the basic built in and standard library functions,
+especially those needed for debugging native Inferno kernels on a target board.
+.PP
+Acid was originally developed by Phil Winterbottom
+to help debug multi-threaded programs in
+the concurrent language Alef, and provide more sophisticated
+debugging for C programs.
+In the paper
+.I "Acid: A Debugger Built From a Language" ,
+Winterbottom
+discusses Acid's design, including some worked examples of unusual
+applications of Acid to find memory leaks and assist code coverage analysis.
+Following that is the
+.I "Acid Reference Manual" ,
+also by Phil Winterbottom,
+which gives a more precise specification of the Acid debugging language and its libraries.
+.SH
+Preliminaries -- the environment
+.PP
+Acid runs under the host operating system used for cross-development,
+in the same way as the Inferno compilers.
+Before running either compilers or Acid, the following
+environment variables must be set appropriately:
+.TS
+center;
+lf(CW) lf(R)w(4i) .
+ROOT	T{
+the directory in which Inferno lives (eg,
+.CW /usr/inferno ).
+T}
+SYSHOST	T{
+.I host
+operating system type:
+.CW Nt ,
+.CW Solaris ,
+.CW Plan9 ,
+.CW Linux
+or
+.CW FreeBSD
+T}
+OBJTYPE	T{
+.I host
+machine's architecture type:
+.CW 386 ,
+.CW sparc ,
+.CW mips ,
+or
+.CW powerpc
+T}
+.TE
+They might be set by a login shell profile
+(eg,
+Unix
+.CW ".profile" ,
+or
+Plan 9
+.CW lib/profile ).
+Also ensure that the directory
+.P1
+$ROOT/$SYSHOST/$OBJTYPE/bin
+.P2
+is on your search path.
+For example, on a Solaris sparc, one might use:
+.P1
+ROOT=\fIinferno_root\fP
+SYSHOST=Solaris
+OBJTYPE=sparc
+ACIDLIB=$ROOT/lib/acid
+PATH=$ROOT/$SYSHOST/$OBJTYPE/bin:$PATH
+export ROOT ACIDLIB PATH OBJTYPE SYSHOST
+.P2
+where
+.I "inferno_root"
+is the directory in which Inferno lives (eg,
+.CW "/usr/inferno" ).
+.SH
+An Example Program
+.PP
+The first example is not kernel code, but a small program that
+will be compiled but not run, to demonstrate basic Acid commands for
+source and object file inspection.
+The code is shown below:
+.P1
+int
+factorial(int n)
+{
+	if (n == 1)
+		return 1;
+	return n * factorial(n-1);
+}
+
+int f;
+void
+main(void)
+{
+	f = factorial(5);
+}
+
+void
+_main(void)
+{
+	main();
+}
+.P2
+.SH
+Compiling and Linking
+.PP
+The first step is to create an executable.  The example shows the process for creating ARM executables.  Substitute the appropriate compiler and linker for other cpu types.
+.P1
+% 5c factorial.c
+% 5l -o factorial factorial.5
+% ls
+factorial
+factorial.5
+factorial.c
+.P2
+.SH
+Starting Acid
+.PP
+Even without the target machine on which
+to run the program, many Acid features are available.
+The following command starts debugging the
+.CW "factorial"
+executable. Note that, upon startup, Acid will attempt to load some libaries from the directory specified in the
+.CW "ACIDLIB"
+environment variable (defaults to
+.CW "/usr/inferno/lib/acid" ).
+It will also attempt to load the file
+.CW "$HOME/lib/acid" ,
+in which you can place commands to be executed during startup.
+.P1
+% acid factorial
+factorial:Arm plan 9 executable
+
+$ROOT/lib/acid/port
+$ROOT/lib/acid/arm
+acid:
+.P2
+.SH
+Exploring the Executable
+.PP
+To find out what symbols are in the program:
+.P1
+acid: symbols("")
+etext	T	0x00001068
+f	D	0x00002000
+setR12	D	0x00002ffc
+end	B	0x00002008
+bdata	D	0x00002000
+edata	D	0x00002008
+factorial	T	0x00001020
+main	T	0x00001048
+_main	T	0x0000105c
+acid:
+.P2
+The output from the
+.CW symbols()
+function is similar to the output from the
+.I nm (10.1)
+command. The first column is the symbol name, the second column gives the section the symbol is in, and the third column is the address of the symbol.
+.PP
+There is also a
+.CW "symbols"
+global variable.  Variables and functions can have the same names.  It holds the list of symbol information that the
+.CW symbols
+function uses to generate the table:
+.d0
+.P1
+acid: symbols
+{{"etext", T, 0x00001068}, {"f", D, 0x00002000}, {"setR12", D, 0x00002ffc},
+ {"end", B, 0x00002008}, {"bdata", D, 0x00002000}, {"edata", D, 0x00002008},
+ {"factorial", T, 0x00001020}, {"main", T, 0x00001048}, {"_main", T, 0x00001
+05c}}
+acid:
+.P2
+.d1
+In large programs, finding the symbol you are interested in from a list that may be thousands of lines long would be difficult. The string argument of
+.CW symbols()
+is a regular expression against which to match symbols.
+All symbols that contain the pattern will be displayed.  For example:
+.P1
+acid: symbols("main")
+main	T	0x00001048
+_main	T	0x0000105c
+acid: symbols("^main")
+main	T	0x00001048
+acid:
+.P2
+The
+.CW symbols
+function is written in the
+.I acid
+command language and lives in the
+.CW "port"
+library
+.CW $ACIDLIB/port ). (
+.P1
+defn symbols(pattern)
+{
+	local l, s;
+
+	l = symbols;
+	while l do {
+		s = head l;
+		if regexp(pattern, s[0]) then
+			print(s[0], "\t", s[1], "\t", s[2], "\n");
+		l = tail l;
+	}
+}
+.P2
+Acid retrieves the list of symbols from the executable and turns each one into a global variable whose value is the address of the symbol. If the symbol clashes with a builtin name or keyword or a previously defined function, enough
+.CW "$"
+characters are prepended to the name to make it unique.  The list of such renamings is printed at startup.
+.PP
+Most acid functions operate on addresses.  For example, to view the source code for a given address, use the
+.CW src
+function:
+.P1
+acid: src(main)
+/usr/jrf/factorial.c:10
+ 5		return n * factorial(n-1);
+ 6	}
+ 7	
+ 8	int f;
+ 9	void
+>10	main(void)
+ 11	{
+ 12		f = factorial(5);
+ 13	}
+ 14	
+ 15	void
+.P2
+The
+.Af "src" addr
+function displays a section of source code, with the line containing the address passed as an argument in the middle of the display. To print the assembly code beginning at a given address, use the
+.CW asm()
+function.
+.P1
+acid: asm(factorial)
+factorial 0x00001020	MOVW.W	R14,#-0x8(R13)
+factorial+0x4 0x00001024	CMP.S	$#0x1,R0
+factorial+0x8 0x00001028	MOVW.EQ	$#0x1,R0
+factorial+0xc 0x0000102c	RET.EQ.P	#0x8(R13)
+factorial+0x10 0x00001030	MOVW	R0,n+0(FP)
+factorial+0x14 0x00001034	SUB	$#0x1,R0,R0
+factorial+0x18 0x00001038	BL	factorial
+factorial+0x1c 0x0000103c	MOVW	n+0(FP),R2
+factorial+0x20 0x00001040	MUL	R2,R0,R0
+factorial+0x24 0x00001044	RET.P	#0x8(R13)
+main 0x00001048	MOVW.W	R14,#-0x8(R13)
+acid:
+.P2
+The output contains the symbolic address (symbol name+offset, where symbol name is the name of the enclosing function) followed by the absolute address, followed by the disassembled code.
+The
+.Af "asm" addr
+function prints the assembly beginning at
+.I "addr"
+and ending after either 30 lines have been printed, or the end of the function has been reached.  The
+.CW "casm()"
+function continues the assembly listing from where it left off, even past the end of the function and into the next one.
+.P1
+acid: casm()
+main+0x4 0x0000104c	MOVW	$#0x5,R0
+main+0x8 0x00001050	BL	factorial
+main+0xc 0x00001054	MOVW	R0,$f-SB(SB)
+main+0x10 0x00001058	RET.P	#0x8(R13)
+_main 0x0000105c	MOVW.W	R14,#-0x4(R13)
+acid:
+.P2
+All the functions presented so far are written in the acid command language. To see the source of a comand written in the acid command language, use the builtin command
+.CW "whatis [" "\fIname\fP\f(CW ]\fP."
+It prints the definition of the optional argument
+.I "name" .
+If
+.I "name"
+is an Acid builtin,
+.CW whatis
+prints
+.CW "builtin function" .
+.P1
+acid: whatis casm
+defn casm() {
+        asm(lasmaddr);
+}
+acid:
+acid: whatis atof
+builtin function
+acid:
+.P2
+If
+.I name
+is a variable, it prints the type of variable, and for the integer type, gives the format code used to print the value:
+.P1
+acid: whatis pid
+integer variable format D
+acid:
+.P2
+With no arguments,
+.CW whatis
+lists all available functions:
+.P1
+acid: whatis
+Bsrc       bpmask     follow     new        sh         
+_bpconddel bpneq      func       newproc    source     
+_bpcondset bpor       gpr        next       spr        
+_stk       bpprint    include    notestk    spsrch     
+access     bppush     interpret  params     src        
+acidinit   bpset      itoa       pcfile     start      
+addsrcdir  bptab      kill       pcline     startstop  
+asm        casm       kstk       pfl        status     
+atof       cont       labstk     print      stk        
+atoi       debug      line       printto    stmnt      
+bpaddr     dump       linkreg    procs      stop       
+bpand      error      lkstk      rc         stopped    
+bpconddel  file       locals     readfile   strace     
+bpcondset  filepc     lstk       reason     symbols    
+bpdel      findsrc    map        regexp     waitstop   
+bpderef    fmt        match      regs       
+bpeq       fnbound    mem        setproc    
+acid:
+.P2
+The
+.Af "Bsrc" addr
+function brings up an editor on the line containing
+.I "addr" .
+It simply invokes a shell script named
+.CW "B"
+that takes two arguments,
+.I "-line"
+and
+.I "file"
+The shell script invokes
+.CW "$EDITOR +"
+.I "line file" .
+If unset,
+.CW "EDITOR"
+defaults to
+.I vi .
+The shell script, or the
+.CW Bsrc
+function can be easily rewritten to work with your favorite editor.
+.PP
+Entering a symbol name by itself will print the address of the symbol. Prefixing the symbol name with a
+.CW "*"
+will print the value at the address in the variable. Continuing to use our
+.CW "factorial"
+example:
+.P1
+acid: f
+0x00002000
+acid: *f
+0x00000000
+acid:
+.P2
+.SH
+Remote Debugging
+.PP
+Now that you have a basic understanding of how to explore the executable, it is time to examine a real remote debugging session.
+.PP
+We'll use the SA1100 keyboard driver as an example. Examining the kernel configuration file, you'll see the following:
+.P1
+dev
+        keyboard
+link    driver/keyboard port
+        scanfujn860     kbd.h keycodes.h
+link    ./../driver     plat
+        kbdfujitsu      ./../common/ssp.h \e
+                        /driver/keyboard/kbd.h \e
+                        /driver/keyboard/keycodes.h
+port
+        const char *defaultkeyboard = "fujitsu";
+        const char *defaultkeytable = "scanfujn860";
+        int debugkeys = 1;      /* 1 = enabled, 0 = disabled */
+.P2
+This describes the pieces of the keyboard driver which are linked into the kernel. The source code lives in two places,
+.CW "$ROOT/os/driver/keyboard" ,
+and
+.CW "$ROOT/os/plat/sa1100/driver" .
+.PP
+The next step is to build a kernel. Use the
+.I mk
+target
+.CW acid
+to ensure that the Acid symbolic debugging data is
+produced.
+For example:
+.P1
+% mk 'CONF=sword' acid isword.p9.gz
+.P2
+This creates the Acid file
+.CW isword.acid ,
+containing Acid declarations describing kernel structures,
+the kernel executable
+.CW isword.p9 ;
+and finally
+.I gzip s
+a copy of the kernel in
+.CW isword.p9.gz
+to load onto the device. Next, copy the gzipped image onto the device and then boot it. Follow the directions found elsewhere for details of this process.
+.PP
+From a shell prompt on the target device, start the remote debugger by writing the letter
+.CW r
+(for run) to
+.CW "#b/dbgctl" .
+Next, start Acid in remote debug mode, specifying the serial port it is connected to with the
+.CW "-R"
+option.
+.CW "$CONF"
+is the name of the configuration file used, for example
+.CW "sword" .
+.P1
+% acid -R /dev/cua/b -l i$CONF.acid i$CONF
+isword:Arm plan 9 executable
+$ROOT/lib/acid/port
+i$CONF.acid
+$ROOT/lib/acid/arm
+/usr/jrf/lib/acid
+acid:
+.P2
+You are now debugging the kernel that is running on the target device. All of the previously listed commands will work as described before, in addition, there are many more commands available.
+.SH
+Kernel Process Listing
+.PP
+To get a list of kernel processes, use the
+.CW "ps()"
+function:
+.P1
+acid: ps()
+PID     PC              PRI     STATE   NAME
+1       0x00054684      5       Queueing        interp
+2       0x00000000      1       Wakeme  consdbg
+3       0x00000000      5       Wakeme  tcpack
+4       0x00000000      5       Wakeme  Fs.sync
+5       0x00000000      4       Wakeme  touchscreen
+6       0x00054684      5       Queueing        dis
+7       0x00059788      5       Wakeme  dis
+8       0x00054684      5       Queueing        dis
+9       0x00054684      5       Queueing        dis
+10      0x00054684      5       Wakeme  dis
+11      0x0004c26c      1       Running dbg
+acid:
+.P2
+The
+.CW "PC"
+column shows the address the process was executing at when the
+.CW ps
+command retrieved statistics on it. The
+.CW "PRI"
+column lists process priorities. The smaller the number the higher the process priority. Notice that the kernel process (kproc) running the debugger is the highest priority process in the system. The only process you will ever see in the
+.CW "Running"
+state while executing the
+.CW ps
+command will be the debugger, since it is gathering information about the other processes.
+.SH
+Breakpoints
+.PP
+Breakpoints in Inferno, unlike most traditional kernel debuggers, are conditional breakpoints. There are minimally two conditions which must be met. These conditions are address and process id. A breakpoint will only be taken when execution for a specific kernel process reaches the specified address. The user can create additional conditions that are evaluated if the address and process id match. If evaluation of these conditions result in a nonzero value, the breakpoint is taken, otherwise it is ignored, and execution continues.
+.PP
+Again, the best way to proceed is with an example:
+.P1
+acid: setproc(7)
+.P2
+The
+.Af setproc pid
+function selects a kproc to which later commands will be applied;
+the one with process ID (\fIpid\fP)
+in this case.
+.P1
+acid: bpset(keyboardread)
+Waiting...
+7: stopped      flush8to4+0x18c MOVW    (R3<<#4),R3
+.P2
+After selecting a kproc, we set a breakpoint at the address referred to by the
+.CW "keyboardread"
+symbol. As described before, the value of a global variable created from a symbol in the executable is the address of the symbol. In this case the address is the first instruction in the
+.CW "keyboardread()"
+function. Notice that setting a breakpoint stops the kproc from executing. A bit later, we'll see how to get it to continue execution.
+.PP
+Next, display the list of breakpoints using
+.CW "bptab()" :
+.P1
+acid: bptab()
+ID      PID     ADDR                    CONDITIONS
+0       7       keyboardread 0x0003c804 { }
+.P2
+The first column is a unique number that identifies the breakpoint. The second column is the process ID in which the breakpoint will be taken. The third and fourth columns are the address of the breakpoint, first in symbolic form, then in numeric form. Finally, the last column is a list of conditions to evaluate whenever the kproc specified in the
+.CW "PID"
+column hits the the address specified in the
+.CW "ADDR"
+column. When they match, the list of conditions is evaluated. If the result is nonzero, the breakpoint is taken. Since we used the simplified breakpoint creation function,
+.CW "bpset()"
+, there are no additional conditions. Later on, we'll see how to set conditional breakpoints.
+.PP
+Start the selected kproc executing again, and wait for it to hit the breakpoint.
+.P1
+acid: cont()
+.P2
+The
+.CW "cont()"
+function will not return until a breakpoint has been hit, and there is no way to interrupt it. This means you should only set breakpoints that will be hit, otherwise you'll have to reboot the target device and restart your debugging session.
+.PP
+To continue our example, repeatedly hit new line (return, enter)
+on the keyboard on the target device, until the breakpoint occurs:
+.P1
+break 0: pid 7: stopped keyboardread    SUB     $#0xa4,R13,R13
+acid:
+.P2
+This message, followed by the interactive prompt returning tells you that a breakpoint was hit. It gives the breakpoint id, the kernel process id, then the symbolic address at which execution halted, followed by the disassembly of the instruction at that address.
+.PP
+The
+.CW "kstk()"
+function prints a kernel stack trace, beginning with the current frame, all the way back to the call that started the kproc. For each function, it gives the name name, arguments, source file, and line number, followed by the symbolic address, source file, and line number of the caller.
+.d0
+.P1
+acid: kstk()
+At pc:247812:keyboardread /usr/inferno/os/driver/keyboard/devkey
+board.c:350
+keyboardread(offset=0x0000009d,buf=0x001267f8,n=0x00000001) /usr
+/inferno/os/driver/keyboard/devkeyboard.c:350
+        called from kchanio+0x9c /usr/inferno/os/port/sysfile.c:
+75
+kchanio(buf=0x001267f8,n=0x00000001,mode=0x00000000) /usr/infern
+o/os/port/sysfile.c:64
+        called from consread+0x144 /usr/inferno/os/driver/port/d
+evcons
+consread(offset=0x0000009d,buf=0x0043d4fc,n=0x00000400,c=0x0044e
+c38) /
+usr/inferno/os/driver/port/devcons.c:357
+        called from kread+0x164 /usr/inferno/os/port/sysfile.c:2
+97
+kread(fd=0x00000006,n=0x00000400,va=0x0043d4fc) /usr/inferno/os/
+port/sysfile.c:272
+        called from Sys_read+0x84 /usr/inferno/os/port/inferno.c
+:244
+Sys_read() /usr/inferno/os/port/inferno.c:229
+        called from mcall+0x98 /usr/inferno/interp/xec.c:590
+mcall() /usr/inferno/interp/xec.c:569
+        called from xec+0x128 /usr/inferno/interp/xec.c:1098
+xec(p=0x0044edd8) /usr/inferno/interp/xec.c:1077
+        called from vmachine+0xbc /usr/inferno/os/port/dis.c:706
+vmachine() /usr/inferno/os/port/dis.c:677
+        called from _main+0x50 /usr/inferno/os/plat/sa1100/infern
+o/main.c:237
+acid:
+.P2
+.d1
+There is another kernel stack dump function,
+.CW "lkstk()"
+which shows the same information as
+.CW "kstk()"
+plus the names and values of local variables. Notice that in addition to the
+`called from'
+information, each local variable and its value is listed on a line by itself.
+.d0
+.P1
+acid: lkstk()
+At pc:247812:keyboardread /usr/inferno/os/driver/keyboard/devkeyboard.
+c:350
+keyboardread(offset=0x00000018,buf=0x001267f9,n=0x00000001) /usr/inferno
+/os/driver/keyboard/devkeyboard.c:350
+        called from kchanio+0x9c /usr/inferno/os/port/sysfile.c:75
+        tmp=0x00000000
+kchanio(buf=0x001267f9,n=0x00000001,mode=0x00000000) /usr/inferno/os/por
+t/sysfile.c:64
+        called from consread+0x144 /usr/inferno/os/driver/port/devcons
+        c=0x0045a858
+        r=0x00000001
+consread(offset=0x00000015,buf=0x0043d4fc,n=0x00000400,c=0x0044ec38) /us
+r/inferno/os/driver/port/devcons.c:357
+        called from kread+0x164 /usr/inferno/os/port/sysfile.c:297
+        r=0x00000001
+        ch=0x0000006c
+        eol=0x00000000
+        i=0x00000000
+        mt=0x60000053
+        tmp=0x0007317c
+        l=0x0044ec38
+        p=0x00049754
+kread(fd=0x00000006,n=0x00000400,va=0x0043d4fc) /usr/inferno/os/port/sys
+file.c:272
+        called from Sys_read+0x84 /usr/inferno/os/port/inferno.c:244
+        c=0x0044ec38
+        dir=0x00000000
+Sys_read() /usr/inferno/os/port/inferno.c:229
+        called from mcall+0x98 /usr/inferno/interp/xec.c:590
+        f=0x0044eff0
+        n=0x00000400
+mcall() /usr/inferno/interp/xec.c:569
+        called from xec+0x128 /usr/inferno/interp/xec.c:1098
+        ml=0x0043d92c
+        f=0x0044eff0
+xec(p=0x0044edd8) /usr/inferno/interp/xec.c:1077
+        called from vmachine+0xbc /usr/inferno/os/port/dis.c:706
+vmachine() /usr/inferno/os/port/dis.c:677
+        called from _main+0x50 /usr/inferno/os/plat/sa1100/inferno/main.
+c:237
+        r=0x0044edd8
+        o=0x0044ee50
+.P2
+.d1
+The
+.CW "step()"
+function allows the currently selected process to execute a single instruction, and then stop.
+.P1
+acid: step()
+break 1: pid 7: stopped keyboardread+0x4   MOVW  R14,#0x0(R13)
+acid:
+.P2
+The
+.CW "bpdel" (
+.I id )
+command deletes the breakpoint identified by
+.I id :
+.P1
+acid: bpdel(0)
+.P2
+The
+.CW "start()"
+command places the kproc back into the state it was in when it was stopped.
+.P1
+acid: start(7)
+acid:
+.P2
+Now lets look at how to set conditional breakpoints.
+.d0
+.P1
+acid: bpcondset(7, keyboardread, {bppush(_startup), bpderef()})
+Waiting...
+7: stopped      sched+0x20      MOVW    #0xffffff70(R12),R6
+acid: bptab()
+ID      PID     ADDR                    CONDITIONS
+0       7       keyboardread 0x0003c804 {
+                                        {"p", 0x00008020}
+                                        {"*", 0x00000000} }
+acid: *_startup = 0
+acid: cont()
+.P2
+.d1
+Conditional breakpoints are set with
+.CW "bpcondset()"
+. It takes three arguments, the kernel process id, the address, and a list of stack based operations which are executed if the pid and addr match. The operations push values onto the stack, and if at the end of execution, a nonzero value is on the top of the stack, the breakpoint is taken. Examining the list of breakpoints with the
+.CW "bptab()"
+function shows the list of conditions to apply. The list is a bit confusing to read, but the
+.CW ""p""
+means push and the
+.CW ""*""
+means
+.I dereference .
+.PP
+No matter how much you type on the keyboard, this particular breakpoint will never be taken. That's because before continuing, we set the value at the address
+.CW "_startup"
+to zero, so whenever execution reaches
+.CW "keyboardread"
+in kproc number 7, it pushes the address
+.CW "_startup" ,
+then pops it and pushes the word at that address. Since the top of the stack is zero, the breakpoint is ignored.
+.PP
+This contrived example may not be all that useful, but you can use a similar method in your driver to examine some state before making the decision to take the breakpoint.
+.SH
+Examining Registers
+.PP
+There are three commands to dump registers:
+.CW gpr() ,
+.CW spr()
+and
+.CW "regs()" .
+The
+.CW "gpr()"
+function dumps the general purpose registers,
+.CW "spr()"
+dumps special purpose registers (such as the
+.CW "PC"
+and
+.CW "LINK "
+registers), and
+.CW "regs()"
+dumps both:
+.d0
+.P1
+acid: regs()
+PC      0x0004a3b0 sched+0x20  /home/tad/inf2.1/os/port/proc.c:82
+LINK    0x0004b8e8 kchanio+0xa4  /home/tad/inf2.1/os/port/sysfile.c:75
+SP      0x00453c4c
+R0      0x00458798 R1   0x000fdf9c R2   0x0003c804 R3   0x00000000
+R4      0xffffffff R5   0x00000001 R6   0x00458798 R7   0x00000001
+R8      0x001267f8 R9   0x00000000 R10  0x0044ee50 R11  0x00029f9c
+R12     0x000fc854
+acid:
+.P2
+.d1
+.SH
+Complex Types
+.PP
+When reading in the symbol table, Acid treats all of the symbols in the executable as pointers to integers. This is fine for global integer variables, but it makes examining more complex types difficult. Luckily there is a solution. Acid allows you to create a description for more complex types, and a function which will automatically be called for these complex types. In fact, the compiler can automatically generate the acid code to describe these complex types. For example, if we wanted to print out the devtab structure for the keyboard driver, we can just give its name:
+.P1
+acid: whatis keyboarddevtab
+integer variable format a complex Dev
+acid: keyboarddevtab
+        dc      107
+        name    0x0010e0ea
+        reset   0x0003c3fc
+        init    0x0003c438
+        attach  0x0003c5dc
+        clone   0x000480d0
+        walk    0x0003c600
+        stat    0x0003c640
+        open    0x0003c680
+        create  0x0004881c
+        close   0x0003c768
+        read    0x0003c804
+        bread   0x0004883c
+        write   0x0003c968
+        bwrite  0x00048900
+        remove  0x00048978
+        wstat   0x00048998
+acid:
+.P2
+Acid knows the keyboarddevtab variable is of type Dev, and it prints it by invoking the function Dev(keyboarddevtab).
+.P1
+acid: whatis Dev
+complex Dev {
+        'D' 0 dc;
+        'X' 4 name;
+        'X' 8 reset;
+        'X' 12 init;
+        'X' 16 attach;
+        'X' 20 clone;
+        'X' 24 walk;
+        'X' 28 stat;
+        'X' 32 open;
+        'X' 36 create;
+        'X' 40 close;
+        'X' 44 read;
+        'X' 48 bread;
+        'X' 52 write;
+        'X' 56 bwrite;
+        'X' 60 remove;
+        'X' 64 wstat;
+};
+.P3
+defn Dev(addr) {
+        complex Dev addr;
+        print("\etdct",addr.dc,"\en");
+        print("\etnamet",addr.nameX,"\en");
+        print("\etresett",addr.resetX,"\en");
+        print("\etinitt",addr.initX,"\en");
+        print("\etattacht",addr.attachX,"\en");
+        print("\etclonet",addr.cloneX,"\en");
+        print("\etwalkt",addr.walkX,"\en");
+        print("\etstatt",addr.statX,"\en");
+        print("\etopent",addr.openX,"\en");
+        print("\etcreatet",addr.createX,"\en");
+        print("\etcloset",addr.closeX,"\en");
+        print("\etreadt",addr.readX,"\en");
+        print("\etbreadt",addr.breadX,"\en");
+        print("\etwritet",addr.writeX,"\en");
+        print("\etbwritet",addr.bwriteX,"\en");
+        print("\etremovet",addr.removeX,"\en");
+        print("\etwstatt",addr.wstatX,"\en");
+}
+.P2
+Notice the complex type definition and the function to print the type both have the same name. If we know that an address is the address of a complex type, even though acid may not
+(say we're storing multiple types of data in a void pointer),
+we can print the complex type by calling the type printing function ourselves.
+.P1
+acid: print(fmt(keyboarddevtab, 'X'))
+0x00106d50
+acid: Dev(0x00106d50)
+        dc      107
+        name    0x0010e0ea
+        reset   0x0003c3fc
+        init    0x0003c438
+        attach  0x0003c5dc
+        clone   0x000480d0
+        walk    0x0003c600
+        stat    0x0003c640
+        open    0x0003c680
+        create  0x0004881c
+        close   0x0003c768
+        read    0x0003c804
+        bread   0x0004883c
+        write   0x0003c968
+        bwrite  0x00048900
+        remove  0x00048978
+        wstat   0x00048998
+acid:
+.P2
+.SH
+Conclusion
+.PP
+This introduction to using Acid for remote debugging Inferno kernels should be enough to get you started. As a tutorial, it only describes how to use some of the features of the debugger, and does not attempt to describe how to do advanced debugging such as writing your own functions, or modifying existing ones. Exploring the source, setting breakpoints, single stepping through code, and examining the contents of variables are the usual uses of a debugger. This tutorial gives examples of all of these.
+.PP
+For a more in depth discussion of the acid command language, and how to write your own acid functions, see the manual page
+.I acid (10.1)
+and Phil Winterbottom's papers on the Acid Debugger,
+reprinted in this volume.
+.TL
+Appendix
+.LP
+There are two important differences between Acid described in the
+accompanying paper, and Acid as distributed with Inferno for use in
+kernel debugging.
+.SH
+Connecting Acid to the remote Inferno kernel
+.PP
+A remote Plan 9 kernel can be debugged in the same
+way as a Plan 9 user process, using the
+file server
+.I rdbfs (4).
+It is a user-level file server on Plan 9 that
+uses a special debugging protocol on a serial connection to
+the remote kernel, but on the Plan 9 side serves a file system interface
+like that of
+.I proc (3),
+for use by Acid.
+Acid therefore does not need any special code to access the remote kernel's memory,
+or exert control over it.
+.PP
+Inferno's version of Acid currently runs under the host operating systems,
+which do not support such a mechanism (except for Plan 9).
+Instead, Acid itself provides a special debugging protocol,
+with (host) platform-specific interface code to access a serial port.
+This might well be addressed in future by implementing the native kernel debugger
+in Limbo.
+.SH
+Handling of breakpoints
+.PP
+.de Ip
+.KS
+.LP
+.tl '\f2\\$1\fP\ \ \f(CW\\$2(\f2\\$3\f(CW)\f1''\\$4'
+.IP
+..
+.de Ex
+.KE
+.KS
+.IP
+.ft CW
+.ta 4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n +4n
+.nf
+.in +4n
+.br
+..
+.de Ee
+.fi
+.ft 1
+.br
+.in -4n
+.KE
+..
+The following functions are provided by the Acid library
+.CW $ROOT/lib/acid/$OBJTYPE
+for use in native kernel debugging.
+In several cases they change the behavior described in the Acid manual.
+The functions are:
+.P1
+	id = bpset(addr)
+	id = bpcondset(pid, addr, list)
+	bppush(val)
+	bpderef()
+	bpmask()
+	bpeq()
+	bpneq()
+	bpand()
+	bpor()
+	bptab()
+	addr = bpaddr(id)
+	bpdel(id)
+	bpconddel(id)
+.P2
+.PP
+With traditional breakpoints, when a program reaches an address at which a breakpoint is set, execution is halted, and the debugger is notified. In applications programming, this type of breakpoint is sufficient because communicating the break in execution to the debugger is handled by the operating system. The traditional method of handling breakpoints breaks down when program being debugged is the kernel. A breakpoint cannot entirely suspend the execution of the kernel because there is no other program that can handle the communication to the debugger. 
+.PP
+Some operating systems solve this problem by including a
+`mini' operating system,
+a self-contained program within the kernel that has its own code to handle the hardware used to communicate with the remote debugger or user. There are many problems with this mechanism. First, the debugger code that lives inside the kernel must duplicate a lot of code contained elsewhere in the kernel. This makes the kernel much bigger, and can increase maintenance costs. Typically this type of debug support treats the kernel as having a single thread of control, so a breakpoint stops everything while the user decides what to do about it. The only places in the kernel breakpoints cannot be set are in the debugger itself, and in the code that handles notifying the debugger of the breakpoint. 
+.PP
+The Inferno kernel takes a different approach. The remote debug support is provided by a device driver that makes use of kernel services. Communication with the remote debugger is handled by a kernel process dedicated entirely to that task. All breakpoints can be considered to be minimally conditional on two values. First, the address to take the break at, and second, the kernel process to take the break in. This method allows the kernel debugger to be implemented as a regular Inferno device driver. The device driver can make use of all the APIs available to device drivers, it does not need to be self contained. Additionally, conditional breakpoints can be set anywhere in the kernel, with two exceptions. As with traditional debugger implementations, breakpoints can not be set in the code that handles notifying the debugger of the breakpoint. Unlike traditional implementations, the code that handles the execution and evaluation of the conditions applied to the breakpoint is the only other place breakpoint
+cannot be set. Since both of these parts of the kernel code are self contained, the user can set breakpoints in any other kernel routines. For example, the user could set a breakpoint in
+.CW kread() ,
+for a given kernel process, but the debugger can still call
+.CW kread()
+itself.
+.PP
+Use of conditional breakpoints can help make the debugging process more efficient. If there is a bug that occurs in the Nth iteration of a loop, with unconditional breakpoints, user intervention is required N-1 times before reaching the state the bug occurs in. Conditional breakpoints give the user the ability to automatically check the value of N, and only take the breakpoint when it reaches the critical value.
+.PP
+The following changed
+and additional functions in the Acid library provide access
+to this extended breakpoint support:
+.SH
+Setting Breakpoints
+.LP
+.\"
+.\"
+.\"
+.Ip integer bpset integer "Set a breakpoint
+.CW bpset
+places an unconditional breakpoint for the currently
+selected kernel process at the address specified
+by its
+.I integer
+argument.
+It returns the ID of the newly created breakpoint, or the nil list on error.
+It is simply shorthand for a call
+.Ex
+bpcondset(pid, addr, {})
+.Ee
+where
+.I pid
+is the global variable identifying the currently selected process,
+.I addr
+is the user-supplied address for the breakpoint,
+and
+.CW {}
+is the empty list, signifying no conditions.
+.Ip integer bpcondset "pid,addr,list" "Set conditional breakpoint
+Sets a conditional breakpoint at addr for the kernel process identified by
+.I pid .
+The
+.I list
+argument is a list of operations that are executed when execution reaches
+.I addr .
+If execution results in a a non-zero value on the top of the stack, the breakpoint is taken, otherwise it is skipped. 
+The
+.I list
+is in reverse polish notation format, and has these operations:
+.Ex
+PUSH
+DEREF   (pop val, push *(ulong*)val)
+MASK    (pop mask, pop value, push value & mask)
+EQ      (pop v1, pop v2, push v1 == v2)
+NEQ     (pop v1, pop v2, push v1 != v2)
+AND     (pop v1, pop v2, push v1 && v1)
+OR      (pop v1, pop v2, push v1 || v2)
+.Ee
+Condition lists are executed in a single pass, starting with the first command in the list, ending with the last. If a nonzero value is on the top of the stack at the end of execution, the breakpoint is taken, otherwise it is skipped.
+.RS
+.LP
+In effect, there are two mandatory conditions, the address of the breakpoint, and the kernel process id. These two conditions must be met for the condition list to be processed. If these conditions are met, the entire condition list is processed, there is no short circuit evaluation path.
+.LP
+For example, given the following code fragment:
+.P1 +.4i
+int i;
+
+for(i=0; i<1000; i++) {
+	...
+}
+.P2
+the following call to
+.CW bpcondset()
+sets a conditional breakpoint to be taken when execution reaches
+.I addr
+in kernel process
+.I pid
+on the 500th iteration of the loop:
+.P1 +.4i
+bpcondset(pid, addr, {bppush(i),
+		bpderef(), bppush(500), bpeq()}); 
+.P2
+.RE
+.SH
+Condition List Construction
+.LP
+.Ip list bppush val "Construct breakpoint stack
+Push val onto the stack.
+.KE
+.Ip list bpderef ""  "Construct breakpoint stack
+Replace the value at the top of the stack with the value found at the address obtained by treating value at the top of the stack as an address. Pop the value on the top of the stack, treat it as a ulong*, and push the value at the address.
+.Ex
+addr = pop(); 
+push(*(ulong*)addr); 
+.Ee
+.Ip list bpmask "" "Construct breakpoint stack
+Replace the top two values on the stack with the value obtained by masking the second value on the stack with the top of the stack. 
+.Ex
+mask = pop(); 
+value = pop(); 
+push(value & mask); 
+.Ee
+.Ip list bpeq "" "Construct breakpoint stack
+Comparison of the top two values on the stack. Replace the top two values on the stack with a 1 if the values are equal, or a zero if they are not. 
+.Ex
+v1 = pop(); 
+v2 = pop(); 
+push(v1 == v2); 
+.Ee
+.Ip list bpneq "" "Construct breakpoint stack
+Negative comparison of the top two values on the stack. Replace the top two values on the stack with a 0 if the values are equal, or 1 if they are not. 
+.Ex
+v1 = pop(); 
+v2 = pop(); 
+push(v1 != v2); 
+.Ee
+.Ip list bpand "" "Construct breakpoint stack
+Logical and of the top two values on the stack. Replace the top two values on the stack with a 0 if both are zero, or 1 if both are nonzero. 
+.Ex
+v1 = pop(); 
+v2 = pop(); 
+push(v1 && v2); 
+.Ee
+.Ip list bpor ""   "Construct breakpoint stack
+Logical or of the top two values on the stack. Replace the top two values on the stack with a 1 if either is nonzero, 0 otherwise. 
+.Ex
+v1 = pop(); 
+v2 = pop(); 
+push(v1 || v2);
+.Ee
+.SH
+Breakpoint Status
+.LP
+.Ip {} bptab "" "List active breakpoints
+Prints the list of breakpoints containing the following information in order: breakpoint number, kernel process id, breakpoint address, and the list of conditions to execute to determine if the breakpoint will be taken. 
+.Ex
+acid: bptab() 
+ID	PID	ADDR				CONDITIONS 
+0	1	consread+0x20 0x216cc	{} 
+acid: 
+.Ee
+.Ip integer bpaddr id  "Address of breakpoint
+Returns the address the breakpoint identified by
+.I id
+is set to trigger on.
+.KE
+.SH
+Deleting breakpoints
+.Ip {} bpdel id "Delete breakpoint
+Delete the breakpoint identified by
+.I  id .
+Shorthand for bpconddel(). 
+.KE
+.Ip {} bpconddel id  "Delete conditional breakpoint
+Delete the conditional breakpoint identified by the integer
+.I id .
+.KE
binary files /dev/null b/doc/acidtut.pdf differ
--- /dev/null
+++ b/doc/acme/acme.ms
@@ -1,0 +1,1295 @@
+.de EX
+.nr x \\$1v
+\\!h0c n \\nx 0
+..
+.de FG		\" start figure caption: .FG filename.ps verticalsize
+.KF
+.BP \\$1 \\$2
+.sp .5v
+.EX \\$2v
+.ps -1
+.vs -1
+..
+.de fg		\" end figure caption (yes, it is clumsy)
+.ps
+.vs
+.br
+\l'1i'
+.KE
+..
+.TL
+Acme: A User Interface for Programmers
+.AU
+.I "Rob Pike
+.I rob@plan9.bell-labs.com
+.SP .22i exactly
+.AB
+.FS
+\l'1i'
+.br
+Originally appeared in
+.I
+Proc. of the Winter 1994 USENIX Conf.,
+.R
+pp. 223-234,
+San Francisco, CA
+.br
+Reprinted in
+.I "Plan 9 Programmer's Manual: Volume 2"
+(Second Edition), AT&T 1995.
+.FE
+A hybrid of window system, shell, and editor, Acme gives text-oriented
+applications a clean, expressive, and consistent style of interaction.
+Traditional window systems support interactive client programs and offer libraries of
+pre-defined operations such as pop-up menus
+and buttons to promote a consistent
+user interface among the clients.
+Acme instead provides its clients with a fixed user interface and
+simple conventions to encourage its uniform use.
+Clients access the facilities of Acme through a file system interface;
+Acme is in part a file server that exports device-like files that may be
+manipulated to access and control the contents of its windows.
+Written in a concurrent programming language,
+Acme is structured as a set of communicating processes that neatly subdivide
+the various aspects of its tasks: display management, input, file server, and so on.
+.PP
+Acme attaches distinct functions to the three mouse buttons:
+the left selects text;
+the middle executes textual commands;
+and the right combines context search and file opening
+functions to integrate the various applications and files in
+the system.
+.PP
+Acme works well enough to have developed
+a community that uses it exclusively.
+Although Acme discourages the traditional style of interaction
+based on typescript windows\(emteletypes\(emits
+users find Acme's other services render
+typescripts obsolete. 
+.AE
+.SH
+History and motivation
+.PP
+The usual typescript style of interaction with
+Unix and its relatives is an old one.
+The typescript\(eman intermingling of textual commands and their
+output\(emoriginates with the scrolls of paper on teletypes.
+The advent of windowed terminals has given each user what
+amounts to an array of teletypes, a limited and unimaginative
+use of the powers of bitmap displays and mice.
+Systems like the Macintosh
+that do involve the mouse as an integral part of the interaction
+are geared towards general users, not experts, and certainly
+not programmers.
+Software developers, at least on time-sharing systems, have been left behind.
+.FG ./acme.fig1 5i
+Figure 1.  A small Acme screen\(emnormally it runs on a larger display\(emdemonstrating
+some of the details discussed in the text.
+The right column contains some guide files,
+a mailbox presented by Acme's mail program,
+the columnated display of files in Acme's own source directory,
+a couple of windows from the OED browser,
+a debugger window,
+and an error window showing diagnostics from a compilation.
+The left column holds a couple of source files
+.CW dat.h "" (
+and
+.CW acme.l ),
+another debugger window displaying a stack trace,
+and a third source file
+.CW time.l ). (
+.CW Time.l
+was opened from the debugger by clicking the right mouse button
+on a line in the stack window;
+the mouse cursor landed on the offending line of
+.CW acme.l
+after a click on the compiler message.
+.fg
+.PP
+Some programs have mouse-based editing of
+text files and typescripts;
+ones I have built include
+the window systems
+.CW mux
+[Pike88]
+and
+.CW 8½
+[Pike91]
+and the text editor
+Sam [Pike87].
+These have put the programmer's mouse to some productive work,
+but not wholeheartedly.  Even experienced users of these programs
+often retype text that could be grabbed with the mouse,
+partly because the menu-driven interface is imperfect
+and partly because the various pieces are not well enough integrated.
+.PP
+Other programs\(emEMACS [Stal93] is the prime example\(emoffer a high
+degree of integration but with a user interface built around the
+ideas of cursor-addressed terminals that date from the 1970's.
+They are still keyboard-intensive and
+dauntingly complex.
+.PP
+The most ambitious attempt to face these issues was the Cedar
+system, developed at Xerox [Swei86].
+It combined a new programming language, compilers,
+window system, even microcode\(ema complete system\(emto
+construct a productive, highly
+integrated and interactive environment
+for experienced users of compiled languages.
+Although successful internally, the system was so large
+and so tied to specific hardware that it never fledged.
+.PP
+Cedar was, however, the major inspiration for Oberon [Wirt89],
+a system of similar scope but much smaller scale.
+Through careful selection of Cedar's ideas, Oberon shows
+that its lessons can be applied to a small, coherent system
+that can run efficiently on modest hardware.
+In fact, Oberon probably
+errs too far towards simplicity: a single-process system
+with weak networking, it seems an architectural throwback.
+.PP
+Acme is a new program,
+a combined window system, editor, and shell,
+that applies
+some of the ideas distilled by Oberon.
+Where Oberon uses objects and modules within a programming language (also called Oberon),
+Acme uses files and commands within an existing operating system (Plan 9).
+Unlike Oberon, Acme does not yet have support for graphical output, just text.
+At least for now, the work on Acme has concentrated on
+producing the smoothest user interface possible for a programmer
+at work.
+.PP
+The rest of this paper describes Acme's interface,
+explains how programs can access it,
+compares it to existing systems,
+and finally presents some unusual aspects of its implementation.
+.SH
+User interface
+.PP
+.FG ./acme.fig2 3i
+Figure 2.  An Acme window showing a section of code.
+The upper line of text is the tag containing the file name,
+relevant commands, and a scratch area (right of the vertical bar);
+the lower portion of the window is the
+body, or contents, of the file.
+Here the scratch area contains a command for the middle button
+.CW mk ) (
+and a word to search for with the right button
+.CW cxfidalloc ). (
+The user has just
+clicked the right button on
+.CW cxfidalloc
+and Acme has searched for the word, highlighted it,
+and moved the mouse cursor there.  The file has been modified:
+the center of the layout box is black and the command
+.CW Put
+appears in the tag.
+.fg
+Acme windows are arrayed in columns (Figure 1) and are used more
+dynamically than in an environment like X Windows or
+.CW 8½
+[Sche86, Pike91].
+The system frequently creates them automatically and the user
+can order a new one with a single mouse button click.
+The initial placement of a new window is determined
+automatically, but the user may move an existing window anywhere
+by clicking or dragging a
+.I "layout box
+in the upper left corner of
+the window.
+.PP
+Acme windows have two parts: a
+.I tag
+holding a single line of text,
+above a
+.I body
+holding zero or more lines (Figure 2).
+The body typically contains an image of a file being edited
+or the editable output of a
+program, analogous to an
+EMACS shell
+window.  The tag contains
+the name of the window
+(usually the name of the associated
+file or directory), some built-in commands, and a scratch area to hold arbitrary text.
+If a window represents a directory, the name in the tag ends with
+a slash and the body contains a list of the names of the files
+in the directory.
+Finally, each non-empty body holds a scroll bar at the left of the text.
+.PP
+Each column of windows also has a layout box and a tag.
+The tag has no special meaning, although Acme pre-loads it with a few
+built-in commands.
+There is also a tag across the whole display, also loaded with
+helpful commands and a list of active processes started
+by Acme.
+.PP
+Typing with the keyboard and selecting with the left button are as in
+many other systems, including the Macintosh,
+.CW 8½ ,
+and Sam.
+The middle and right buttons are used, somewhat like the left button,
+to `sweep' text, but the indicated text is treated in a way
+that depends on the text's location\(em\f2context\f1\(emas well as its content.
+This context, based on the directory of the file containing the text,
+is a central component of Acme's style of interaction.
+.PP
+Acme has no single notion of `current directory'.
+Instead, every command, file name,
+action, and so on is interpreted or executed in the directory named by the
+tag of the window containing the command.  For example, the string
+.CW mammals
+in a window labeled
+.CW /lib/
+or
+.CW /lib/insects
+will be interpreted as the file name
+.CW /lib/mammals
+if such a file exists.
+.PP
+Throughout Acme, the middle mouse button is used to execute commands
+and the right mouse button is used to locate and select files and text.
+Even when there are no true files on which to operate\(emfor example
+when editing mail messages\(emAcme and its applications use
+consistent extensions of these basic functions.
+This idea is as vital to Acme as icons are to the Macintosh.
+.PP
+The middle button executes commands: text swept with the button
+pressed is underlined; when the button is released, the underline is
+removed and the indicated text is executed.
+A modest number of commands are recognized as built-ins: words like
+.CW Cut ,
+.CW Paste ,
+and
+.CW New
+name
+functions performed directly by Acme.
+These words often appear in tags to make them always available,
+but the tags are not menus: any text anywhere in Acme may be a command.
+For example, in the tag or body of any window one may type
+.CW Cut ,
+select it with the left button, use the middle button to execute it,
+and watch it disappear again.
+.PP
+If the middle button indicates a command that is not recognized as a built-in,
+it is executed in the directory
+named by the tag of the window holding the text.
+Also, the file to be executed is searched for first in that directory.
+Standard input is connected to
+.CW /dev/null ,
+but standard and error outputs are connected to an Acme window,
+created if needed, called
+\f2dir\f(CW/+Errors\f1 where
+.I dir
+is the directory of the window.
+(Programs that need interactive input use a different interface, described below.)
+A typical use of this is to type
+.CW mk
+(Plan 9's
+.CW make )
+in the scratch area in the tag of a C source window, say
+.CW /sys/src/cmd/sam/regexp.c ,
+and execute it.
+Output, including compiler errors, appears in the window labeled
+.CW /sys/src/cmd/sam/+Errors ,
+so file names in the output are associated with the windows and directory
+holding the source.
+The
+.CW mk
+command remains in the tag, serving as a sort of menu item for the associated
+window.
+.PP
+Like the middle button, the right button is used to indicate text by sweeping it out.
+The indicated text is not a command, however, but the argument of a generalized
+search operator.
+If the text, perhaps after appending it to the directory of the window containing it,
+is the name of an existing file, Acme creates a new window to hold the file
+and reads it in.  It then moves the mouse cursor to that window.  If the file is
+already loaded into Acme, the mouse motion happens but no new window is made.
+For example, indicating the string
+.CW sam.h
+in
+.P1
+#include "sam.h"
+.P2
+in a window on the file
+.CW /sys/src/cmd/sam/regexp.c
+will open the file
+.CW /sys/src/cmd/sam/sam.h .
+.PP
+If the file name is followed immediately by a colon and a legal address in
+Sam notation (for example a line number or a regular expression delimited in
+slashes or a comma-separated compound of such addresses), Acme highlights
+the target of that address in the file and places the mouse there.  One may jump to
+line 27 of
+.CW dat.h
+by indicating with the right button the text
+.CW dat.h:27 .
+If the file is not already open, Acme loads it.
+If the file name is null, for example if the indicated string is
+.CW :/^main/ ,
+the file is assumed to be that of the window containing the string.
+Such strings, when typed and evaluated in the tag of a window, amount to
+context searches.
+.PP
+If the indicated text is not the name of an existing file, it is taken to be literal
+text and is searched for in the body of the window containing the text, highlighting
+the result as if it were the result of a context search.
+.PP
+For the rare occasion when a file name
+.I is
+just text to search for, it can be selected with the left button and used as the
+argument to a built-in
+.CW Look
+command that always searches for literal text.
+.SH
+Nuances and heuristics
+.PP
+A user interface should not only provide the necessary functions, it should also
+.I feel
+right.
+In fact, it should almost not be felt at all; when one notices a
+user interface, one is distracted from the job at hand [Pike88].
+To approach this invisibility, some of Acme's properties and features
+are there just to make the others easy to use.
+Many are based on a fundamental principle of good design:
+let the machine do the work.
+.PP
+Acme tries to avoid needless clicking and typing.
+There is no `click-to-type', eliminating a button click.
+There are no pop-up or pull-down menus, eliminating the mouse action needed to
+make a menu appear.
+The overall design is intended to make text on the screen useful without
+copying or retyping; the ways in which this happens involve
+the combination of many aspects of the interface.
+.PP
+Acme tiles its windows and places them automatically
+to avoid asking the user to place and arrange them.
+For this policy to succeed, the automatic placement must behave well enough
+that the user is usually content with the location of a new window.
+The system will never get it right all the time, but in practice most
+windows are used at least for a while where Acme first places them.
+There have been several complete rewrites of the
+heuristics for placing a new window,
+and with each rewrite the system became
+noticeably more comfortable.  The rules are as follows, although
+they are still subject to improvement.
+The window appears in the `active' column, that most recently used for typing or
+selecting.
+Executing and searching do not affect the choice of active column,
+so windows of commands and such do not draw new windows towards them,
+but rather let them form near the targets of their actions.
+Output (error) windows always appear towards the right, away from
+edited text, which is typically kept towards the left.
+Within the column, several competing desires are balanced to decide where
+and how large the window should be:
+large blank spaces should be consumed;
+existing text should remain visible;
+existing large windows should be divided before small ones;
+and the window should appear near the one containing the action that caused
+its creation.
+.PP
+Acme binds some actions to chords of mouse buttons.
+These include
+.CW Cut
+and
+.CW Paste
+so these common operations can be done without
+moving the mouse.
+Another is a way to apply a command in one window to text (often a file name)
+in another, avoiding the actions needed to assemble the command textually.
+.PP
+Another way Acme avoids the need to move the mouse is instead to move the cursor
+to where it is likely to be used next.  When a new window is made, Acme
+moves the cursor to the new window; in fact, to the selected text in that window.
+When the user deletes a newly made window, the cursor is
+returned to the point it was before the window was made,
+reducing the irritation of windows that pop up to report annoying errors.
+.PP
+When a window is moved, Acme moves the cursor to the layout box in
+its new place, to permit further adjustment without moving the mouse.
+For example, when a click of the left mouse button on the layout box grows
+the window, the cursor moves to the new location of the box so repeated clicks,
+without moving the mouse, continue to grow it.
+.PP
+Another form of assistance the system can offer is to supply precision in
+pointing the mouse.  The best-known form of this is `double-clicking' to
+select a word rather than carefully sweeping out the entire word.
+Acme provides this feature, using context to decide whether to select
+a word, line, quoted string, parenthesized expression, and so on.
+But Acme takes the idea much further by applying it to execution
+and searching.
+A
+.I single
+click, that is, a null selection, with either the middle or right buttons,
+is expanded automatically to indicate the appropriate text containing
+the click.  What is appropriate depends on the context.
+.PP
+For example, to execute a single-word command
+such as
+.CW Cut ,
+it is not necessary to sweep the entire word; just clicking the button once with
+the mouse pointing at the word is sufficient.  `Word'
+means the largest string of likely file name characters surrounding the location
+of the click: click on a file name, run that program.
+On the right button, the rules are more complicated because
+the target of the click might be a file name, file name with address,
+or just plain text.  Acme examines the text near the click to find
+a likely file name;
+if it finds one, it checks that it names an existing file (in the directory named in the tag, if the name is relative)
+and if so, takes that as the result, after extending it with any address
+that may be present.  If there is no file with that name, Acme
+just takes the largest alphanumeric string under the click.
+The effect is a natural overloading of the button to refer to plain text as
+well as file names.
+.PP
+First, though, if the click occurs over the left-button-selected text in the window,
+that text is taken to be what is selected.
+This makes it easy to skip through the occurrences of a string in a file: just click
+the right button
+on some occurrence of the text in the window (perhaps after typing it in the tag)
+and click once for each subsequent occurrence.  It isn't even necessary to move
+the mouse between clicks; Acme does that.
+To turn a complicated command into a sort of menu item, select it:
+thereafter, clicking the middle button on it will execute the full command.
+.PP
+As an extra feature, Acme recognizes file names in angle brackets
+.CW <>
+as names of files in standard directories of include files,
+making it possible for instance to look at
+.CW <stdio.h>
+with a single click.
+.PP
+Here's an example to demonstrate how the actions and defaults work together.
+Assume
+.CW /sys/src/cmd/sam/regexp.c
+is
+open and has been edited.  We write it (execute
+.CW Put
+in the tag; once the file is written, Acme removes the word from the tag)
+and type
+.CW mk
+in the tag.  We execute
+.CW mk
+and get some errors, which appear in a new window labeled
+.CW /sys/src/cmd/sam/+Errors .
+The cursor moves automatically to that window.
+Say the error is
+.P1
+main.c:112: incompatible types on assignment to `pattern'
+.P2
+We move the mouse slightly and click the right button
+at the left of the error message; Acme
+makes a new window, reads
+.CW /sys/src/cmd/main.c
+into it, selects line 112
+and places the mouse there, right on the offending line.
+.SH
+Coupling to existing programs
+.PP
+Acme's syntax for file names and addresses makes it easy for other programs
+to connect automatically to Acme's capabilities.  For example, the output of
+.P1
+grep -n variable *.[ch]
+.P2
+can be used to help Acme step through the occurrences of a variable in a program;
+every line of output is potentially a command to open a file.
+The file names need not be absolute, either: the output
+appears in a window labeled with the directory in which
+.CW grep
+was run, from which Acme can derive the full path names.
+.PP
+When necessary, we have changed the output of some programs,
+such as compiler error messages, to match
+Acme's syntax.
+Some might argue that it shouldn't be necessary to change old programs,
+but sometimes programs need to be updated when systems change,
+and consistent output benefits people as well as programs.
+A historical example is the retrofitting of standard error output to the
+early Unix programs when pipes were invented.
+.PP
+Another change was to record full path names in
+the symbol table of executables, so line numbers reported by the debugger
+are absolute names that may be used directly by Acme; it's not necessary
+to run the debugger in the source directory.  (This aids debugging
+even without Acme.)
+.PP
+A related change was to add lines of the form
+.P1
+#pragma src "/sys/src/libregexp"
+.P2
+to header files; coupled with Acme's ability to locate a header file,
+this provides a fast, keyboardless way to get the source associated with a library.
+.PP
+Finally, Acme directs the standard output of programs it runs to
+windows labeled by the directory in which the program is run.
+Acme's splitting of the
+output into directory-labeled windows is a small feature that has a major effect:
+local file names printed by programs can be interpreted directly by Acme.
+By indirectly coupling the output of programs to the input,
+it also simplifies the management of software that occupies multiple
+directories.
+.SH
+Coupling to new programs
+.PP
+Like many Plan 9 programs,
+Acme offers a programmable interface to
+other programs by acting as a file server.
+The best example of such a file server is the window system
+.CW 8½
+[Pike91],
+which exports files with names such as
+.CW screen ,
+.CW cons ,
+and
+.CW mouse
+through which applications may access the I/O capabilities of the windows.
+.CW 8½
+provides a
+.I distinct
+set of files for each window and builds a private file name space
+for the clients running `in' each window;
+clients in separate windows see distinct files with the same names
+(for example
+.CW /dev/mouse ).
+Acme, like the process file system [PPTTW93], instead associates each
+window with a directory of files; the files of each window are visible
+to any application.
+This difference reflects a difference in how the systems are used:
+.CW 8½
+tells a client what keyboard and mouse activity has happened in its window;
+Acme tells a client what changes that activity wrought on any window it asks about.
+Putting it another way,
+.CW 8½
+enables the construction of interactive applications;
+Acme provides the interaction for applications.
+.PP
+The root of
+Acme's file system is mounted using Plan 9 operations on the directory
+.CW /mnt/acme .
+In
+that root directory appears a directory for each window, numbered with the window's identifier,
+analogous to a process identifier, for example
+.CW /mnt/acme/27 .
+The window's directory
+contains 6 files:
+.CW /mnt/acme/27/addr ,
+.CW body ,
+.CW ctl ,
+.CW data ,
+.CW event ,
+and
+.CW tag .
+The
+.CW body
+and
+.CW tag
+files contain the text of the respective parts of the window; they may be
+read to recover the contents.  Data written to these files is appended to the text;
+.CW seeks
+are ignored.
+The
+.CW addr
+and
+.CW data
+files provide random access to the contents of the body.
+The
+.CW addr
+file is written to set a character position within the body; the
+.CW data
+file may then be read to recover the contents at that position,
+or written to change them.
+(The tag is assumed
+small and special-purpose enough not to need special treatment.
+Also,
+.CW addr
+indexes by character position, which is not the same as byte offset
+in Plan 9's multi-byte character set [Pike93]).
+The format accepted by the
+.CW addr
+file is exactly the syntax of addresses within the user interface,
+permitting regular expressions, line numbers, and compound addresses
+to be specified.  For example, to replace the contents of lines 3 through 7,
+write the text
+.P1
+3,7
+.P2
+to the
+.CW addr
+file, then write the replacement text to the
+.CW data
+file.  A zero-length write deletes the addressed text; further writes extend the replacement.
+.PP
+The control file,
+.CW ctl ,
+may be written with commands to effect actions on the window; for example
+the command
+.P1
+name /adm/users
+.P2
+sets the name in the tag of the window to
+.CW /adm/users .
+Other commands allow deleting the window, writing it to a file, and so on.
+Reading the
+.CW ctl
+file recovers a fixed-format string containing 5 textual numbers\(emthe window
+identifier, the number of characters in the tag, the number in the body,
+and some status information\(emfollowed by the text of the tag, up to a newline.
+.PP
+The last file,
+.CW event ,
+is the most unusual.
+A program reading a window's
+.CW event
+file is notified of all changes to the text of the window, and
+is asked to interpret all middle- and right-button actions.
+The data passed to the program is fixed-format and reports
+the source of the action (keyboard, mouse, external program, etc.),
+its location (what was pointed at or modified), and its nature (change,
+search, execution, etc.).
+This message, for example,
+.P1
+MI15 19 0 4 time
+.P2
+reports that actions of the mouse
+.CW M ) (
+inserted in the body (capital
+.CW I )
+the 4 characters of
+.CW time
+at character positions 15 through 19; the zero is a flag word.
+Programs may apply their own interpretations of searching and
+execution, or may simply reflect the events back to Acme,
+by writing them back to the
+.CW event
+file, to have the default interpretation applied.
+Some examples of these ideas in action are presented below.
+.PP
+Notice that changes to the window are reported
+after the fact; the program is told about them but is not required to act
+on them.  Compare this to a more traditional interface in which a program
+is told, for example, that a character has been typed on the keyboard and
+must then display and interpret it.
+Acme's style stems from the basic model of the system, in which any
+number of agents\(emthe keyboard, mouse, external programs
+writing to
+.CW data
+or
+.CW body ,
+and so on\(emmay
+change the contents of a window.
+The style is efficient: many programs are content
+to have Acme do most of the work and act only when the editing is completed.
+An example is the Acme mail program, which can ignore the changes
+made to a message being composed
+and just read its body when asked to send it.
+A disadvantage is that some traditional ways of working are impossible.
+For example, there is no way `to turn off echo': characters appear on the
+screen and are read from there; no agent or buffer stands between
+the keyboard and the display.
+.PP
+There are a couple of other files made available by Acme in its root directory
+rather than in the directory of each window.
+The text file
+.CW /mnt/acme/index
+holds a list of all window names and numerical identifiers,
+somewhat analogous to the output of the
+.CW ps
+command for processes.
+The most important, though, is
+.CW /mnt/acme/new ,
+a directory that makes new windows, similar to the
+.CW clone
+directory in the Plan 9 network devices [Pres93].
+The act of opening any file in
+.CW new
+creates a new Acme window; thus the shell command
+.P1
+grep -n var *.c > /mnt/acme/new/body
+.P2
+places its output in the body of a fresh window.
+More sophisticated applications may open
+.CW new/ctl ,
+read it to discover the new window's identifier, and then
+open the window's other files in the numbered directory.
+.SH
+Acme-specific programs
+.PP
+Although Acme is in part an attempt to move beyond typescripts,
+they will probably always have utility.
+The first program written for Acme was therefore one
+to run a shell or other traditional interactive application
+in a window, the Acme analog of
+.CW xterm .
+This program,
+.CW win ,
+has a simple structure:
+it acts as a two-way intermediary between Acme and the shell,
+cross-connecting the standard input and output of the shell to the
+text of the window.
+The style of interaction is modeled after
+.CW mux
+[Pike88]: standard output is added to the window at the
+.I "output point;
+text typed after the output point
+is made available on standard input when a newline is typed.
+After either of these actions, the output point is advanced.
+This is different from the working of a regular terminal,
+permitting cut-and-paste editing of an input line until the newline is typed.
+Arbitrary editing may be done to any text in the window.
+The implementation of
+.CW win ,
+using the
+.CW event ,
+.CW addr ,
+and
+.CW data
+files, is straightforward.
+.CW Win
+needs no code for handling the keyboard and mouse; it just monitors the
+contents of the window.  Nonetheless, it allows Acme's full editing to be
+applied to shell commands.
+The division of labor between
+.CW win
+and
+.CW Acme
+contrasted with
+.CW xterm
+and the X server demonstrates how much work Acme handles automatically.
+.CW Win
+is implemented by a single source file 560 lines long and has no graphics code.
+.PP
+.CW Win
+uses the middle and right buttons to connect itself in a consistent way
+with the rest of Acme.
+The middle button still executes commands, but in a style more suited
+to typescripts.  Text selected with the middle button is treated as if
+it had been typed after the output point, much as a similar feature in
+.CW xterm
+or
+.CW 8½ ,
+and therefore causes it to be `executed' by the application running in the window.
+Right button actions are reflected back to Acme but refer to the appropriate
+files because
+.CW win
+places the name of the current directory in the tag of the window.
+If the shell is running, a simple shell function replacing the
+.CW cd
+command can maintain the tag as the shell navigates the file system.
+This means, for example, that a right button click on a file mentioned in an
+.CW ls
+listing opens the file within Acme.
+.PP
+Another Acme-specific program is a mail reader that begins by presenting,
+in a window, a listing of the messages in the user's mailbox, one per line.
+Here the middle and right button actions are modified to refer to
+mail commands
+and messages, but the change feels natural.
+Clicking the right button on a line creates a new window and displays the
+message there, or, if it's already displayed, moves the mouse to that window.
+The metaphor is that the mailbox is a directory whose constituent files are messages.
+The mail program also places some relevant commands in the tag lines of
+the windows; for example, executing the word
+.CW Reply
+in a message's tag creates a new window
+in which to compose a message to the sender of the original;
+.CW Post
+then dispatches it.
+In such windows, the addressee is just a list of names
+on the first line of the body, which may be edited to add or change recipients.
+The program also monitors the mailbox, updating the `directory' as new messages
+arrive.
+.PP
+The mail program is as simple as it sounds; all the work of interaction,
+editing, and management of the display is done by Acme.
+The only
+difficult sections of the 1200
+lines of code concern honoring the external protocols for managing
+the mailbox and connecting to
+.CW sendmail .
+.PP
+One of the things Acme does not provide directly is a facility like
+Sam's command language to enable actions such as global substitution;
+within Acme, all editing is done manually.
+It is easy, though, to write external programs for such tasks.
+In this, Acme comes closer to the original intent of Oberon:
+a directory,
+.CW /acme/edit ,
+contains a set of tools for repetitive editing and a template
+or `guide' file that gives examples
+of its use.  
+Acme's editing guide,
+.CW /acme/edit/guide ,
+looks like this:
+.P1
+e file | x '/regexp/' | c 'replacement'
+e file:'0,$' | x '/.*word.*\en/' | p -n
+e file | pipe command args ...
+.P2
+The syntax is reminiscent of Sam's command language, but here the individual
+one-letter commands are all stand-alone programs connected by pipes.
+Passed along the pipes are addresses, analogous to structural expressions
+in Sam terminology.
+The
+.CW e
+command, unlike that of Sam, starts the process by generating the address
+(default dot, the highlighted selection) in the named files.
+The other commands are as in Sam:
+.CW p
+prints the addressed text on standard output (the
+.CW -n
+option is analogous to that of
+.CW grep ,
+useful in combination with the right mouse button);
+.CW x
+matches a regular expression to the addressed (incoming) text,
+subdividing the text;
+.CW c
+replaces the text; and so on.  Thus, global substitution throughout a file,
+which would be expressed in Sam as
+.P1
+0,$ x/regexp/ c/replacement/
+.P2
+in Acme's editor becomes
+.P1
+e 'file:0,$' | x '/regexp/' | c 'replacement'
+.P2
+.PP
+To use the Acme editing commands, open
+.CW /acme/edit/guide ,
+use the mouse and keyboard to edit one of the commands to the right form,
+and execute it with the middle button.
+Acme's context rules find the appropriate binaries in
+.CW /acme/edit
+rather than
+.CW /bin ;
+the effect is to turn
+.CW /acme/edit
+into a toolbox containing tools and instructions (the guide file) for their use.
+In fact, the source for these tools is also there, in the directory
+.CW /acme/edit/src .
+This setup allows some control of the file name space for binary programs;
+not only does it group related programs, it permits the use of common
+names for uncommon jobs.  For example, the single-letter names would
+be unwise in a directory in everyone's search path; here they are only
+visible when running editing commands.
+.PP
+In Oberon,
+such a collection would be called a
+.I tool
+and would consist
+of a set of entry points in a module and a menu-like piece of text containing
+representative commands that may be edited to suit and executed.
+There is, in fact, a tool called
+.CW Edit
+in Oberon.
+To provide related functionality,
+Acme exploits the directory and file structure of the underlying
+system, rather than the module structure of the language;
+this fits well with Plan 9's
+file-oriented philosophy.
+Such tools are central to the working of Oberon but they are
+less used in Acme, at least so far.
+The main reason is probably that Acme's program interface permits
+an external program to remain executing in the background, providing
+its own commands as needed (for example, the
+.CW Reply
+command in the mail program); Oberon uses tools to
+implement such services because its must invoke
+a fresh program for each command.
+Also,
+Acme's better integration allows more
+basic functions to be handled internally; the right mouse button
+covers a lot of the basic utility of the editing tools in Oberon.
+Nonetheless, as more applications are written for Acme,
+many are sure to take this Oberon tool-like form.
+.SH
+Comparison with other systems
+.PP
+Acme's immediate ancestor is Help [Pike92], an experimental system written
+a few years ago as a first try at exploring some of Oberon's ideas
+in an existing operating system.
+Besides much better engineering, Acme's advances over Help
+include the actions of the right button (Help had nothing comparable),
+the ability to connect long-running programs to the user interface
+(Help had no analog of the
+.CW event
+file),
+and the small but important change to split command output into
+windows labeled with the directory in which the commands run.
+.PP
+Most of Acme's style, however, derives from the user interface and window
+system of Oberon [Wirt89, Reis91].
+Oberon includes a programming language and operating system,
+which Acme instead borrows from an existing system, Plan 9.
+When I first saw Oberon, in 1988, I was struck by the
+simplicity of its user interface, particularly its lack of menus
+and its elegant use of multiple mouse buttons.
+The system seemed restrictive, though\(emsingle process,
+single language, no networking, event-driven programming\(emand
+failed to follow through on some of its own ideas.
+For example, the middle mouse button had to be pointed accurately and
+the right button was essentially unused.
+Acme does follow through:
+to the basic idea planted by Oberon, it adds
+the ability to run on different operating systems and hardware,
+connection to existing applications including
+interactive ones such as shells and debuggers,
+support for multiple processes,
+the right mouse button's features,
+the default actions and context-dependent properties
+of execution and searching,
+and a host of little touches such as moving the mouse cursor that make the system 
+more pleasant.
+At the moment, though, Oberon does have one distinct advantage: it incorporates
+graphical programs well into its model, an issue Acme has not yet faced.
+.PP
+Acme shares with the Macintosh a desire to use the mouse well and it is
+worth comparing the results.
+The mouse on the Macintosh has a single button, so menus are essential
+and the mouse must frequently move a long way
+to reach the appropriate function.
+An indication that this style has trouble is that applications provide
+keyboard sequences to invoke menu selections and users often prefer them.
+A deeper comparison is that the Macintosh uses pictures where Acme uses text.
+In contrast to pictures, text can be edited quickly, created on demand,
+and fine-tuned to the job at hand; consider adding an option to a command.
+It is also self-referential; Acme doesn't need menus because any text can be
+in effect a menu item.
+The result is that, although a Macintosh screen is certainly prettier and probably
+more attractive, especially to beginners, an Acme screen is more dynamic
+and expressive, at least for programmers and experienced users.
+.PP
+For its role in the overall system,
+Acme most resembles EMACS [Stal93].
+It is tricky to compare Acme to EMACS, though, because there are
+many versions of EMACS and, since it is fully programmable, EMACS
+can in principle do anything Acme does.
+Also, Acme is much younger and therefore has not
+had the time to acquire as many features.
+The issue therefore is less what the systems can be programmed to do than
+how they are used.
+The EMACS versions that come closest to Acme's style are those that
+have been extended to provide a programming environment, usually
+for a language such as LISP [Alle92, Lucid92].
+For richness of the existing interface, these EMACS versions are certainly superior to Acme.
+On the other hand, Acme's interface works equally well already for a variety
+of languages; for example, one of its most enthusiastic users works almost
+exclusively in Standard ML, a language nothing like C.
+.PP
+Where Acme excels is in the smoothness of its interface.
+Until recently, EMACS did not support the mouse especially well,
+and even with the latest version providing features such as `extents'
+that can be programmed to behave much like Acme commands,
+many users don't bother to upgrade.
+Moreover, in the versions that provide extents, 
+most EMACS packages don't take advantage of them.
+.PP
+The most important distinction is just that
+EMACS is fundamentally keyboard-based, while
+Acme is mouse-based.
+.PP
+People who try Acme find it hard to go back to their previous environment.
+Acme automates so much that to return to a traditional interface
+is to draw attention to the extra work it requires.
+.SH
+Concurrency in the implementation
+.PP
+Acme is about 8,000 lines of code in Alef, a concurrent object-oriented language syntactically similar to C [Alef].
+Acme's structure is a set of communicating
+processes in a single address space.
+One subset of the processes drives the display and user interface,
+maintaining the windows; other processes forward mouse and keyboard
+activity and implement the file server interface for external programs.
+The language and design worked out well;
+as explained elsewhere [Pike89, Gans93, Reppy93],
+user interfaces built with concurrent systems
+can avoid the clumsy
+top-level event loop typical of traditional interactive systems.
+.PP
+An example of the benefits of the multi-process style
+is the management of the state of open
+files held by clients of the file system interface.
+The problem is that some I/O requests,
+such as reading the
+.CW event
+file, may block if no data is available, and the server must
+maintain the state of (possibly many) requests until data appears.
+For example,
+in
+.CW 8½ ,
+a single-process window system written in C, pending requests were queued in
+a data structure associated with each window.
+After activity in the window that might complete pending I/O,
+the data structure was scanned for requests that could now finish.
+This structure did not fit well with the rest of the program and, worse,
+required meticulous effort
+to guarantee correct behavior under all conditions
+(consider raw mode, reads of partial lines, deleting a window,
+multibyte characters, etc.).
+.PP
+Acme instead creates a new dedicated process
+for each I/O request.
+This process coordinates with the rest of the system
+using Alef's synchronous communication;
+its state implicitly encodes the state of
+the I/O request and obviates the need for queuing.
+The passage of the request through Acme proceeds as follows.
+.PP
+Acme contains a file server process, F, that executes a
+.CW read
+system call to receive a Plan 9 file protocol (9P) message from the client [AT&T92].
+The client blocks until Acme answers the request.
+F communicates with an allocation process, M,
+to acquire an object of type
+.CW Xfid
+(`executing fid'; fid is a 9P term)
+to hold the request.
+M sits in a loop (reproduced in Figure 2) waiting for either a request for
+a new
+.CW Xfid
+or notification that an existing one has finished its task.
+When an
+.CW Xfid
+is created, an associated process, X,
+is also made.
+M queues idle
+.CW Xfids ,
+allocating new ones only when the list is empty.
+Thus, there is always a pool of
+.CW Xfids ,
+some executing, some idle.
+.PP
+The
+.CW Xfid
+object contains a channel,
+.CW Xfid.c ,
+for communication with its process;
+the unpacked message; and some associated functions,
+mostly corresponding to 9P messages such as
+.CW Xfid.write
+to handle a 9P write request.
+.PP
+The file server process F parses the message to see its nature\(emopen,
+close, read, write, etc.  Many messages, such as directory
+lookups, can be handled immediately; these are responded to directly
+and efficiently
+by F without invoking the
+.CW Xfid ,
+which is therefore maintained until the next message.
+When a message, such as a write to the display, requires the attention
+of the main display process and interlocked access to its data structures,
+F enables X
+by sending a function pointer on
+.CW Xfid.c .
+For example, if the message is a write, F executes
+.P1
+x->c <-= Xfid.write;
+.P2
+which sends
+the address of
+.CW Xfid.write
+on
+.CW Xfid.c ,
+waking up X.
+.PP
+The
+.CW Xfid
+process, X, executes a simple loop:
+.P1
+void
+Xfid.ctl(Xfid *x)
+{
+    for(;;){
+        (*<-x->c)(x);      /* receive and execute message */
+        bflush();          /* synchronize bitmap display */
+        cxfidfree <-= x;   /* return to free list */
+    }
+}
+.P2 
+Thus X
+will wake up with the address of a function to call (here
+.CW Xfid.write )
+and execute it; once that completes, it returns itself to the pool of
+free processes by sending its address back to the allocator.
+.PP
+Although this sequence may seem complicated, it is just a few lines
+of code and is in fact far simpler
+than the management of the I/O queues in
+.CW 8½ .
+The hard work of synchronization is done by the Alef run time system.
+Moreover, the code worked the first time, which cannot be said for the code in
+.CW 8½ .
+.SH
+Undo
+.PP
+Acme provides a general undo facility like that of Sam, permitting
+textual changes to be unwound arbitrarily.
+The implementation is superior to Sam's, though,
+with much higher performance and the ability to `redo' changes.
+.PP
+Sam uses
+a multi-pass algorithm that builds
+a transcript of changes to be made simultaneously
+and then executes them atomically.
+This was thought necessary because the elements of a repetitive
+command such as a global substitution should all be applied to the same
+initial file and implemented simultaneously; forming the complete
+transcript before executing any of the changes avoids the
+cumbersome management of addresses in a changing file.
+Acme, however, doesn't have this problem; global substitution
+is controlled externally and may be made incrementally by exploiting
+an observation: if the changes are sorted in address order and
+executed in reverse, changes will not invalidate the addresses of
+pending changes.
+.PP
+Acme therefore avoids the initial transcript.  Instead, changes are applied
+directly to the file, with an undo transcript recorded in a separate list.
+For example, when text is added to a window, it is added directly and a record
+of what to delete to restore the state is appended to the undo list.
+Each undo action and the file are marked with a sequence number;
+actions with the same sequence number are considered a unit
+to be undone together.
+The invariant state of the structure
+is that the last action in the undo list applies to the current state of the file,
+even if that action is one of a related set from, for example, a global substitute.
+(In Sam, a related set of actions needed to be undone simultaneously.)
+To undo an action, pop the last item on the undo list, apply it to the file,
+revert it, and append it to a second, redo list.
+To redo an action, do the identical operation with the lists interchanged.
+The expensive operations occur
+only when actually undoing; in normal editing the overhead is minor.
+For example, Acme reads files about seven times faster than Sam, partly
+because of this improvement and partly because of a cleaner implementation.
+.PP
+Acme uses a temporary file to hold the text, keeping in memory only the
+visible portion, and therefore can edit large files comfortably
+even on small-memory machines such as laptops.
+.SH
+Future
+.PP
+Acme is still under development.
+Some things are simply missing.
+For example, Acme should support non-textual graphics, but this is being
+deferred until it can be done using a new graphics model being developed
+for Plan 9.  Also, it is undecided how Acme's style of interaction should best be
+extended to graphical applications.
+On a smaller scale, although the system feels smooth and comfortable,
+work continues to tune the heuristics and
+try new ideas for the user interface.
+.PP
+There need to be more programs that use Acme.  Browsers for
+Usenet and AP News articles, the Oxford English Dictionary, and other
+such text sources exist, but more imaginative applications will
+be necessary to prove that Acme's approach is viable.
+One that has recently been started is an interface to the debugger Acid [Wint94],
+although it is still
+unclear what form it will ultimately take.
+.PP
+Acme shows that it is possible to make a user interface a stand-alone component
+of an interactive environment.  By absorbing more of the interactive
+functionality than a simple window system, Acme off-loads much of the
+computation from its applications, which helps keep them small and
+consistent in their interface.  Acme can afford to dedicate
+considerable effort to making that interface as good as possible; the result
+will benefit the entire system.
+.PP
+Acme is complete and useful enough to attract users.
+Its comfortable user interface,
+the ease with which it handles multiple tasks and
+programs in multiple directories,
+and its high level of integration
+make it addictive.
+Perhaps most telling,
+Acme shows that typescripts may not be the most
+productive interface to a time-sharing system.
+.SH
+Acknowledgements
+.PP
+Howard Trickey, Acme's first user, suffered buggy versions gracefully and made
+many helpful suggestions.  Chris Fraser provided the necessary insight for the Acme editing
+commands.
+.SH
+References
+.LP
+[Alef] P. Winterbottom,
+``Alef Language Reference Manual'',
+.I
+Plan 9 Programmer's Manual,
+.R
+AT&T Bell Laboratories,
+Murray Hill, NJ,
+1992;
+revised in this volume.
+.br
+[Alle92]
+.I
+Allegro Common Lisp user Guide, Vol 2, 
+.R
+Chapter 14, "The Emacs-Lisp Interface". 
+March 1992.
+.br
+[AT&T92] Plan 9 Programmer's manual, Murray Hill, New Jersey, 1992.
+.br
+[Far89] Far too many people, XTERM(1), Massachusetts Institute of Technology, 1989.
+.br
+[Gans93] Emden R. Gansner and John H. Reppy,  ``A Multi-threaded Higher-order User Interface Toolkit'', in
+.I
+Software Trends, Volume 1,
+User Interface Software,
+.R
+Bass and Dewan (Eds.),
+John Wiley & Sons 1993,
+pp. 61-80.
+.br
+[Lucid92] Richard Stallman and Lucid, Inc.,
+.I
+Lucid GNU EMACS Manual,
+.R
+March 1992.
+.br
+[Pike87] Rob Pike, ``The Text Editor \f(CWsam\fP'', Softw. - Pract. and Exp., Nov 1987, Vol 17 #11, pp. 813-845; reprinted in this volume.
+.br
+[Pike88] Rob Pike, ``Window Systems Should Be Transparent'', Comp. Sys., Summer 1988, Vol 1 #3, pp. 279-296.
+.br
+[Pike89] Rob Pike, ``A Concurrent Window System'', Comp. Sys., Spring 1989, Vol 2 #2, pp. 133-153.
+.br
+[PPTTW93] Rob Pike, Dave Presotto, Ken Thompson, Howard Trickey, and Phil Winterbottom, ``The Use of Name Spaces in Plan 9'',
+Op. Sys. Rev.,  Vol. 27, No. 2, April 1993, pp. 72-76,
+reprinted in this volume.
+.br
+[Pike91] Rob Pike, ``8½, the Plan 9 Window System'', USENIX Summer Conf. Proc., Nashville, June, 1991, pp. 257-265,
+reprinted in this volume.
+.br
+[Pike92] Rob Pike, ``A Minimalist Global User Interface'', Graphics Interface '92 Proc., Vancouver, 1992, pp. 282-293.  An earlier version appeared under the same title in USENIX Summer Conf. Proc., Nashville, June, 1991, pp. 267-279.
+.br
+[Pike93] Rob Pike and Ken Thompson, ``Hello World or Καλημέρα κόσμε or
+\f(Jpこんにちは 世界\fP'', USENIX Winter Conf. Proc., San Diego, 1993, pp. 43-50,
+reprinted in this volume.
+.br
+[Pres93] Dave Presotto and Phil Winterbottom, ``The Organization of Networks in Plan 9'', Proc. Usenix Winter 1993, pp. 271-287, San Diego, CA,
+reprinted in this volume.
+.br
+[Reis91] Martin Reiser, \fIThe Oberon System,\fP Addison Wesley, New York, 1991.
+.br
+[Reppy93] John H. Reppy,
+``CML: A higher-order concurrent language'', Proc. SIGPLAN'91 Conf. on Programming, Lang. Design and Impl., June, 1991, pp. 293-305.
+.br
+[Sche86] Robert W. Scheifler and Jim Gettys,
+``The X Window System'',
+ACM Trans. on Graph., Vol 5 #2, pp. 79-109.
+.br
+[Stal93] Richard Stallman,
+.I
+Gnu Emacs Manual, 9th edition, Emacs version 19.19,
+.R
+MIT.
+.br
+[Swei86] Daniel Sweinhart, Polle Zellweger, Richard Beach, and Robert Hagmann,
+``A Structural View of the Cedar Programming Environment'',
+ACM Trans. Prog. Lang. and Sys., Vol. 8, No. 4, pp. 419-490, Oct. 1986.
+.br
+[Wint94], Philip Winterbottom, ``Acid: A Debugger based on a Language'', USENIX Winter Conf. Proc., San Francisco, CA, 1993,
+reprinted in this volume.
+.br
+[Wirt89] N. Wirth and J. Gutknecht, ``The Oberon System'', Softw. - Prac. and Exp., Sep 1989, Vol 19 #9, pp 857-894.
binary files /dev/null b/doc/acme/acme.pdf differ
--- /dev/null
+++ b/doc/acme/mkfile
@@ -1,0 +1,4 @@
+<../fonts
+
+acme.ps:D:	acme.ms
+	{echo $FONTS; cat acme.ms} | troff -mpm -mpictures -mnihongo | lp -dstdout >acme.ps
--- /dev/null
+++ b/doc/asm.ms
@@ -1,0 +1,1394 @@
+.ft CW
+.ta 8n +8n +8n +8n +8n +8n +8n
+.ft
+.TL
+A Manual for the Plan 9 assembler
+.AU
+.I "Rob Pike"
+.AI
+rob@plan9.bell-labs.com
+.SH
+Machines
+.PP
+There is an assembler for each of the MIPS, SPARC, Intel 386,
+Motorola 68020 and 68000, IBM Power PC, DEC Alpha, and ARM.
+The 68020 assembler,
+.CW 2a ,
+is the oldest and in many ways the prototype.
+The assemblers are really just variations of a single program:
+they share many properties such as left-to-right assignment order for
+instruction operands and the synthesis of macro instructions
+such as
+.CW MOVE
+to hide the peculiarities of the load and store structure of the machines.
+To keep things concrete, the first part of this manual is
+specifically about the 68020.
+At the end is a description of the differences among
+the other assemblers.
+.ig
+.PP
+The document, ``How to Use the Plan 9 C Compiler'', by Rob Pike,
+is a prerequisite for this manual.
+..
+.SH
+Registers
+.PP
+All pre-defined symbols in the assembler are upper-case.
+Data registers are
+.CW R0
+through
+.CW R7 ;
+address registers are
+.CW A0
+through
+.CW A7 ;
+floating-point registers are
+.CW F0
+through
+.CW F7 .
+.PP
+A pointer in
+.CW A6
+is used by the C compiler to point to data, enabling short addresses to
+be used more often.
+The value of
+.CW A6
+is constant and must be set during C program initialization
+to the address of the externally-defined symbol
+.CW a6base .
+.PP
+The following hardware registers are defined in the assembler; their
+meaning should be obvious given a 68020 manual:
+.CW CAAR ,
+.CW CACR ,
+.CW CCR ,
+.CW DFC ,
+.CW ISP ,
+.CW MSP ,
+.CW SFC ,
+.CW SR ,
+.CW USP ,
+and
+.CW VBR .
+.PP
+The assembler also defines several pseudo-registers that
+manipulate the stack:
+.CW FP ,
+.CW SP ,
+and
+.CW TOS .
+.CW FP
+is the frame pointer, so
+.CW 0(FP)
+is the first argument,
+.CW 4(FP)
+is the second, and so on.
+.CW SP
+is the local stack pointer, where automatic variables are held
+(SP is a pseudo-register only on the 68020);
+.CW 0(SP)
+is the first automatic, and so on as with
+.CW FP .
+Finally,
+.CW TOS
+is the top-of-stack register, used for pushing parameters to procedures,
+saving temporary values, and so on.
+.PP
+The assembler and loader track these pseudo-registers so
+the above statements are true regardless of what has been
+pushed on the hardware stack, pointed to by
+.CW A7 .
+The name
+.CW A7
+refers to the hardware stack pointer, but beware of mixed use of
+.CW A7
+and the above stack-related pseudo-registers, which will cause trouble.
+Note, too, that the
+.CW PEA
+instruction is observed by the loader to
+alter SP and thus will insert a corresponding pop before all returns.
+The assembler accepts a label-like name to be attached to
+.CW FP
+and
+.CW SP
+uses, such as
+.CW p+0(FP) ,
+to help document that
+.CW p
+is the first argument to a routine.
+The name goes in the symbol table but has no significance to the result
+of the program.
+.SH
+Referring to data
+.PP
+All external references must be made relative to some pseudo-register,
+either
+.CW PC
+(the virtual program counter) or
+.CW SB
+(the ``static base'' register).
+.CW PC
+counts instructions, not bytes of data.
+For example, to branch to the second following instruction, that is,
+to skip one instruction, one may write
+.P1
+	BRA	2(PC)
+.P2
+Labels are also allowed, as in
+.P1
+	BRA	return
+	NOP
+return:
+	RTS
+.P2
+When using labels, there is no
+.CW (PC)
+annotation.
+.PP
+The pseudo-register
+.CW SB
+refers to the beginning of the address space of the program.
+Thus, references to global data and procedures are written as
+offsets to
+.CW SB ,
+as in
+.P1
+	MOVL	$array(SB), TOS
+.P2
+to push the address of a global array on the stack, or
+.P1
+	MOVL	array+4(SB), TOS
+.P2
+to push the second (4-byte) element of the array.
+Note the use of an offset; the complete list of addressing modes is given below.
+Similarly, subroutine calls must use
+.CW SB :
+.P1
+	BSR	exit(SB)
+.P2
+File-static variables have syntax
+.P1
+	local<>+4(SB)
+.P2
+The
+.CW <>
+will be filled in at load time by a unique integer.
+.PP
+When a program starts, it must execute
+.P1
+	MOVL	$a6base(SB), A6
+.P2
+before accessing any global data.
+(On machines such as the MIPS and SPARC that cannot load a register
+in a single instruction, constants are loaded through the static base
+register.  The loader recognizes code that initializes the static
+base register and treats it specially.  You must be careful, however,
+not to load large constants on such machines when the static base
+register is not set up, such as early in interrupt routines.)
+.SH
+Expressions
+.PP
+Expressions are mostly what one might expect.
+Where an offset or a constant is expected,
+a primary expression with unary operators is allowed.
+A general C constant expression is allowed in parentheses.
+.PP
+Source files are preprocessed exactly as in the C compiler, so
+.CW #define
+and
+.CW #include
+work.
+.SH
+Addressing modes
+.PP
+The simple addressing modes are shared by all the assemblers.
+Here, for completeness, follows a table of all the 68020 addressing modes,
+since that machine has the richest set.
+In the table,
+.CW o
+is an offset, which if zero may be elided, and
+.CW d
+is a displacement, which is a constant between -128 and 127 inclusive.
+Many of the modes listed have the same name;
+scrutiny of the format will show what default is being applied.
+For instance, indexed mode with no address register supplied operates
+as though a zero-valued register were used.
+For "offset" read "displacement."
+For "\f(CW.s\fP" read one of
+.CW .L ,
+or
+.CW .W
+followed by
+.CW *1 ,
+.CW *2 ,
+.CW *4 ,
+or
+.CW *8
+to indicate the size and scaling of the data.
+.IP
+.TS
+l lfCW.
+data register	R0
+address register	A0
+floating-point register	F0
+special names	CAAR, CACR, etc.
+constant	$con
+floating point constant	$fcon
+external symbol	name+o(SB)
+local symbol	name<>+o(SB)
+automatic symbol	name+o(SP)
+argument	name+o(FP)
+address of external	$name+o(SB)
+address of local	$name<>+o(SB)
+indirect post-increment	(A0)+
+indirect pre-decrement	-(A0)
+indirect with offset	o(A0)
+indexed with offset	o()(R0.s)
+indexed with offset	o(A0)(R0.s)
+external indexed	name+o(SB)(R0.s)
+local indexed	name<>+o(SB)(R0.s)
+automatic indexed	name+o(SP)(R0.s)
+parameter indexed	name+o(FP)(R0.s)
+offset indirect post-indexed	d(o())(R0.s)
+offset indirect post-indexed	d(o(A0))(R0.s)
+external indirect post-indexed	d(name+o(SB))(R0.s)
+local indirect post-indexed	d(name<>+o(SB))(R0.s)
+automatic indirect post-indexed	d(name+o(SP))(R0.s)
+parameter indirect post-indexed	d(name+o(FP))(R0.s)
+offset indirect pre-indexed	d(o()(R0.s))
+offset indirect pre-indexed	d(o(A0))
+offset indirect pre-indexed	d(o(A0)(R0.s))
+external indirect pre-indexed	d(name+o(SB))
+external indirect pre-indexed	d(name+o(SB)(R0.s))
+local indirect pre-indexed	d(name<>+o(SB))
+local indirect pre-indexed	d(name<>+o(SB)(R0.s))
+automatic indirect pre-indexed	d(name+o(SP))
+automatic indirect pre-indexed	d(name+o(SP)(R0.s))
+parameter indirect pre-indexed	d(name+o(FP))
+parameter indirect pre-indexed	d(name+o(FP)(R0.s))
+.TE
+.in
+.SH
+Laying down data
+.PP
+Placing data in the instruction stream, say for interrupt vectors, is easy:
+the pseudo-instructions
+.CW LONG
+and
+.CW WORD
+(but not
+.CW BYTE )
+lay down the value of their single argument, of the appropriate size,
+as if it were an instruction:
+.P1
+	LONG	$12345
+.P2
+places the long 12345 (base 10)
+in the instruction stream.
+(On most machines,
+the only such operator is
+.CW WORD
+and it lays down 32-bit quantities.
+The 386 has all three:
+.CW LONG ,
+.CW WORD ,
+and
+.CW BYTE .
+The AMD64 adds
+.CW QUAD
+for 64-bit values.)
+.PP
+Placing information in the data section is more painful.
+The pseudo-instruction
+.CW DATA
+does the work, given two arguments: an address at which to place the item,
+including its size,
+and the value to place there.  For example, to define a character array
+.CW array
+containing the characters
+.CW abc
+and a terminating null:
+.P1
+	DATA    array+0(SB)/1, $'a'
+	DATA    array+1(SB)/1, $'b'
+	DATA    array+2(SB)/1, $'c'
+	GLOBL   array(SB), $4
+.P2
+or
+.P1
+	DATA    array+0(SB)/4, $"abc\ez"
+	GLOBL   array(SB), $4
+.P2
+The
+.CW /1
+defines the number of bytes to define,
+.CW GLOBL
+makes the symbol global, and the
+.CW $4
+says how many bytes the symbol occupies.
+Uninitialized data is zeroed automatically.
+The character
+.CW \ez
+is equivalent to the C
+.CW \e0.
+The string in a
+.CW DATA
+statement may contain a maximum of eight bytes;
+build larger strings piecewise.
+Two pseudo-instructions,
+.CW DYNT
+and
+.CW INIT ,
+allow the (obsolete) Alef compilers to build dynamic type information during the load
+phase.
+The
+.CW DYNT
+pseudo-instruction has two forms:
+.P1
+	DYNT	, ALEF_SI_5+0(SB)
+	DYNT	ALEF_AS+0(SB), ALEF_SI_5+0(SB)
+.P2
+In the first form,
+.CW DYNT
+defines the symbol to be a small unique integer constant, chosen by the loader,
+which is some multiple of the word size.  In the second form,
+.CW DYNT
+defines the second symbol in the same way,
+places the address of the most recently
+defined text symbol in the array specified by the first symbol at the
+index defined by the value of the second symbol,
+and then adjusts the size of the array accordingly.
+.PP
+The
+.CW INIT
+pseudo-instruction takes the same parameters as a
+.CW DATA
+statement.  Its symbol is used as the base of an array and the
+data item is installed in the array at the offset specified by the most recent
+.CW DYNT
+pseudo-instruction.
+The size of the array is adjusted accordingly.
+The
+.CW DYNT
+and
+.CW INIT
+pseudo-instructions are not implemented on the 68020.
+.SH
+Defining a procedure
+.PP
+Entry points are defined by the pseudo-operation
+.CW TEXT ,
+which takes as arguments the name of the procedure (including the ubiquitous
+.CW (SB) )
+and the number of bytes of automatic storage to pre-allocate on the stack,
+which will usually be zero when writing assembly language programs.
+On machines with a link register, such as the MIPS and SPARC,
+the special value -4 instructs the loader to generate no PC save
+and restore instructions, even if the function is not a leaf.
+Here is a complete procedure that returns the sum
+of its two arguments:
+.P1
+TEXT	sum(SB), $0
+	MOVL	arg1+0(FP), R0
+	ADDL	arg2+4(FP), R0
+	RTS
+.P2
+An optional middle argument
+to the
+.CW TEXT
+pseudo-op is a bit field of options to the loader.
+Setting the 1 bit suspends profiling the function when profiling is enabled for the rest of
+the program.
+For example,
+.P1
+TEXT	sum(SB), 1, $0
+	MOVL	arg1+0(FP), R0
+	ADDL	arg2+4(FP), R0
+	RTS
+.P2
+will not be profiled; the first version above would be.
+Subroutines with peculiar state, such as system call routines,
+should not be profiled.
+.PP
+Setting the 2 bit allows multiple definitions of the same
+.CW TEXT
+symbol in a program; the loader will place only one such function in the image.
+It was emitted only by the Alef compilers.
+.PP
+Subroutines to be called from C should place their result in
+.CW R0 ,
+even if it is an address.
+Floating point values are returned in
+.CW F0 .
+Functions that return a structure to a C program
+receive as their first argument the address of the location to
+store the result;
+.CW R0
+is unused in the calling protocol for such procedures.
+A subroutine is responsible for saving its own registers,
+and therefore is free to use any registers without saving them (``caller saves'').
+.CW A6
+and
+.CW A7
+are the exceptions as described above.
+.SH
+When in doubt
+.PP
+If you get confused, try using the
+.CW -S
+option to
+.CW 2c
+and compiling a sample program.
+The standard output is valid input to the assembler.
+.SH
+Instructions
+.PP
+The instruction set of the assembler is not identical to that
+of the machine.
+It is chosen to match what the compiler generates, augmented
+slightly by specific needs of the operating system.
+For example,
+.CW 2a
+does not distinguish between the various forms of
+.CW MOVE
+instruction: move quick, move address, etc.  Instead the context
+does the job.  For example,
+.P1
+	MOVL	$1, R1
+	MOVL	A0, R2
+	MOVW	SR, R3
+.P2
+generates official
+.CW MOVEQ ,
+.CW MOVEA ,
+and
+.CW MOVESR
+instructions.
+A number of instructions do not have the syntax necessary to specify
+their entire capabilities.  Notable examples are the bitfield
+instructions, the
+multiply and divide instructions, etc.
+For a complete set of generated instruction names (in
+.CW 2a
+notation, not Motorola's) see the file
+.CW /sys/src/cmd/2c/2.out.h .
+Despite its name, this file contains an enumeration of the
+instructions that appear in the intermediate files generated
+by the compiler, which correspond exactly to lines of assembly language.
+.PP
+The MC68000 assembler,
+.CW 1a ,
+is essentially the same, honoring the appropriate subset of the instructions
+and addressing modes.
+The definitions of these are, nonetheless, part of
+.CW 2.out.h .
+.SH
+Laying down instructions
+.PP
+The loader modifies the code produced by the assembler and compiler.
+It folds branches,
+copies short sequences of code to eliminate branches,
+and discards unreachable code.
+The first instruction of every function is assumed to be reachable.
+The pseudo-instruction
+.CW NOP ,
+which you may see in compiler output,
+means no instruction at all, rather than an instruction that does nothing.
+The loader discards all
+.CW NOP 's.
+.PP
+To generate a true
+.CW NOP
+instruction, or any other instruction not known to the assembler, use a
+.CW WORD
+pseudo-instruction.
+Such instructions on RISCs are not scheduled by the loader and must have
+their delay slots filled manually.
+.SH
+MIPS
+.PP
+The registers are only addressed by number:
+.CW R0
+through
+.CW R31 .
+.CW R29
+is the stack pointer;
+.CW R30
+is used as the static base pointer, the analogue of
+.CW A6
+on the 68020.
+Its value is the address of the global symbol
+.CW setR30(SB) .
+The register holding returned values from subroutines is
+.CW R1 .
+When a function is called, space for the first argument
+is reserved at
+.CW 0(FP)
+but in C (not Alef) the value is passed in
+.CW R1
+instead.
+.PP
+The loader uses
+.CW R28
+as a temporary.  The system uses
+.CW R26
+and
+.CW R27
+as interrupt-time temporaries.  Therefore none of these registers
+should be used in user code.
+.PP
+The control registers are not known to the assembler.
+Instead they are numbered registers
+.CW M0 ,
+.CW M1 ,
+etc.
+Use this trick to access, say,
+.CW STATUS :
+.P1
+#define	STATUS	12
+	MOVW	M(STATUS), R1
+.P2
+.PP
+Floating point registers are called
+.CW F0
+through
+.CW F31 .
+By convention,
+.CW F24
+must be initialized to the value 0.0,
+.CW F26
+to 0.5,
+.CW F28
+to 1.0, and
+.CW F30
+to 2.0;
+this is done by the operating system.
+.PP
+The instructions and their syntax are different from those of the manufacturer's
+manual.
+There are no
+.CW lui
+and kin; instead there are
+.CW MOVW
+(move word),
+.CW MOVH
+(move halfword),
+and
+.CW MOVB
+(move byte) pseudo-instructions.  If the operand is unsigned, the instructions
+are
+.CW MOVHU
+and
+.CW MOVBU .
+The order of operands is from left to right in dataflow order, just as
+on the 68020 but not as in MIPS documentation.
+This means that the
+.CW Bcond
+instructions are reversed with respect to the book; for example, a
+.CW va
+.CW BGTZ
+generates a MIPS
+.CW bltz
+instruction.
+.PP
+The assembler is for the R2000, R3000, and most of the R4000 and R6000 architectures.
+It understands the 64-bit instructions
+.CW MOVV ,
+.CW MOVVL ,
+.CW ADDV ,
+.CW ADDVU ,
+.CW SUBV ,
+.CW SUBVU ,
+.CW MULV ,
+.CW MULVU ,
+.CW DIVV ,
+.CW DIVVU ,
+.CW SLLV ,
+.CW SRLV ,
+and
+.CW SRAV .
+The assembler does not have any cache, load-linked, or store-conditional instructions.
+.PP
+Some assembler instructions are expanded into multiple instructions by the loader.
+For example the loader may convert the load of a 32 bit constant into an
+.CW lui
+followed by an
+.CW ori .
+.PP
+Assembler instructions should be laid out as if there
+were no load, branch, or floating point compare delay slots;
+the loader will rearrange\(em\f2schedule\f1\(emthe instructions
+to guarantee correctness and improve performance.
+The only exception is that the correct scheduling of instructions
+that use control registers varies from model to model of machine
+(and is often undocumented) so you should schedule such instructions
+by hand to guarantee correct behavior.
+The loader generates
+.P1
+	NOR	R0, R0, R0
+.P2
+when it needs a true no-op instruction.
+Use exactly this instruction when scheduling code manually;
+the loader recognizes it and schedules the code before it and after it independently.  Also,
+.CW WORD
+pseudo-ops are scheduled like no-ops.
+.PP
+The
+.CW NOSCHED
+pseudo-op disables instruction scheduling
+(scheduling is enabled by default);
+.CW SCHED
+re-enables it.
+Branch folding, code copying, and dead code elimination are
+disabled for instructions that are not scheduled.
+.SH
+SPARC
+.PP
+Once you understand the Plan 9 model for the MIPS, the SPARC is familiar.
+Registers have numerical names only:
+.CW R0
+through
+.CW R31 .
+Forget about register windows: Plan 9 doesn't use them at all.
+The machine has 32 global registers, period.
+.CW R1
+[sic] is the stack pointer.
+.CW R2
+is the static base register, with value the address of
+.CW setSB(SB) .
+.CW R7
+is the return register and also the register holding the first
+argument to a C (not Alef) function, again with space reserved at
+.CW 0(FP) .
+.CW R14
+is the loader temporary.
+.PP
+Floating-point registers are exactly as on the MIPS.
+.PP
+The control registers are known by names such as
+.CW FSR .
+The instructions to access these registers are
+.CW MOVW
+instructions, for example
+.P1
+	MOVW	Y, R8
+.P2
+for the SPARC instruction
+.P1
+	rdy	%r8
+.P2
+.PP
+Move instructions are similar to those on the MIPS: pseudo-operations
+that turn into appropriate sequences of
+.CW sethi
+instructions, adds, etc.
+Instructions read from left to right.  Because the arguments are
+flipped to
+.CW SUBCC ,
+the condition codes are not inverted as on the MIPS.
+.PP
+The syntax for the ASI stuff is, for example to move a word from ASI 2:
+.P1
+	MOVW	(R7, 2), R8
+.P2
+The syntax for double indexing is
+.P1
+	MOVW	(R7+R8), R9
+.P2
+.PP
+The SPARC's instruction scheduling is similar to the MIPS's.
+The official no-op instruction is:
+.P1
+	ORN	R0, R0, R0
+.P2
+.SH
+i386
+.PP
+The assembler assumes 32-bit protected mode.
+The register names are
+.CW SP ,
+.CW AX ,
+.CW BX ,
+.CW CX ,
+.CW DX ,
+.CW BP ,
+.CW DI ,
+and
+.CW SI .
+The stack pointer (not a pseudo-register) is
+.CW SP
+and the return register is
+.CW AX .
+There is no physical frame pointer but, as for the MIPS,
+.CW FP
+is a pseudo-register that acts as
+a frame pointer.
+.PP
+Opcode names are mostly the same as those listed in the Intel manual
+with an
+.CW L ,
+.CW W ,
+or
+.CW B
+appended to identify 32-bit, 
+16-bit, and 8-bit operations.
+The exceptions are loads, stores, and conditionals.
+All load and store opcodes to and from general registers, special registers
+(such as
+.CW CR0,
+.CW CR3,
+.CW GDTR,
+.CW IDTR,
+.CW SS,
+.CW CS,
+.CW DS,
+.CW ES,
+.CW FS,
+and
+.CW GS )
+or memory are written
+as
+.P1
+	MOV\f2x\fP	src,dst
+.P2
+where
+.I x
+is
+.CW L ,
+.CW W ,
+or
+.CW B .
+Thus to get
+.CW AL
+use a
+.CW MOVB
+instruction.  If you need to access
+.CW AH ,
+you must mention it explicitly in a
+.CW MOVB :
+.P1
+	MOVB	AH, BX
+.P2
+There are many examples of illegal moves, for example,
+.P1
+	MOVB	BP, DI
+.P2
+that the loader actually implements as pseudo-operations.
+.PP
+The names of conditions in all conditional instructions
+.CW J , (
+.CW SET )
+follow the conventions of the 68020 instead of those of the Intel
+assembler:
+.CW JOS ,
+.CW JOC ,
+.CW JCS ,
+.CW JCC ,
+.CW JEQ ,
+.CW JNE ,
+.CW JLS ,
+.CW JHI ,
+.CW JMI ,
+.CW JPL ,
+.CW JPS ,
+.CW JPC ,
+.CW JLT ,
+.CW JGE ,
+.CW JLE ,
+and
+.CW JGT
+instead of
+.CW JO ,
+.CW JNO ,
+.CW JB ,
+.CW JNB ,
+.CW JZ ,
+.CW JNZ ,
+.CW JBE ,
+.CW JNBE ,
+.CW JS ,
+.CW JNS ,
+.CW JP ,
+.CW JNP ,
+.CW JL ,
+.CW JNL ,
+.CW JLE ,
+and
+.CW JNLE .
+.PP
+The addressing modes have syntax like
+.CW AX ,
+.CW (AX) ,
+.CW (AX)(BX*4) ,
+.CW 10(AX) ,
+and
+.CW 10(AX)(BX*4) .
+The offsets from
+.CW AX
+can be replaced by offsets from
+.CW FP
+or
+.CW SB
+to access names, for example
+.CW extern+5(SB)(AX*2) .
+.PP
+Other notes: Non-relative
+.CW JMP
+and
+.CW CALL
+have a
+.CW *
+added to the syntax.
+Only
+.CW LOOP ,
+.CW LOOPEQ ,
+and
+.CW LOOPNE
+are legal loop instructions.  Only
+.CW REP
+and
+.CW REPN
+are recognized repeaters.  These are not prefixes, but rather
+stand-alone opcodes that precede the strings, for example
+.P1
+	CLD; REP; MOVSL
+.P2
+Segment override prefixes in
+.CW MOD/RM
+fields are not supported.
+.SH
+AMD64
+.PP
+The assembler's conventions are similar to those for the 386, above.
+The architecture provides extra fixed-point registers
+.CW R8
+to
+.CW R15 .
+All registers are 64 bit, but instructions access low-order 8, 16 and 32 bits
+as described in the processor handbook.
+For example,
+.CW MOVL
+to
+.CW AX
+puts a value in the low-order 32 bits and clears the top 32 bits to zero.
+Literal operands are limited to signed 32 bit values, which are sign-extended
+to 64 bits in 64 bit operations; the exception is
+.CW MOVQ ,
+which allows 64-bit literals.
+MMX registers are
+.CW M0
+to
+.CW M7 ,
+and
+XMM registers are
+.CW X0
+to
+.CW X15 .
+.PP
+There are many new instructions, including the MMX and XMM media instructions,
+and conditional move instructions.
+As with the 386 instruction names,
+all new 64-bit integer instructions, and the MMX and XMM instructions
+uniformly use
+.CW L
+for `long word' (32 bits) and
+.CW Q
+for `quad word' (64 bits).
+Some instructions use
+.CW O
+(`octword') for 128-bit values, where the processor handbook
+variously uses
+.CW O
+or
+.CW DQ .
+The assembler also consistently uses
+.CW PL
+for `packed long' in
+XMM instructions, instead of
+.CW Q ,
+.CW DQ
+or
+.CW PI .
+Either
+.CW MOVL
+or
+.CW MOVQ
+can be used to move values to and from control registers, even when
+the registers might be 64 bits.
+The assembler often accepts the handbook's name to ease conversion
+of existing code (but remember that the operand order is uniformly
+source then destination).
+.PP
+C's
+.CW "long long"
+type is 64 bits, but passed and returned by value, not by reference.
+More notably, C pointer values are 64 bits, and thus
+.CW "long long"
+and
+.CW "unsigned long long"
+are the only integer types wide enough to hold a pointer value.
+The C compiler and library use the XMM floating-point instructions, not
+the old 387 ones, although the latter are implemented by assembler and loader.
+The compiler provides external registers,
+allocated from
+.CW R15
+down.
+.PP
+The calling conventions are different from the 386.
+.CW CALL
+pushes, and
+.CW RET
+pops a 64-bit return address on the stack.
+The first integer or pointer argument is passed in a register, which is
+.CW BP
+for an integer or pointer (it can be referred to in assembly code by the pseudonym
+.CW RARG ).
+.CW AX
+holds the return value from subroutines as before.
+Floating-point results are returned in
+.CW X0 ,
+although currently the first parameter is not passed in a register if floating-point.
+All parameters less than 8 bytes in length have 8 byte slots reserved on the stack
+to preserve alignment and simplify variable-length argument list access,
+including the first parameter when passed in a register,
+although bytes 4 to 7 are not initialized.
+.PP
+The assembler assumes 64-bit mode unless a
+.CW MODE
+pseudo-operation is given:
+.P1
+	MODE $32
+.P2
+to change to 32-bit mode.
+The effect is mainly to diagnose instructions that are illegal in
+the given mode, but the loader will also assume 32-bit operands and addresses,
+and 32-bit PC values for call and return.
+.SH
+Alpha
+.PP
+On the Alpha, all registers are 64 bits.  The architecture handles 32-bit values
+by giving them a canonical format (sign extension in the case of integer registers).
+Registers are numbered
+.CW R0
+through
+.CW R31 .
+.CW R0
+holds the return value from subroutines, and also the first parameter.
+.CW R30
+is the stack pointer,
+.CW R29
+is the static base,
+.CW R26
+is the link register, and
+.CW R27
+and
+.CW R28
+are linker temporaries.
+.PP
+Floating point registers are numbered
+.CW F0
+to
+.CW F31 .
+.CW F28
+contains
+.CW 0.5 ,
+.CW F29
+contains
+.CW 1.0 ,
+and
+.CW F30
+contains
+.CW 2.0 .
+.CW F31
+is always
+.CW 0.0
+on the Alpha.
+.PP
+The extension character for
+.CW MOV
+follows DEC's notation:
+.CW B
+for byte (8 bits),
+.CW W
+for word (16 bits),
+.CW L
+for long (32 bits),
+and
+.CW Q
+for quadword (64 bits).
+Byte and ``word'' loads and stores may be made unsigned
+by appending a
+.CW U .
+.CW S
+and
+.CW T
+refer to IEEE floating point single precision (32 bits) and double precision (64 bits), respectively.
+.SH
+PowerPC
+.PP
+The PowerPC follows the Plan 9 model set by the MIPS and SPARC,
+not the elaborate ABIs.
+The 32-bit instructions of the 60x and 8xx PowerPC architectures are supported;
+there is no support for the older POWER instructions.
+Registers are
+.CW R0
+through
+.CW R31 .
+.CW R0
+is initialized to zero; this is done by C start up code
+and assumed by the compiler and loader.
+.CW R1
+is the stack pointer.
+.CW R2
+is the static base register, with value the address of
+.CW setSB(SB) .
+.CW R3
+is the return register and also the register holding the first
+argument to a C function, with space reserved at
+.CW 0(FP)
+as on the MIPS.
+.CW R31
+is the loader temporary.
+The external registers in Plan 9's C are allocated from
+.CW R30
+down.
+.PP
+Floating point registers are called
+.CW F0
+through
+.CW F31 .
+By convention, several registers are initialized
+to specific values; this is done by the operating system.
+.CW F27
+must be initialized to the value
+.CW 0x4330000080000000
+(used by float-to-int conversion),
+.CW F28
+to the value 0.0,
+.CW F29
+to 0.5,
+.CW F30
+to 1.0, and
+.CW F31
+to 2.0.
+.PP
+As on the MIPS and SPARC, the assembler accepts arbitrary literals
+as operands to
+.CW MOVW ,
+and also to
+.CW ADD
+and others where `immediate' variants exist,
+and the loader generates sequences
+of
+.CW addi ,
+.CW addis ,
+.CW oris ,
+etc. as required.
+The register indirect addressing modes use the same syntax as the SPARC,
+including double indexing when allowed.
+.PP
+The instruction names are generally derived from the Motorola ones,
+subject to slight transformation:
+the
+.CW . ' `
+marking the setting of condition codes is replaced by
+.CW CC ,
+and when the letter
+.CW o ' `
+represents `OE=1' it is replaced by
+.CW V .
+Thus
+.CW add ,
+.CW addo.
+and
+.CW subfzeo.
+become
+.CW ADD ,
+.CW ADDVCC
+and
+.CW SUBFZEVCC .
+As well as the three-operand conditional branch instruction
+.CW BC ,
+the assembler provides pseudo-instructions for the common cases:
+.CW BEQ ,
+.CW BNE ,
+.CW BGT ,
+.CW BGE ,
+.CW BLT ,
+.CW BLE ,
+.CW BVC ,
+and
+.CW BVS .
+The unconditional branch instruction is
+.CW BR .
+Indirect branches use
+.CW "(CTR)"
+or
+.CW "(LR)"
+as target.
+.PP
+Load or store operations are replaced by
+.CW MOV
+variants in the usual way:
+.CW MOVW
+(move word),
+.CW MOVH
+(move halfword with sign extension), and
+.CW MOVB
+(move byte with sign extension, a pseudo-instruction),
+with unsigned variants
+.CW MOVHZ
+and
+.CW MOVBZ ,
+and byte-reversing
+.CW MOVWBR
+and
+.CW MOVHBR .
+`Load or store with update' versions are
+.CW MOVWU ,
+.CW MOVHU ,
+and
+.CW MOVBZU .
+Load or store multiple is
+.CW MOVMW .
+The exceptions are the string instructions, which are
+.CW LSW
+and
+.CW STSW ,
+and the reservation instructions
+.CW lwarx
+and
+.CW stwcx. ,
+which are
+.CW LWAR
+and
+.CW STWCCC ,
+all with operands in the usual data-flow order.
+Floating-point load or store instructions are
+.CW FMOVD ,
+.CW FMOVDU ,
+.CW FMOVS ,
+and
+.CW FMOVSU .
+The register to register move instructions
+.CW fmr
+and
+.CW fmr.
+are written
+.CW FMOVD
+and
+.CW FMOVDCC .
+.PP
+The assembler knows the commonly used special purpose registers:
+.CW CR ,
+.CW CTR ,
+.CW DEC ,
+.CW LR ,
+.CW MSR ,
+and
+.CW XER .
+The rest, which are often architecture-dependent, are referenced as
+.CW SPR(n) . 
+The segment registers of the 60x series are similarly
+.CW SEG(n) ,
+but
+.I n
+can also be a register name, as in
+.CW SEG(R3) .
+Moves between special purpose registers and general purpose ones,
+when allowed by the architecture,
+are written as
+.CW MOVW ,
+replacing
+.CW mfcr ,
+.CW mtcr ,
+.CW mfmsr ,
+.CW mtmsr ,
+.CW mtspr ,
+.CW mfspr ,
+.CW mftb ,
+and many others.
+.PP
+The fields of the condition register
+.CW CR
+are referenced as
+.CW CR(0)
+through
+.CW CR(7) .
+They are used by the
+.CW MOVFL
+(move field) pseudo-instruction,
+which produces
+.CW mcrf
+or
+.CW mtcrf .
+For example:
+.P1
+	MOVFL	CR(3), CR(0)
+	MOVFL	R3, CR(1)
+	MOVFL	R3, $7, CR
+.P2
+They are also accepted in
+the conditional branch instruction, for example
+.P1
+	BEQ	CR(7), label
+.P2
+Fields of the
+.CW FPSCR
+are accessed using
+.CW MOVFL
+in a similar way:
+.P1
+	MOVFL	FPSCR, F0
+	MOVFL	F0, FPSCR
+	MOVFL	F0, $7, FPSCR
+	MOVFL	$0, FPSCR(3)
+.P2
+producing
+.CW mffs ,
+.CW mtfsf ,
+or
+.CW mtfsfi
+as appropriate.
+.SH
+ARM
+.PP
+The assembler provides access to
+.CW R0
+through
+.CW R14
+and the
+.CW PC .
+The stack pointer is
+.CW R13 ,
+the link register is
+.CW R14 ,
+and the static base register is
+.CW R12 .
+.CW R0
+is the return register and also the register holding
+the first argument to a subroutine.
+The assembler supports the
+.CW CPSR
+and
+.CW SPSR
+registers.
+It also knows about coprocessor registers
+.CW C0
+through
+.CW C15 .
+Floating registers are
+.CW F0
+through
+.CW F7 ,
+.CW FPSR
+and
+.CW FPCR .
+.PP
+As with the other architectures, loads and stores are called
+.CW MOV ,
+e.g.
+.CW MOVW
+for load word or store word, and
+.CW MOVM
+for
+load or store multiple,
+depending on the operands.
+.PP
+Addressing modes are supported by suffixes to the instructions:
+.CW .IA
+(increment after),
+.CW .IB
+(increment before),
+.CW .DA
+(decrement after), and
+.CW .DB
+(decrement before).
+These can only be used with the
+.CW MOV
+instructions.
+The move multiple instruction,
+.CW MOVM ,
+defines a range of registers using brackets, e.g.
+.CW [R0-R12] .
+The special
+.CW MOVM
+addressing mode bits
+.CW W ,
+.CW U ,
+and
+.CW P
+are written in the same manner, for example,
+.CW MOVM.DB.W .
+A
+.CW .S
+suffix allows a
+.CW MOVM
+instruction to access user
+.CW R13
+and
+.CW R14
+when in another processor mode.
+Shifts and rotates in addressing modes are supported by binary operators
+.CW <<
+(logical left shift),
+.CW >>
+(logical right shift),
+.CW ->
+(arithmetic right shift), and
+.CW @>
+(rotate right); for example
+.CW "R7>>R2" or
+.CW "R2@>2" .
+The assembler does not support indexing by a shifted expression;
+only names can be doubly indexed.
+.PP
+Any instruction can be followed by a suffix that makes the instruction conditional:
+.CW .EQ ,
+.CW .NE ,
+and so on, as in the ARM manual, with synonyms
+.CW .HS
+(for
+.CW .CS )
+and
+.CW .LO
+(for
+.CW .CC ),
+for example
+.CW ADD.NE .
+Arithmetic
+and logical instructions
+can have a
+.CW .S
+suffix, as ARM allows, to set condition codes.
+.PP
+The syntax of the
+.CW MCR
+and
+.CW MRC
+coprocessor instructions is largely as in the manual, with the usual adjustments.
+The assembler directly supports only the ARM floating-point coprocessor
+operations used by the compiler:
+.CW CMP ,
+.CW ADD ,
+.CW SUB ,
+.CW MUL ,
+and
+.CW DIV ,
+all with
+.CW F
+or
+.CW D
+suffix selecting single or double precision.
+Floating-point load or store become
+.CW MOVF
+and
+.CW MOVD .
+Conversion instructions are also specified by moves:
+.CW MOVWD ,
+.CW MOVWF ,
+.CW MOVDW ,
+.CW MOVWD ,
+.CW MOVFD ,
+and
+.CW MOVDF .
binary files /dev/null b/doc/asm.pdf differ
binary files /dev/null b/doc/backmatter.pdf differ
--- /dev/null
+++ b/doc/bltj.ms
@@ -1,0 +1,1073 @@
+.TL
+The Inferno Operating System
+.AU
+Sean Dorward
+Rob Pike
+David Leo Presotto
+Dennis M. Ritchie
+Howard Trickey
+Phil Winterbottom
+.AI
+Computing Science Research Center
+Lucent Technologies, Bell Labs
+Murray Hill, New Jersey
+USA
+.FS
+.FA
+Originally appeared in the
+.I "Bell Labs Technical Journal" ,
+Vol. 2, No. 1, Winter 1997, pp. 5-18.
+.br
+Minor revisions have been made by Vita Nuova to reflect subsequent changes to Inferno.
+.br
+Copyright © 1997 Lucent Technologies Inc.  All rights reserved.
+.FE
+.AB
+Inferno is an operating system for creating and supporting distributed services.
+It was originally developed by the Computing Science Research Center of Bell Labs, the R&D arm of Lucent Technologies, and
+further developed by other groups in Lucent.
+.LP
+Inferno was designed specifically as a commercial product, both for licensing
+in the marketplace and for use within new Lucent offerings.
+It encapsulates many years of Bell Labs research in operating systems, languages, on-the-fly compilers, graphics, security, networking and portability.
+.AE
+.SH
+Introduction
+.LP
+Inferno is intended to be used in a variety of network environments, for example those supporting
+advanced telephones, hand-held devices, TV set-top boxes attached to cable or satellite systems, and inexpensive Internet computers, but also in conjunction with traditional computing systems.
+.LP
+The most visible new environments involve cable television, direct satellite broadcast, the Internet, and other networks. As the entertainment, telecommunications, and computing industries converge and interconnect, a variety of public data networks are emerging, each potentially as useful and profitable as the telephone system. Unlike the telephone system, which started with standard terminals and signaling, these networks are developing in a world of diverse terminals, network hardware, and protocols. Only a well-designed, economical operating system can insulate the various providers of content and services from the equally varied transport and presentation
+platforms. Inferno is a network operating system for this new world.
+.LP
+Inferno's definitive strength lies in its portability and versatility across several dimensions:
+.IP •
+Portability across processors: it currently runs on Intel, Sparc, MIPS, ARM, HP-PA, and PowerPC architectures and is readily portable to others.
+.IP •
+Portability across environments: it runs as a stand-alone operating system on small terminals, and also as a user application under Windows NT, Windows 95, Unix (Irix, Solaris, FreeBSD, Linux, AIX, HP/UX) and Plan 9. In all of these environments, Inferno applications see an identical interface.
+.IP •
+Distributed design: the identical environment is established at the user's terminal and at the server, and each may import the resources (for example, the attached I/O devices or networks) of the other.  Aided by the communications facilities of the run-time system, applications may be split easily (and even dynamically) between client and server.
+.IP •
+Minimal hardware requirements: it runs useful applications stand-alone on machines with as little as 1 MB of memory, and does not require memory-mapping hardware.
+.IP •
+Portable applications: Inferno applications are written in the type-safe language Limbo, whose binary representation is identical over all platforms.
+.IP •
+Dynamic adaptability: applications may, depending on the hardware or other resources available, load different program modules to perform a specific function. For example, a video player application might use any of several different decoder modules.
+.LP
+Underlying the design of Inferno is a model of the diversity of application areas it intends to stimulate. Many providers are interested in purveying media and services: telephone network service providers, WWW servers, cable companies, merchants, various information providers.
+There are many connection technologies: ordinary telephone modems, ISDN, ATM, the Internet, analog broadcast or cable TV, cable modems, digital video on demand, and other interactive TV systems.
+.LP
+Applications more clearly related to Lucent's current and planned product offerings include
+control of switches and routers, and the associated operations system facilities needed to support them.
+For example,  Inferno software controls an IP switch/router for voice and data being
+developed by Lucent's Bell Labs research and Network Systems organizations.
+An Inferno-based firewall (Signet) is being used to secure outside access to the Research
+Internet connection.
+.LP
+Finally, there are existing or potential hardware endpoints. Some are in consumers' homes: PCs,
+game consoles, newer set-top boxes. Some are inside the networks themselves: nodes for billing, network monitoring or provisioning. The higher ends of these spectra, epitomized by fully interactive TV with video on demand, may be fascinating, but have developed more slowly than expected. One reason is the cost of the set-top box, especially its memory requirements. Portable terminals, because of weight and cost considerations, are similarly constrained.
+.LP
+Inferno is parsimonious enough in its resource requirements to support interesting applications on today's hardware, while being versatile enough to grow into the future. In particular, it enables developers to create applications that will work across a range of facilities. An example: an interactive shopping catalog that works in text mode over a POTS modem, shows still pictures (perhaps with audio) of the merchandise over ISDN, and includes video clips over digital cable.
+.LP
+Clearly not everyone who deploys an Inferno-based solution will want to span the whole range of possibilities, but the system architecture should be constrained only by the desired markets and the available interconnection and server technologies, not by the software.
+.SH
+Inferno interfaces
+.LP
+The role of the Inferno system is to
+.I "create"
+several standard interfaces for its applications:
+.IP •
+Applications use various resources internal to the system, such as a consistent virtual machine that runs the application programs, together with library modules that perform services as simple as string manipulation through more sophisticated graphics services for dealing with text, pictures,
+higher-level toolkits, and video.
+.IP •
+Applications exist in an external environment containing resources such as data files that can be read and manipulated, together with objects that are named and manipulated like files but are more active. Devices (for example a hand-held remote control, an MPEG decoder or a network interface) present themselves to the application as files.
+.IP •
+Standard protocols exist for communication within and between separate machines running Inferno, so that applications can cooperate.
+.LP
+At the same time, Inferno
+.I uses
+interfaces supplied by an existing environment, either bare hardware or standard operating systems and protocols.
+.LP
+Most typically, an Inferno-based service would consist of many relatively cheap terminals running Inferno as a native system, and a smaller number of large machines running Inferno as a hosted system. On these server machines Inferno might interface to databases, transaction systems, existing OA&M facilities, and other resources provided under the native operating system. The Inferno applications themselves would run either on the client or server machines, or both.
+.SH
+External Environment of Inferno Applications
+.LP
+The purpose of most Inferno applications is to present information or media to the user; thus applications must locate the information sources in the network and construct a local representation of them. The information flow is not one-way: the user's terminal (whether a network computer, TV set-top, PC, or videophone) is also an information source and its devices represent resources to applications. Inferno draws heavily on the design of the Plan 9 operating system [1] in the way it presents resources to these applications.
+.LP
+The design has three principles.
+.IP •
+All resources are named and accessed like files in a forest of hierarchical file systems.
+.IP •
+The disjoint resource hierarchies provided by different services are joined together into a single private hierarchical
+.I "name space" .
+.IP •
+A communication protocol, called
+.I "Styx" ,
+is applied uniformly to access these resources, whether local or remote.
+.LP
+In practice, most applications see a fixed set of files organized as a directory tree. Some of the files contain ordinary data, but others represent more active resources. Devices are represented as files, and device drivers (such as a modem, an MPEG decoder, a network interface, or the TV screen) attached to a particular hardware box present themselves as small directories. These directories typically containing two files,
+.CW "data"
+and
+.CW "ctl" ,
+which respectively perform actual device input/output and control operations. System services also live behind file names. For example, an Internet domain name server might be attached to an agreed-upon name (say
+.CW "/net/dns" ); 
+after writing to this file a string representing a symbolic Internet domain name, a subsequent read from the file would return the corresponding numeric Internet address.
+.LP
+The glue that connects the separate parts of the resource name space together is the Styx protocol.
+Within an instance of Inferno, all the device drivers and other internal resources respond to the procedural version of Styx. The Inferno kernel implements a
+.I "mount driver"
+that transforms file system operations into remote procedure calls for transport over a network. On the other side of the connection, a server unwraps the Styx messages and implements them using resources local to it. Thus, it is possible to import parts of the name space (and thus resources) from other machines.
+.LP
+To extend the example above, it is unlikely that a set-top box would store the code needed for an Internet domain name-server within itself. Instead, an Internet browser would import the
+.CW "/net/dns"
+resource into its own name space from a server machine across a network.
+.LP
+The Styx protocol lies above and is independent of the communications transport layer; it is readily carried over TCP/IP, PPP, ATM or various modem transport protocols.
+.SH
+Internal Environment of Inferno Applications
+.LP
+Inferno applications are written in a new language called Limbo [2], which was designed specifically for the Inferno environment. Its syntax is influenced by C and Pascal, and it supports the standard data types common to them, together with several higher-level data types such as lists, tuples, strings, dynamic arrays, and simple abstract data types.
+.LP
+In addition, Limbo supplies several advanced constructs carefully integrated into the Inferno virtual machine. In particular, a communication mechanism called a
+.I "channel"
+is used to connect different Limbo tasks on the same machine or across the network.
+A channel transports typed data in a machine-independent fashion, so that complex data structures (including channels themselves) may be passed between Limbo tasks or attached to files in the name space for language-level communication between machines.
+.LP
+Multi-tasking is supported directly by the Limbo language: independently scheduled threads of control may be spawned, and an
+.CW "alt"
+statement is used to coordinate the channel communication
+between tasks (that is,
+.CW "alt"
+is used to select one of several channels that are ready to communicate).
+By building channels and tasks into the language and its virtual machine, Inferno encourages a communication style that is easy to use and safe.
+.LP
+Limbo programs are built of
+.I "modules" ,
+which are self-contained units with a well-defined interface
+containing functions (methods), abstract data types, and constants defined by the module and visible outside it. Modules are accessed dynamically; that is, when one module wishes to make use of another, it dynamically executes a
+.CW "load"
+statement naming the desired module, and uses a returned handle to access the new module.
+When the module is no longer in use, its storage and code will be released.
+The flexibility of the modular structure contributes to the smallness of typical Inferno applications, and also to their adaptability.
+For example, in the shopping catalog described above,
+the application's main module checks dynamically for the existence of the video resource.
+If it is unavailable, the video-decoder module is never loaded.
+.LP
+Limbo is fully type-checked at compile- and run-time; for example, pointers, besides being more
+restricted than in C, are checked before being dereferenced, and the type-consistency of a dynamically loaded module is checked when it is loaded. Limbo programs run safely on a machine
+without memory-protection hardware.
+Moreover, all Limbo data and program objects are subject to
+a garbage collector, built deeply into the Limbo run-time system. All system data objects are tracked by the virtual machine and freed as soon as they become unused. For example, if an application task creates a graphics window and then terminates, the window automatically disappears the instant the last reference to it has gone away.
+.LP
+Limbo programs are compiled into byte-codes representing instructions for a virtual machine called
+Dis. The architecture of the arithmetic part of Dis is a simple 3-address machine, supplemented with a few specialized operations for handling some of the higher-level data types like arrays and strings. Garbage collection is handled below the level of the machine language; the scheduling of tasks is similarly hidden. When loaded into memory for execution, the byte-codes are expanded
+into a format more efficient for execution; there is also an optional on-the-fly compiler that turns a Dis instruction stream into native machine instructions for the appropriate real hardware. This can be done efficiently because Dis instructions match well with the instruction-set architecture of today's machines. The resulting code executes at a speed approaching that of compiled C.
+.LP
+Underlying Dis is the Inferno kernel, which contains the interpreter and on-the-fly compiler as well as memory management, scheduling, device drivers, protocol stacks, and the like.
+The kernel also contains the core of the file system (the name evaluator and the code that turns file system operations into remote procedure calls over communications links) as well as the small file systems implemented internally.
+.LP
+Finally, the Inferno virtual machine implements several standard modules internally. These include
+.CW "Sys" ,
+which provides system calls and a small library of useful routines (e.g. creation of network connections, string manipulations). Module
+.CW "Draw"
+is a basic graphics library that handles raster graphics, fonts, and windows. Module
+.CW "Prefab"
+builds on
+.CW "Draw"
+to provide structured complexes containing images and text inside of windows; these elements may be scrolled, selected, and changed by the methods of
+.CW "Prefab" .
+Module
+.CW "Tk"
+is an all-new implementation of the Tk graphics toolkit [18], with a Limbo interface. A
+.CW "Math"
+module encapsulates the procedures for numerical programming.
+.SH
+The Environment of the Inferno System
+.LP
+Inferno creates a standard environment for applications. Identical application programs can run
+under any instance of this environment, even in distributed fashion, and see the same resources.
+Depending on the environment in which Inferno itself is implemented, there are several versions of the Inferno kernel, Dis/Limbo interpreter, and device driver set.
+.LP
+When running as the native operating system, the kernel includes all the low-level glue (interrupt handlers, graphics and other device drivers) needed to implement the abstractions presented to applications.
+For a hosted system, for example under Unix, Windows NT or Windows 95, Inferno runs as a set of ordinary processes.
+Instead of mapping its device-control functionality to real hardware,
+it adapts to the resources provided by the operating system under which it runs.
+For example, under Unix, the graphics library might be implemented using the X window system and the networking using the socket interface; under Windows, it uses the native Windows graphics and Winsock calls.
+.LP
+Inferno is, to the extent possible, written in standard C and most of its components are independent of the many operating systems that can host it.
+.SH
+Security in Inferno
+.LP
+Inferno provides security of communication, resource control, and
+system integrity.
+.LP
+Each external communication channel may be transmitted in the clear,
+accompanied by message digests to prevent corruption, or encrypted to
+prevent corruption and interception.  Once communication is set up,
+the encryption is transparent to the application.  Key exchange is
+provided through standard public-key mechanisms; after key exchange,
+message digesting and line encryption likewise use standard symmetric
+mechanisms.
+.LP
+Inferno is secure against erroneous or malicious applications, and
+encourages safe collaboration between mutually suspicious service
+providers and clients.  The resources available to applications appear
+exclusively in the name space of the application, and standard
+protection modes are available.  This applies to data, to
+communication resources, and to the executable modules that constitute
+the applications.  Security-sensitive resources of the system are
+accessible only by calling the modules that provide them; in
+particular, adding new files and servers to the name space is
+controlled and is an authenticated operation.  For example, if the
+network resources are removed from an application's name space, then
+it is impossible for it to establish new network connections.
+.LP
+Object modules may be signed by trusted authorities who guarantee
+their validity and behavior, and these signatures may be checked by
+the system the modules are accessed.
+.LP
+Although Inferno provides a rich variety of authentication and security
+mechanisms, as detailed below, few application programs need to
+be aware of them or explicitly include coding to make use of them.
+Most often, access to resources across a secure communications link
+is arranged in advance by the larger system in which the application operates.
+For example, when a client system uses a server system
+and connection authentication or link encryption is appropriate,
+the server resources will most naturally be supplied
+as a part of the application's name space.
+The communications channel that carries the Styx protocol
+can be set to authenticate or encrypt; thereafter,
+all use of the resource is automatically protected.
+.SH
+Security mechanisms
+.LP
+Authentication and digital signatures are performed using
+public key cryptography.  Public keys are certified by
+Inferno-based or other certifying authorities that sign the public keys with their
+own private key.
+.LP
+Inferno uses encryption for:
+.IP •
+mutual authentication of communicating parties;
+.IP •
+authentication of messages between these parties; and
+.IP •
+encryption of messages between these parties.
+.LP
+The encryption algorithms provided by Inferno
+include the SHA, MD4, and MD5 secure hashes;
+Elgamal public key signatures and signature verification [4];
+RC4 encryption;
+DES encryption;
+and public key exchange based on the Diffie-Hellman scheme.
+The public key signatures use keys with moduli up to 4096 bits,
+512 bits by default.
+.LP
+There is no generally accepted national or international authority
+for storing or generating public or private encryption keys.
+Thus Inferno includes tools for using or implementing a trusted authority,
+but it does not itself provide the authority,
+which is an administrative function.
+Thus an organization using Inferno (or any other security
+and key-distribution scheme) must design its system to suit its
+own needs, and in particular decide whom to trust as a Certifying
+Authority (CA).  However, the Inferno design is sufficiently flexible
+and modular to accommodate the protocols likely to be attractive in practice.
+.LP
+The certifying authority that signs a user's
+public key determines the size of the key and the public key
+algorithm used.  Tools provided with
+Inferno use these signatures for authentication.  Library
+interfaces are provided for Limbo programs to sign and verify
+signatures.
+.LP
+Generally authentication is performed using public key cryptography.  Parties
+register by having their public keys signed by the certifying authority (CA).
+The signature covers a secure hash (SHA, MD4, or MD5) of
+the name of the party, his public key, and an expiration time.  The signature,
+which contains the name of the signer, along with the signed information,
+is termed a
+.I "certificate" .
+.LP
+When parties communicate, they use the Station to Station protocol[5] to
+establish the identities of the two parties and to create a mutually known secret.
+This STS protocol uses the Diffie-Hellman algorithm [6] to create this shared
+secret.
+The protocol is protected against replay attacks by choosing new random
+parameters for each conversation.  It is secured against `man in
+the middle' attacks by having the parties exchange certificates and then
+digitally signing key parts of the protocol.   To masquerade as another
+party an attacker would have to be able to forge that party's signature.
+.SH
+Line Security
+.LP
+A network conversation can be secured against modification alone
+or against both modification and snooping.  To secure against
+modification, Inferno can append a secure MD5 or SHA hash (called a digest),
+.P1
+hash(secret, message, messageid)
+.P2
+to each message.
+.I "Messageid"
+is a 32 bit number that starts at 0 and is incremented by
+one for each message sent.  Thus messages can be neither
+changed, removed, reordered or inserted into the stream without knowing
+the secret or breaking the secure hash algorithm.
+.LP
+To secure against snooping, Inferno supports encryption of the complete conversation
+using either RC4 or DES with either DES chain block coding (DESCBC)
+and electronic code book (DESECB).
+.LP
+Inferno uses the same encapsulation format as Netscape's Secure Sockets Layer [7].
+It is possible to encapsulate
+a  message stream in multiple encapsulations to provide varying degrees of
+security.
+.SH
+Random Numbers
+.LP
+The strength of cryptographic algorithms depends in part on strength
+of the random numbers
+used for choosing keys, Diffie-Hellman parameters, initialization vectors, etc.
+Inferno achieves this in two steps: a slow (100 to 200 bit
+per second) random bit stream comes from sampling the low order bits of a
+free running counter whenever a clock ticks.  The clock must be unsynchronized,
+or at least poorly synchronized, with the counter.  This generator is then used to
+alter the state of a faster pseudo-random number generator.
+Both the slow and fast generators were tested on a number of architectures
+using self correlation, random walk, and repeatability tests.
+.SH
+Introduction to Limbo
+.LP
+Limbo is the application programming language for the Inferno operating system.  Although Limbo looks syntactically like C, it has a number of features that make it easier to use, safer, and more suited to the heterogeneous, networked Inferno environment: a rich set of basic types, strong typing, garbage collection, concurrency, communications, and modules.  Limbo may be interpreted or compiled `just in time' for efficient, portable execution.
+.LP
+This paper introduces the language by studying an example of a complete, useful Limbo program.  The program illustrates general programming as well as aspects of concurrency, graphics, module loading, and other features of Limbo and Inferno.
+.SH
+The problem
+.LP
+Our example program is a stripped-down version of the Inferno[14] program
+.CW "view" ,
+which displays graphical image files on the screen, one per window.  This version sacrifices some functionality, generality, and error-checking but performs the basic job.  The files may be in either GIF[12, 13] or JPEG[19] format and must be converted before display, or they may already be in the Inferno standard format that needs no conversion.
+.CW "View"
+`sniffs' each file to determine what processing it requires, maps the colors if necessary, creates a new window, and copies the converted image to it.  Each window is given a title bar across the top to identify it and hold the buttons to move and delete the window.
+.SH
+The Source
+.LP
+Here is the complete Limbo source for our version of
+.CW "view" ,
+annotated with line numbers for easy reference (Limbo, of course, does not use line numbers).  Subsequent sections explain the workings of the program.  Although the program is too large to absorb as a first example without some assistance, it's worth skimming before moving to the next section, to get an idea of the style of the language.  Control syntax derives from C[11], while declaration syntax comes from the Pascal family of languages[17].  Limbo borrows features from a number of languages (e.g., tuples on lines 45 and 48) and introduces a few new ones (e.g. explicit module loading on lines 90 and 92).
+.P1
+ 1  implement View;
+.P3
+ 2  include "sys.m";
+ 3     sys: Sys;
+.P3
+ 4  include "draw.m";
+ 5     draw: Draw;
+ 6     Rect, Display, Image: import draw;
+.P3
+ 7  include "bufio.m";
+.P3
+ 8  include "imagefile.m";
+.P3
+ 9  include "tk.m";
+10     tk: Tk;
+.P3
+11  include   "wmlib.m";
+12     wmlib: Wmlib;
+.P3
+13  include "string.m";
+14     str: String;
+.P3
+15  View: module
+16  {
+17     init: fn(ctxt: ref Draw->Context,
+                argv: list of string);
+18  };
+.P3
+19  init(ctxt: ref Draw->Context,
+         argv: list of string)
+20  {
+21     sys   = load Sys Sys->PATH;
+22     draw  = load Draw Draw->PATH;
+23     tk    = load Tk Tk->PATH;
+24     wmlib = load Wmlib Wmlib->PATH;
+25     str   = load String String->PATH;
+26     wmlib->init();
+.P3
+27     imageremap := load Imageremap
+                          Imageremap->PATH;
+28     bufio := load Bufio Bufio->PATH;
+.P3
+29     argv = tl argv;
+30     if(argv != nil
+         && str->prefix("-x ", hd argv))
+31        argv = tl argv;
+.P3
+32     viewer := 0;
+33     while(argv != nil){
+34        file := hd argv;
+35        argv = tl argv;
+.P3
+36        im := ctxt.display.open(file);
+37        if(im == nil){
+38           idec := filetype(file);
+39           if(idec == nil)
+40              continue;
+.P3
+41           fd := bufio->open(file,
+                          Bufio->OREAD);
+42           if(fd == nil)
+43              continue;
+.P3
+44           idec->init(bufio);
+45           (ri, err) := idec->read(fd);
+46           if(ri == nil)
+47              continue;
+.P3
+48           (im, err) = imageremap->remap(
+                      ri, ctxt.display, 1);
+49           if(im == nil)
+50              continue;
+51        }
+.P3
+52        spawn view(ctxt, im, file,
+                     viewer++);
+53     }
+54  }
+.P3
+55  view(ctxt: ref Draw->Context,
+         im: ref Image, file: string,
+         viewer: int)
+56  {
+57     corner := string(25+20*(viewer%5));
+.P3
+58     (nil, file) = str->splitr(file, "/");
+59     (t, menubut) := wmlib->titlebar(ctxt.screen,
+            " -x "+corner+" -y "+corner+
+            " -bd 2 -relief raised",
+             "View: "+file, Wmlib->Hide);
+.P3
+60     event := chan of string;
+61     tk->namechan(t, event, "event");
+.P3
+62     tk->cmd(t, "frame .im -height " +
+                  string im.r.dy() +
+                  " -width " +
+                  string im.r.dx());
+63     tk->cmd(t, "bind . <Configure> "+
+                  "{send event resize}");
+64     tk->cmd(t, "bind . <Map> "+
+                  "{send event resize}");
+65     tk->cmd(t, "pack .im -side bottom"+
+                  " -fill both -expand 1");
+66     tk->cmd(t, "update");
+.P3
+67     t.image.draw(posn(t), im, ctxt.display.ones, im.r.min);
+68     for(;;) alt{
+69     menu := <-menubut =>
+70        if(menu == "exit")
+71           return;
+72        wmlib->titlectl(t, menu);
+73     <-event =>
+74        t.image.draw(posn(t), im,
+              ctxt.display.ones, im.r.min);
+75     }
+76  }
+.P3
+77  posn(t: ref Tk->Toplevel): Rect
+78  {
+79     minx := int tk->cmd(t,
+                   ".im cget -actx");
+80     miny := int tk->cmd(t,
+                   ".im cget -acty");
+81     maxx := minx + int tk->cmd(t,
+                   ".im cget -actwidth");
+82     maxy := miny + int tk->cmd(t,
+                   ".im cget -actheight");
+.P3
+83     return ((minx, miny), (maxx, maxy));
+84  }
+.P3
+85  filetype(file: string): RImagefile
+86  {
+87     if(len file>4
+         && file[len file-4:]==".gif")
+88        r := load RImagefile
+                   RImagefile->READGIFPATH;
+89     if(len file>4
+         && file[len file-4:]==".jpg")
+90        r = load RImagefile
+                   RImagefile->READJPGPATH;
+91     return r;
+92  }
+.P2
+.SH
+Modules
+.LP
+Limbo programs are composed of modules that are loaded and linked at run-time.  Each Limbo source file is the implementation of a single module; here line 1 states this file implements a module called
+.CW "View" ,
+whose declaration appears in the
+.CW "module"
+declaration on lines 15-18.  The declaration states that the module has one publicly visible element, the function
+.CW "init" .
+Other functions and variables defined in the file will be compiled into the module but only accessible internally.
+.LP
+The function
+.CW "init"
+has a type signature (argument and return types) that makes it callable from the Inferno shell, a convention not made explicit here.  The type of
+.CW "init"
+allows
+.CW "View"
+to be invoked by typing, for example,
+.P1
+view *.jpg
+.P2
+at the Inferno command prompt to view all the JPEG files in a directory.  This interface is all that is required for the module to be callable from the shell; all programs are constructed from modules, and some modules are directly callable by the shell because of their type.  In fact the shell invokes
+.CW "View"
+by loading it and calling
+.CW "init" ,
+not for example through the services of a system
+.CW "exec"
+function as in a traditional operating system.
+.LP
+Not all modules, of course, implement shell commands; modules are also used to construct libraries, services, and other program components.  The module
+.CW "View"
+uses the services of other modules for I/O, graphics, file format conversion, and string processing.  These modules are identified on lines 2-14.  Each module's interface is stored in a public `include file' that holds a definition of a module much like lines 15-18 of the
+.CW "View"
+program.  For example, here is an excerpt from the include file
+.CW "sys.m" :
+.P1
+Sys: module
+{
+   PATH:	con	"$Sys";
+
+   FD: adt   # File descriptor
+   {
+      fd:   int;
+   };
+
+   OREAD:   con 0;
+   OWRITE:  con 1;
+   ORDWR:   con 2;
+
+   open:   fn(s: string, mode: int): ref FD;
+   print:  fn(s: string, *): int;
+   read:   fn(fd: ref FD, buf: array of byte, n: int): int;
+   write:  fn(fd: ref FD, buf: array of byte, n: int): int;
+};
+.P2
+This defines a module type, called
+.CW "Sys" ,
+that has functions with familiar names like
+.CW "open"
+and
+.CW "print" ,
+constants like
+.CW "OREAD"
+to specify the mode for opening a file, an aggregate type
+.CW "adt" ) (
+called
+.CW "FD" ,
+returned by
+.CW "open" ,
+and a constant string called
+.CW "PATH" .
+.LP
+After including the definition of each module,
+.CW "View"
+declares variables to access the module.  Line 3, for example, declares the variable
+.CW "sys"
+to have type
+.CW "Sys" ;
+it will be used to hold a reference to the implementation of the module.  Line 6 imports a number of types from the
+.CW "draw"
+(graphics) module to simplify their use; this line states that the implementation of these types is by default to be that provided by the module referenced by the variable
+.CW "draw" .
+Without such an
+.CW "import"
+statement, calls to methods of these types would require explicit mention of the module providing the implementation.
+.LP
+Unlike most module languages, which resolve unbound references to modules automatically, Limbo requires explicit `loading' of module implementations.
+Although this requires more bookkeeping, it allows a program to have fine control over the loading (and unloading) of modules, an important property in the small-memory systems in which Inferno is intended to run.
+Also, it allows easy garbage collection of unused modules and allows multiple implementations to serve a single interface, a style of programming we will exploit in
+.CW "View" .
+.LP
+Declaring a module variable such as
+.CW "sys"
+is not sufficient to access a module; an implementation must also be loaded and bound to the variable.  Lines 21-25 load the implementations of the standard modules used by
+.CW "View" .
+The
+.CW "load"
+operator, for example
+.P1
+sys = load Sys Sys->PATH;
+.P2
+takes a type
+.CW "Sys" ), (
+the file name of the implementation
+.CW "Sys->PATH" ), (
+and loads it into memory.  If the implementation matches the specified type, a reference to the implementation is returned and stored in the variable
+.CW "sys" ). (
+If not, the constant
+.CW "nil"
+will be returned to indicate an error.  Conventionally, the
+.CW "PATH"
+constant defined by a module names the default implementation.  Because
+.CW "Sys"
+is a built-in module provided by the system, it has a special form of name; other modules'
+.CW "PATH"
+variables name files containing actual code.  For example,
+.CW "Wmlib->PATH"
+is \f5"/dis/lib/wmlib.dis"\fP.
+Note, though, that the name of the implementation of the module in a
+.CW "load"
+statement can be any string.
+.LP
+Line 26 initializes the
+.CW "wmlib"
+module by invoking its
+.CW "init"
+function (unrelated to the
+.CW "init"
+of
+.CW "View" ).  
+Note the use of the
+.CW "->"
+operator to access the member function of the module.  The next two lines load modules, but add a new wrinkle: they also
+.I "declare"
+and
+.I "initialize"
+the module variables storing the reference.  Limbo declarations have the general form
+.P1
+\fIvar\fP: \fItype\fP = \fIvalue\fP;
+.P2
+If the type is missing, it is taken to be the type of the value, so for example,
+.P1
+bufio := load Bufio Bufio->PATH;
+.P2
+on line 28 declares a variable of type
+.CW "Bufio"
+and initializes it to the result of the
+.CW "load"
+expression.
+.SH
+The main loop
+.LP
+The
+.CW "init"
+function takes two parameters, a graphics context,
+.CW "ctxt" ,
+for the program and a list of command-line argument strings,
+.CW "argv" .
+.CW "Argv"
+is a
+.CW "list"
+.CW "of"
+.CW "string" ;
+strings are a built-in type in Limbo and lists are a built-in form of constructor.  Lists have several operations defined:
+.CW "hd"
+(head) returns the first element in the list,
+.CW "tl"
+(tail) the remainder after the head, and
+.CW "len"
+(length) the number of elements in the list.
+.LP
+Line 29 throws away the first element of
+.CW "argv" ,
+which is conventionally the name of the program being invoked by the shell, and lines 30-31 ignore a geometry argument passed by the window system.  The loop from lines 33 to 53 processes each file named in the remaining arguments; when
+.CW "argv"
+is a
+.CW "nil"
+list, the loop is complete.  Line 34 picks off the next file name and line 35 updates the list.
+.LP
+Line 36 is the first method call we have seen:
+.P1
+im := ctxt.display.open(file);
+.P2
+The parameter
+.CW "ctxt"
+is an
+.CW "adt"
+that contains all the relevant information for the program to access its graphics environment.  One of its elements, called
+.CW "display" ,
+represents the connection to the frame buffer on which the program may write.  The
+.CW "adt"
+.CW "display"
+(whose type is imported on line 6) has a member function
+.CW "open"
+that reads a named image file into the memory associated with the frame buffer, returning a reference to the new image. (In X[20] terminology,
+.CW "display"
+represents a connection to the server and
+.CW "open"
+reads a pixmap from a file and instantiates it on that server.)
+.LP
+The
+.CW "display.open"
+method succeeds only if the file exists and is in the standard Inferno image format.  If it fails, it will return
+.CW "nil"
+and lines 38-50 will attempt to convert the file into the right form.
+.SH
+Decoding the file
+.LP
+Line 38 calls
+.CW "filetype"
+to determine what format the file has.  The simple version here, on lines 85-92, just looks at the file suffix to determine the type.  A realistic implementation would work harder, but even this version illustrates the utility of program-controlled loading of modules.
+.LP
+The decoding interface for an image file format is specified by the module type
+.CW "RImagefile" .
+However, unlike the other modules we have looked at,
+.CW "RImagefile"
+has a number of implementations.  If the file is a GIF file,
+.CW "filetype"
+returns the implementation of
+.CW "RImagefile"
+that decodes GIFs; if it is a JPEG file,
+.CW "filetype"
+returns an implementation that decodes JPEGs.  In either case, the
+.CW "read"
+method has the same interface.  Since reference variables like
+.CW "r"
+are implicitly initialized to
+.CW "nil" ,
+that is what
+.CW "filetype"
+will return if it does not recognize the image format.
+.LP
+Thus,
+.CW "filetype"
+accepts a file name and returns the implementation of a module to decode it.
+.LP
+A couple of other points about
+.CW "filetype" .
+First, the expression
+.CW "file[len file-4:]"
+is a
+.I "slice"
+of the string
+.CW "file" ;
+it creates a string holding the last four characters of the file name.  The colon separates the starting and ending indices of the slice; the missing second index defaults to the end of the string.  As with lists,
+.CW "len"
+returns the number of characters (not bytes; Limbo uses Unicode[21] throughout) in the string.
+.LP
+Second, and more important, this version of
+.CW "filetype"
+loads the decoder module anew every time it is called, which is clearly inefficient.  It's easy to do better, though: just store the module in a global, as in this fragment:
+.P1
+readjpg: RImagefile;
+filetype(...)...
+{
+   if(isjpg()){
+      if(readjpg == nil)
+         readjpg = load RImagefile
+            RImagefile->READJPGPATH;
+      return readjpg;
+   }
+}
+.P2
+The program can form its own policies on loading and unloading modules based on time/space or other tradeoffs; the system does not impose its own.
+.LP
+Returning to the main loop, after the type of the file has been discovered, line 41 opens the file for I/O using the buffered I/O package.  Line 44 calls the
+.CW "init"
+function of the decoder module, passing it the instance of the buffered I/O module being used (if we were caching decoder modules, this call to
+.CW "init"
+would be done only when the decoder is first loaded.)  Finally, the Limbo-characteristic line 45 reads in the file:
+.P1
+(ri, err) := idec->read(fd);
+.P2
+The
+.CW "read"
+method of the decoder does the hard job of cracking the image format, which is beyond the scope of this paper.  The result is a
+.I "tuple" :
+a pair of values.  The first element of the pair is the image, while the second is an error string.  If all goes well, the
+.CW "err"
+will be
+.CW "nil" ;
+if there is a problem, however,
+.CW "err"
+may be printed by the application to report what went wrong.  The interesting property of this style of error reporting, common to Limbo programs, is that an error can be returned even if the decoding was successful (that is, even if
+.CW "ri"
+is non-
+.CW "nil" ).  
+For example, the error may be recoverable, in which case it is worth returning the result but also worth reporting that an error did occur, leaving the application to decide whether to display the error or ignore it.
+.CW "View" "\ " (
+ignores it, for brevity.)
+.LP
+In a similar manner, line 48 remaps the colors from the incoming colormap associated with the file to the standard Inferno color map.  The result is an image ready to be displayed.
+.SH
+Creating a process
+.LP
+By line 52 in the main loop, we have an image ready in the variable
+.CW "im"
+and use the Limbo primitive
+.CW "spawn"
+to create a new process to display that image on the screen.
+.CW "Spawn"
+operates on a function call, creating a new process to execute that function.  The process doing the spawning, here the main loop, continues immediately, while the new process begins execution in the specified function with the specified parameters.  Thus line 52 begins a new process in the function
+.CW "view"
+with arguments the graphics context, the image to display, the file name, and a unique identification number used in placing the windows.
+.LP
+The new process shares with the calling process all variables except the stack.  Shared memory can therefore be used to communicate between them; for synchronization, a more sophisticated mechanism is needed, a subject we will cover in the section on communications.
+.SH
+Starting Tk
+.LP
+The function
+.CW "view"
+uses the Inferno Tk graphics toolkit (a re-implementation for Limbo of Ousterhout's Tcl/Tk toolkit [18]) to place the image on the screen in a new window.  Line 57 computes the position of the corner of the window, using the viewer number to stagger the positions of successive windows.  The
+.CW "string"
+keyword is a conversion; in this example the conversion does an automatic translation from an integer expression into a decimal representation of the number.  Thus
+.CW "corner"
+is a string variable, a form more useful in the calls to the Tk library.
+.LP
+The Inferno Tk implementation uses Limbo as its controlling language.
+Rather than building a rich procedural interface, the interface passes strings to a generic Tk command processor, which returns strings as results.
+This is similar to the use Tk within Tcl, but with most of the control flow, arithmetic, and so on written in Limbo.
+.LP
+A good introduction to the style is the function
+.CW "posn"
+on lines 77-84.  The calls to
+.CW "tk->cmd"
+evaluate the textual command in the context defined by the
+.CW "Tk->Toplevel"
+variable
+.CW "t"
+(created on line 57 and passed to
+.CW "posn" ); 
+the result is a decimal integer, converted to binary by the explicit
+.CW "int"
+conversion.  On line 83, all the coordinates of the rectangle are known, and the function returns a nested tuple defining the rectangular position of the
+.CW ".im"
+component of the Toplevel.  This tuple is automatically promoted to the
+.CW "Rect"
+type by the return statement.
+.LP
+Back in function
+.CW "view" ,
+line 58 uses a function from the higher-level
+.CW "String"
+module to strip off the basename of the file name, for use in the banner of the window.  Note that one component of the tuple is nil; the value of this component is discarded.
+Line 58 calls the window manager function
+.CW "wmlib->titlebar"
+to establish a title bar on the window
+The arguments are
+.CW "ctxt.screen" ,
+a data structure representing the window stack on the frame buffer,
+a string specifying the size and properties of the new window, the window's
+label, and the set of control buttons required.
+The
+.CW "+"
+operator on strings performs concatenation.
+The window is labelled \f5"View"\fP
+and the file basename, with a control button to hide the window.
+Titlebars always include a control button to dismiss the window.
+(The size and properties argument is more commonly nil or the empty string,
+leaving the choice of position and style to the window manager.)
+The first value
+in the tuple returned by
+.CW "wmlib->titlebar"
+is a reference to a `top-level' widget\-a window\-upon which the program will assemble its display.
+.SH
+Communications
+.LP
+The second value in the tuple
+returned from
+.CW "wmlib->titlebar"
+is a built-in Limbo type called a channel
+.CW "chan" "" (
+is the keyword).  A channel is a communications mechanism in the manner of Hoare's CSP[15].  Two processes that wish to communicate do so using a shared channel; data sent on the channel by one process may be received by another process.  The communication is
+.I "synchronous" :
+both processes must be ready to communicate before the data changes hands, and if one is not ready the other blocks until it is.  Channels are a feature of the Limbo language: they have a declared type
+.CW "chan" "" (
+.CW "of"
+.CW "int" ,
+.CW "chan"
+.CW "of"
+.CW "list"
+.CW "of"
+.CW "string" ,
+etc.) and only data of the correct type may be sent.  There is no restriction on what may be sent; one may even send a channel on a channel.  Channels therefore serve both to communicate and to synchronize.
+.LP
+Channels are used throughout Inferno to provide interfaces to system functions.  The threading and communications primitives in Limbo are not designed to implement efficient multicomputer algorithms, but rather to provide an elegant way to build active interfaces to devices and other programs.
+.LP
+One example is the
+.CW "menubut"
+channel returned by
+.CW "wmlib->titlebar" ,
+a channel of textual commands sent by the window manager.  The expression on line 69,
+.P1
+menu := <-menubut
+.P2
+receives the next message on the channel and assigns it to the variable menu.  The communications operator,
+.CW "<-" ,
+receives a datum when prefixed to channel and transmits a datum when combined with an assignment operator (e.g.
+.CW "channel<-=2" ).  
+This use of menubut appears inside an
+.CW "alt"
+(alternation) statement, a construct we'll discuss later.
+.LP
+Lines 60 and 61 create and register a new channel,
+.CW "event" ,
+to be used by the Tk module to report user interface events.  Lines 62-66 use simple Tk operations to make the window in which the image may be drawn.  Lines 63 and 64 bind events within this window to messages to be sent on the channel
+.CW "event" .
+For example, line 63 defines that when the configuration of the window is changed, presumably by actions of the window manager, the string
+\f5"resize"\fP
+is to be transmitted on
+.CW "event"
+for interpretation by the application.  This translation of events into messages on explicit channels is fundamental to the Limbo style of programming.
+.SH
+Displaying the image
+.LP
+The payoff occurs on line 67, which steps outside the Tk model to draw the image
+.CW "im"
+directly on the window:
+.P1
+t.image.draw(posn(t), im, ctxt.display.ones, im.r.min);
+.P2
+.CW "Posn"
+calculates where on the screen the image is to go.  The
+.CW "draw"
+method is the fundamental graphics operation in Inferno, whose design is outside our scope here.  In this statement, it just copies the pixels from
+.CW "im"
+to the window's own image,
+.CW "t.image" ;
+the argument
+.CW "ctxt.display.ones"
+is a mask that selects every pixel.
+.SH
+Multi-way communications
+.LP
+Once the image is on the screen,
+.CW "view"
+waits for any changes in the status of the window.  Two things may happen: either the buttons on the title bar may be used, in which case a message will appear on
+.CW "menubut" ,
+or a configuration or mapping operation will apply to the window, in which case a message will appear on
+.CW "event" .
+.LP
+The Limbo
+.CW "alt"
+statement provides control when more than one communication may proceed.  Analogous to a
+.CW "case"
+statement, the
+.CW "alt"
+evaluates a set of expressions and executes the statements associated with the correct expression.   Unlike a
+.CW "case" ,
+though, the expressions in an
+.CW "alt"
+must each be a communication, and the
+.CW "alt"
+will execute the statements associated with the communication that can first proceed.  If none can proceed, the
+.CW "alt"
+waits until one can; if more than one can proceed, it chooses one randomly.
+.LP
+Thus the loop on lines 68-75 processes messages received by the two classes of actions.  When the window is moved or resized, line 73 will receive a \f5"resize"\fP
+message due to the bindings on lines 63 and 64.  The message is discarded but the action of receiving it triggers the repainting of the newly placed window on line 74.  Similarly, messages triggered by buttons on the title bar send a message on
+.CW "menubut" ,
+and the value of that is examined to see if it is
+\f5"exit"\fP,
+which should be handled locally, or anything else, which can be passed on to the underlying library.
+.SH
+Cleanup
+.LP
+If the exit button is pushed, line 71 will return from
+.CW "view" .
+Since
+.CW "view"
+was the top-level function in this process, the process will exit, freeing all its resources.  All memory, open file descriptors, windows, and other resources held by the process will be garbage collected when the return executes.
+.LP
+The Limbo garbage collector [16] uses a hybrid scheme that combines reference counting to reclaim memory the instant its last reference disappears with a real-time sweeping algorithm that runs as an idle-time process to reclaim unreferenced circular structures.
+The instant-free property means that system resources like file descriptors and windows can be tied to the collector for recovery as soon as they become unused; there is no pause until a sweeper discovers it.
+This property allows Inferno to run in smaller memory arenas than are required for efficient mark-and-sweep algorithms, as well as providing an extra level of programmer convenience.
+.SH
+Summary
+.LP
+Inferno supplies a rich environment for constructing distributed applications that are portable\-in fact identical\-even when running on widely divergent underlying hardware.  Its unique advantage over other solutions is that it encompasses not only a virtual machine, but also a complete virtual operating system including network facilities.
+.SH
+Acknowledgment
+.LP
+The cryptographic elements of Inferno owe much
+to the cryptographic library of Lacy et al. [22].
+.SH
+References
+.LP
+.nr PS -1
+.nr VS -1
+.IP 1.
+R. Pike, D. Presotto, S. Dorward, B. Flandrena, K. Thompson, H. Trickey, and P. Winterbottom. ``Plan 9 from Bell Labs'', 
+.I "J. Computing Systems" 
+8:3, Summer 1995, pp. 221-254.
+.IP 2.
+S. Dorward, R. Pike, and P. Winterbottom.  ``Programming in Limbo'', 
+.I "IEEE Compcon 97 Proceedings" ,
+1997.
+.IP 3.
+J. K. Ousterhout. 
+.I "Tcl and the Tk Toolkit" ,
+Addison-Wesley, 1994.
+.IP 4.
+T. Elgamal, ``A Public-Key Cryptosystem and a Signature Scheme Based on Discrete Logarithms'', 
+.I "Advances in Cryptography: Proceedings of CRYPTO 84, " 
+Springer Verlag, 1985, pp. 10-18
+.IP 5.
+B. Schneier,  ``Applied Cryptography'',  Wiley, 1996, p. 516
+.IP 6.
+D. Stinson, ``Cryptography, Theory and Practice'', 
+.I "CRC Press" ,
+1996, p. 271
+.IP 7.
+K. Hickman and T. Elgamal, ``The SSL Protocol (V3.0)'',
+.I "IETF Internet-draft" 
+.IP 8.
+S. M. Bellovin and M. Merritt, ``Encrypted Key Exchange: Password-Based Protocols  Secure Against Dictionary Attack'', Proceedings of the 1992 IEEE Computer Society Conference on Research in Security and Privacy, 1992, pp. 72-84
+.IP 9.
+M. Blaze, J. Feigenbaum, J. Lacy, ``Decentralized Trust Management'', 
+.I "Proceedings 1996 IEEE Symposium on Security and Privacy" ,
+May 1996
+.IP 10.
+R. Rivest and B. Lampson, ``SDSI - A Simple Distributed Security Architecture'', unpublished, 
+.I "http://theory.lcs.mit.edu/~rivest/sdsi10.ps" 
+.IP 11.
+.I "American National Standard for Information Systems  Programming Language C" ,
+American National Standards Institute, X3.159-1989.
+.IP 12.
+.I "GIF Graphics Interchange Format: A standard defining a mechanism for the storage and transmission of bitmap-based graphics information" ,
+CompuServe Incorporated, Columbus, OH, 1987.
+.IP 13.
+.I "GIF Graphics Interchange Format: Version 89a" ,
+CompuServe Incorporated, Columbus, OH, 1990.
+.IP 14.
+S. Dorward et al., ``Inferno'', 
+.I "IEEE Compcon 97 Proceedings" ,
+1997.
+.IP 15.
+C. A. R. Hoare, ``Communicating Sequential Processes''.  
+.I "Comm. ACM" 
+21:8,  pp. 666-677, 1978.
+.IP 16.
+L. Huelsbergen, and P. Winterbottom, ``Very Concurrent Mark & Sweep Garbage Collection without Fine-Grain Synchronization'', Submitted 
+.I "International Conference of Functional Programming" ,
+Amsterdam, 1997.
+.IP 17.
+K. Jensen, and N. Wirth,  
+.I "PascalUser Manual and Report" .
+Springer-Verlag, 1974.
+.IP 18.
+John K. Ousterhout, 
+.I "Tcl and the Tk Toolkit" ,
+Addison-Wesley, 1994.
+.IP 19.
+W. B. Pennebaker. and J. L. Mitchell, 
+.I "JPEG Still Image Data Compression" ,
+Van Nostrand Reinhold, New York, 1992.
+.IP 20.
+R. W. Scheifler, J. Gettys, and R. Newman, 
+.I "X Window System" ,
+Digital Press, 1988.
+.IP 21.
+The Unicode Consortium,
+.I "The Unicode Standard, Version 2.0, " 
+Addison Wesley, 1996.
+.IP 22.
+J. B. Lacy, D. P. Mitchell, and W. M. Schell, ``CryptoLib: Cryptography in Software,'' 
+.I "UNIX Security Symposium IV Proceedings" ,
+USENIX Association, 1993 pp. 1-17.
+.nr PS +1
+.nr VS +1
binary files /dev/null b/doc/bltj.pdf differ
--- /dev/null
+++ b/doc/changes.ms
@@ -1,0 +1,2053 @@
+.\"<-xtx-*> tbl changes.ms | troff -ms | lp -d stdout
+.FP palatino
+.ps 9
+.nr PS 9
+.vs 11
+.nr VS 11
+.nr dP 1
+.nr dV 1p
+.nr dT 4m
+.nr XT 4
+.TL
+System and Interface Changes to Inferno
+.AU
+C H Forsyth
+.br
+Vita Nuova
+.br
+forsyth@vitanuova.com
+.br
+9 June 2003
+.SH
+Overview
+.LP
+This paper describes some of the changes made to Inferno
+interfaces as they stood in the published Third Edition manuals,
+to form the current Fourth Edition of the system,
+and the broad effects on internal and external interfaces.
+Changes include: extensions to the Limbo language;
+new instructions in Dis and the virtual machine; extra content
+in Dis object files; structure of the source tree; configuration of
+.CW emu ;
+replacement of the window system with changes to the client interface;
+commands renamed, replaced, and removed;
+revised support for network booting;
+9P2000 becomes the basis for Styx;
+a graphics model offering alpha-blended compositing and general pixel structure;
+and improvements to Tk.
+.NH 1
+Limbo
+.LP
+Exceptions and fixed point have been added to the Limbo language.
+They are described in more detail in separate notes by John Firth,
+shortly to be available on the Vita Nuova web site
+.CW www.vitanuova.com .
+Channels can now be buffered.
+A form of polymorphism is now available in Limbo.
+.NH 2
+Exceptions
+.LP
+Discussion of exceptions will be restricted here to implications for existing source code.
+The most obvious changes are that
+.CW Sys->rescue ,
+.CW Sys->rescued ,
+.CW Sys->unrescue
+and
+.CW Sys->raise
+have vanished.
+Instead the exception handling is expressed using constructions in the Limbo language.
+Named exceptions can be declared and used (these are described in the note by Firth), and
+they are declared as part of the type of functions that raise them.
+There is also a general `failure' exception that effectively subsumes the old
+.CW Sys->rescue
+scheme, including run-time errors such as `out of memory' that can happen in almost any function.
+Unlike named exceptions a `failure' exception can be raised or caught by any function,
+and its value is a string.
+The
+.CW raise
+statement raises an exception.
+This is most obvious in commands that wish to produce an `exit status'.
+Instead of
+.P1
+sys->raise("fail:usage");
+.P2
+one must now write
+.P1
+raise "fail:usage";
+.P2
+(That is one of the more common source changes required to Third Edition Limbo commands,
+since that was the most common use of exceptions before.)
+A block can have an
+.CW exception
+handler:
+.P1
+{
+	a := array[128] of byte;
+	dosomething(a);
+} exception e {
+"out of memory:*" =>
+	sys->print("i need more space: %s\en", e);
+"fail:*" =>
+	sys->print("exit status: %s\en", e);
+"*" =>
+	sys->print("unexpected error: %s\en", e);
+	raise;	# propagate it
+}
+.P2
+If an exception is raised during the execution of the block (including functions it calls),
+execution of the block is abandoned, and control transfers to the appropriate exception handler
+(which is outside the block).
+Because the compiler and run-time system know the scope of the exception,
+values such as
+.CW a
+above are correctly reclaimed on exit from the faulty block.
+Unhandled failures are propagated to callers; unhandled named exceptions (currently) become failures.
+.LP
+A process group can cause unhandled exceptions in any process in the group either to
+propagate to all members of the group, or to be propagated to the process group leader
+after destroying the other processes in the group.
+This makes it easier to program recovery from exceptions within a group of concurrent processes.
+For instance, if a process is expected to send to another on a channel, but fails unexpectedly instead
+(eg, because memory was exhausted),
+instead of leaving the intended recipient blocked on a receive operation, it can be sent
+an exception to notify it of the failure of the other process, allowing it to take appropriate recovery action.
+(This could sometimes be programmed using the
+.CW wait
+file of
+.I prog (3),
+but not always.)
+.LP
+Exception handling is intended for recovering from disaster.
+We still think it is better Limbo style
+to use tuples, channels and processes to make ordinary error handling explicit.
+The few attempts to use failure exceptions to achieve `pretty' but peculiar control flow have had exactly the usual
+effect of making the code hard to follow and error-prone.
+.NH 2
+Channels
+.LP
+Buffered channels have been added:
+.P1
+c := chan [N] of int;
+.P2
+where
+.I N
+is an integer value,
+creates a channel that will allow up to
+.I N
+integer values to be sent to it without an intervening receive without blocking the sender.
+If
+.I N
+is zero, the channel is unbuffered, equivalent to plain
+.CW "chan of int" ,
+and synchronises sender and receiver as before.
+.LP
+The restriction that a given channel value could not be sent to or received from in two
+.CW alt
+statements simultaneously has been removed.
+.NH 2
+Polymorphism
+.LP
+John Firth has implemented a form of parametric polymorphism in Limbo.
+It too will be described in a separate note.
+Currently we are still fussing over aspects of the constraint syntax
+and some other implications of the most general form, and since some aspects are
+therefore subject to change, including syntax, we have not yet published the details.
+We think it is possible to use the following subset without having to change the code later:
+.IP 1.
+Function declarations can be parametrised by one or more type variables:
+For example:
+.RS
+.P1
+reverse[T](l: list of T): list of T
+{
+	rl: list of T;
+	for(; l != nil; l = tl l)
+		rl = hd l :: rl;
+	return rl;
+}
+.P2
+Such a function can then be invoked on any compatible set of values.
+The function invocation does not specify the type (the compiler does type unification on the parameters).
+Thus the above can be used as:
+.P1
+l1: list of string;
+l2: list of ref Item;
+l3: list of list of string;
+l1 = reverse(l1);
+l2 = reverse(l2);
+l3 = reverse(l3);
+.P2
+.RE
+.IP 2.
+ADTs can also be parametrised:
+.P1
+Tree: adt[T] {
+	v: T;
+	l, r: cyclic ref Tree[T];
+};
+.P2
+allowing declaration of
+.CW "Tree[ref Item]"
+and
+.CW "Tree[string]"
+for instance.
+.IP 3.
+Values of the parametrised type can only be declared, assigned, passed as parameters, returned,
+or sent down channels.
+The only types that can be used as actual parameter types are reference types (ie,
+.CW ref " ADT,"
+.CW array ,
+.CW chan ,
+.CW list
+and
+.CW module ),
+and
+.CW string
+(which is a value type but is implemented using a reference).
+At some point we shall allow a function such as
+.CW reverse
+above to be invoked with any compatible type (not just reference types) but
+that requires changes to Dis and the virtual machine not yet made.
+.LP
+The formal type parameters can be further constrained by listing a set
+of operations that they must have (which currently implies the actual parameters
+must be ADT types with compatible operations).
+We are not completely happy with the current constraint syntax, and some other
+aspects of the scheme, and so that
+be described here later once we have settled it.
+.NH 1
+Dis and virtual machine
+.LP
+To make the Limbo changes and extensions some new operators were added to
+the virtual machine.
+(We also added a
+.CW casel
+operator to allow
+.CW case
+statements to work on
+.CW big
+values.)
+Modules that have exception handlers also have a (new) exception table,
+added to the Dis object format.
+Furthermore, we moved the import table used by the
+.CW load
+operator out of the Dis data space into the object format
+(which also makes it available for inspection by
+.CW wm/rt
+amongst others).
+.LP
+There is now an internal interface to set conditions under
+which modules must be signed to be loaded, and to check a signature on a module.
+Appropriate stubs are defined when module signing is not configured; if
+.I sign (3)
+is configured, however, it replaces them by ones that enforce its signing policy.
+.NH 1
+Window manager
+.LP
+The window manager
+.I wm (1)
+has been reimplemented by Roger Peppe.
+It now multiplexes pointer and keyboard input to applications,
+and manages windows on the display.
+.I Tk (2)
+no longer manages windows from inside the kernel.
+In some ways the structure is closer to that of
+.I mux (1)
+and more specifically the design described in Rob Pike's paper ``A Concurrent Window System''.
+It is possible to import and export window system environments between hosts.
+.LP
+This is one of the bigger causes of source file changes, although many of them
+can be done by global substitutions (eg, using
+.I acme (1)).
+Appendix A gives details.
+.CW Wmlib
+is no longer the application's interface to the window system.
+Instead that is done through a new
+.CW Tkclient
+module; see
+.I tkclient (2).
+(It uses a different
+.CW Wmlib
+as an auxiliary module,
+and also uses a new
+.CW Titlebar
+module to allow the look of the window decoration to be changed more easily).
+An application acquires a window by a call to
+.CW Tkclient->toplevel ;
+starts pointer or keyboard input if desired by calling
+.CW Tkclient->startinput ;
+and puts the window on screen (after sending it Tk configuration commands)
+using
+.CW Tkclient->onscreen .
+Nothing appears on screen until that is called (which amongst other things avoids the resizing on start up that afflicted
+the original scheme).
+.CW Onscreen
+gives it a connection to the window manager for pointer, keyboard and control input,
+with a separate channel for each.
+When it receives data from any of the channels
+(typically using
+.CW alt )
+it must pass it to Tk using calls to appropriate
+.CW Tkclient
+functions.
+.LP
+The toolbar used by the old
+.I wm
+is now provided by a separate program
+.CW wm/toolbar
+(see
+.I toolbar (1)),
+and it is
+.CW toolbar
+that interprets the
+.CW /lib/wmsetup
+file.
+.CW Wm
+invokes
+.CW wm/toolbar
+by default so most users will see no difference, but it does make it easier to develop alternative interfaces.
+More visible is that
+.CW wm/logon
+is now a
+.I client
+of the window manager, and must be invoked as follows:
+.P1
+wm/wm wm/logon
+.P2
+.LP
+Applications need not even use
+.I tk (2).
+There is an interface for
+.CW draw -only
+clients,
+.I wmclient (2).
+.NH 1
+Inferno source tree
+.LP
+The structure of the Inferno source tree has changed in the following ways.
+.NH 2
+Library source
+.LP
+The
+.CW image
+and
+.CW memimage
+directories have gone, replaced by
+.CW libdraw
+and
+.CW libmemdraw .
+The directories in the Inferno root that contain the source for libraries
+now
+always have names starting `\f5lib\f1':
+.CW libcrypt ,
+.CW libinterp ,
+.CW libkeyring ,
+.CW libmath ,
+etc.
+.NH 2
+Emu source
+.LP
+The
+.CW emu
+directory now contains a subdirectory structure similar to the
+.CW os
+kernels, and uses a similar configuration file (parts list) to say what goes in
+a given instance of
+.CW emu .
+This allows platform-dependent selection of drivers, libraries and even
+.CW #/
+(ie,
+.I root (3))
+contents to be done easily.
+.LP
+The top directory,
+.CW /emu ,
+contains:
+.CW mkfile
+that simply moves to the platform configured by
+.CW /mkconfig ,
+allowing builds in the Inferno root as before;
+a subdirectory
+.CW port
+containing portable code (including some code shared by several platforms, such as
+.CW devfs-posix.c );
+and a subdirectory for each hosting platform, distinguished by an upper-case initial letter.
+Current platforms include
+.CW FreeBSD ,
+.CW Irix ,
+.CW Linux ,
+.CW Nt
+(for all Windows platforms after 95),
+.CW Plan9 ,
+.CW Solaris ,
+and several others.
+.NH 2
+Emu configuration
+.LP
+Each platform-specific directory contains a configuration file with the
+same structure and indeed similar contents to the ones used for the native kernel.
+The default configuration file is called
+.CW emu .
+Another can be chosen, again in a similar way to the native kernel, by using
+.P1
+mk 'CONF=\fIcfile\fP'
+.P2
+where
+.I cfile
+is the name of the configuration file.
+The name of the resulting executable file contains the configuration file name but depends on the platform:
+it is \fIcfile\fP\f5.exe\fP on Windows, \f5o.\fP\fIcfile\fP on Unix systems, and \f58.\fP\fIcfile\fP on 386 Plan 9 systems.
+The configuration file format and contents is documented for all types of kernels by
+.I conf (10.6).
+.NH 2
+Tk source
+.LP
+The Tk implementation in
+.CW libtk
+has been made more modular.
+It allows a significantly different `style' to be implemented,
+and although that is by no means trivial to do, there is at least an interface to do it.
+We hope to change various aspects of the standard style further, but that has not yet been done.
+.NH 1
+Commands and modules
+.LP
+There are new commands and library modules, others have become obsolete and been removed,
+and a few existing ones have been given new names (typically when ones with similar function have been
+collected together).
+The biggest change has been to
+.I wm (1),
+which retains the same name but slightly different invocation and completely different
+implementation,
+as discussed above.
+Here I shall simply note the bigger changes, rather than discuss new functionality.
+.NH 2
+Renamed commands
+.LP
+As part of a mild reorganisation of the
+.CW /appl
+and
+.CW /dis
+trees, we have moved commands out of
+.CW /dis/lib
+so that it now contains only library modules except for a few commands left
+there temporarily for compatibility.
+Commands themselves have sometimes been shuffled to subdirectories,
+often copying seemingly better structure from Plan 9,
+so that authentication commands are
+.CW auth/ ...,
+naming service commands are
+.CW ndb/ ...,
+and
+IP-specific commands are
+.CW ip/ "... ."
+.LP
+One noticeable change is that
+.CW lib/cs
+is now
+.CW ndb/cs .
+More dramatically, the command
+.CW lib/srv
+(ie,
+.I srv (8))
+has been replaced by
+.I sh (1)
+scripts, all described by
+.I svc (8),
+that contain appropriate calls to
+.I listen (1)
+after setting up any locally-desired environment.
+.LP
+Other commands have also moved:
+.IP •
+.CW lib/plumber
+is now simply
+.CW plumber
+.IP •
+.CW lib/bootp
+and
+.CW lib/tfptd
+have become
+.CW ip/bootpd
+and
+.CW ip/tftpd ,
+documented in
+.I bootpd (8)
+.IP •
+.CW lib/virgild
+has become
+.CW ip/virgild
+(see
+.I virgild (8))
+.IP •
+.CW lib/chatsrv ,
+.CW lib/rdbgsrv
+and
+.CW cpuslave
+have moved to
+.CW auxi
+(ie,
+.CW /dis/auxi
+and
+.CW /appl/cmd/auxi)
+.IP •
+.CW csquery
+has become
+.CW ndb/csquery
+.NH 2
+New or newly-documented commands
+.IP •
+an authentication server (signer) can use
+.I keyfs (4)
+to store its keys securely in the encrypted file
+.CW /keydb/keys
+(instead of the unencrypted
+.CW /keydb/password ),
+and run
+.I keysrv (4)
+to offer secure change of password remotely.
+They are typically started, with other signing services, by
+.CW svc/auth
+described in
+.I svc (8).
+.IP •
+.CW /dis/auth
+and
+.CW /appl/cmd/auth
+contain commands related to authentication;
+they rely on
+.I keyfs (4)
+in most cases.
+The older ones that use
+.CW /keydb/passwd
+are still in
+.CW /dis/lib
+and
+.CW /appl/lib
+during the transition
+.IP •
+.I dns (8)
+has replaced the
+.CW lib/ipsrv
+implementation of
+.I srv (2);
+when used, it must be started before
+.CW ndb/cs .
+.I Srv (2)
+has reverted to being a hosted-only interface to the hosting system's native
+DNS resolver.
+It is automatically used by
+.I cs (8)
+if it cannot find
+.I dns (8),
+and
+.I dns (8)
+will also use it if available before consulting the DNS network.
+.IP •
+.I chgrp (1),
+.I cpuview (1),
+.I grid (1),
+.I 9660srv (4),
+.I cpuslave (4),
+.I dossrv (4),
+.I keyfs (4),
+.I keysrv (4),
+.I nsslave (4),
+.I palmsrv (4),
+.I registry (4),
+.I rioimport ,
+.I styxchat (1),
+.I styxlisten ,
+.I wmexport ,
+.I wmimport ,
+and
+.I uniq (1)
+are new
+.IP •
+the multiplayer games software previously in
+.CW /appl/games
+has been replaced by a related but significantly different system in
+.CW /appl/spree .
+(Also see
+.I spree (2)
+for supporting modules.)
+.IP •
+.I Registry (4)
+provides dynamic registration and location of services using sets of attributes/value pairs,
+through a name space.
+.I Registries (2)
+provides a convenient Limbo interface for registration and query.
+.NH 2
+Commands removed
+.IP •
+.CW lib/csget
+(see
+.I cs (8)
+for its replacement
+.CW csquery )
+.IP •
+the undocumented and obsolete commands
+.CW lib/isrv
+and
+.CW lib/istyxd
+have been removed, since either the
+.CW none
+authentication protocol, or the
+.CW -A
+option to
+.CW mount
+can be used if no authentication is needed
+.IP •
+.CW lib/srv
+has been replaced by
+.I svc (8)
+as mentioned above.
+.IP •
+.CW getenv
+and
+.CW setenv
+have been removed since the Shell provides alternatives
+.IP •
+.CW wm/license
+is no longer needed
+.NH 2
+New modules
+.LP
+There are library modules to support: registries and configuration files of attribute/value pairs;
+Internet address parsing and manipulation; management of windows and subwindows (used by
+.I wm (1)
+itself); timers; Styx; Styx servers; exception handling; memory
+and performance profiling; Freetype interface; parsing Palm databases; and navigating XML files (without reading them all into memory) and interpreting style sheets.
+.NH 1
+Styx
+.LP
+Styx was derived from the 9P protocol used by Plan 9 in 1995, with changes that reflected the requirements
+of the Inferno project of the time, mainly by removing features that were thought too closely tied to the Plan 9
+environment.
+Some 9P messages were removed, particularly those
+that incorporated details of the Plan 9 authentication methods;
+Styx moved authentication outside the file service protocol.
+Other changes eliminated file locking and append-only files.
+Some restrictions that 9P imposed were retained, however, such as limiting file names to 27 bytes.
+This last restriction is fine for synthetic network services, but
+has been troublesome when trying to access Unix and Windows systems, amongst others.
+.LP
+A recent revision of 9P adds support for much longer file names
+and takes the opportunity to improve other aspects of the protocol.
+It also removes details of authentication algorithms from the protocol.
+The Styx implementation now uses the new version of 9P as the default file service protocol.
+(It is possible that for interoperation with older Inferno systems the system will be able to
+interact with both old and new versions of Styx.)
+.NH 2
+Protocol changes
+.LP
+The messages
+.CW Tauth
+and
+.CW Tversion
+are new to Styx.
+.CW Tversion
+includes negotiation (at connection start) of the message size and protocol version;
+it also introduces a new session.
+.CW Tauth
+obtains access to a special authentication file if the server requires
+authentication within a Styx session.
+.CW Tclone
+has been replaced by a more elaborate form of
+.CW Twalk
+that allows zero to MAXWELEM (16) elements to be walked, perhaps to a new fid, in a single message,
+returning a sequence of qid values in
+.CW Rwalk .
+(A clone is simply a walk of a fid to a new fid with zero elements.)
+A walk of several elements can return partial results if the walk of the first element succeeds but
+subsequent ones fail.
+A partial walk leaves the state of the fids unchanged.
+.CW Ropen
+and
+.CW Rcreate
+return a suggested size for atomic I/O on the fid (0 means `not given').
+All strings are variable length, and consequently
+.CW Twstat
+and
+.CW Rstat
+data is variable length and formatted differently.
+Data returned from
+.CW Tread
+of a directory is similarly changed, because
+directory entries are not fixed length.
+.CW Tnop
+has gone.
+.LP
+Tags remain 16-bit integers, but fids and counts
+become 32-bit integers (mainly of interest to large systems),
+and qids have a different structure.
+Previously a qid was a pair of 32-bit integers, path and vers, where
+path had the top bit set for a directory.
+Now a qid is a triple: a 64-bit path, 32-bit vers, and 8-bit type.
+The type is defined to be the top 8 bits of the file's mode.
+The path does not have the top bit set for a directory, and indeed the
+path value is not interpreted by the protocol.
+There are now bits in the file mode for append-only and exclusive-use
+files (new for Inferno), and for authentication files (new for both Plan 9 and Inferno).
+The stat information includes the user name that last caused the file's mtime to be changed.
+All strings in the protocol are variable length: file names, attach names, user names, and error text.
+.LP
+The message format on the wire is significantly different.
+The message size is negotiated for a connection by
+.CW Tversion ,
+and messages can be large, allowing much more data to be sent in single
+.CW Twrite
+and
+.CW Rread
+messages.
+The header includes a 32-bit message size, making it easy to find message boundaries without
+parsing the contents.
+Strings are
+represented as a 16-bit size followed by the string's UTF-8 encoding (without zero byte).
+R-messages do not carry a copy of the fid from the T-message.
+Padding bytes have gone.
+The order of some fields has changed of course to match message parameter changes.
+.LP
+Authentication of the connection itself, and optionally
+establishing the keys for digesting and encryption,
+is done before the protocol starts, in both Inferno and Plan 9.
+Details will follow on the protocol for that, and Limbo interfaces.
+For now, it can be assumed that the old authentication messages can still be used,
+even after a more flexible protocol has been implemented.
+.CW Tauth
+can be used to authenticate particular accesses within such a session, but
+implies trust by the server that the client system will not cheat its users.
+(That trust is typically established by the connection level authentication which is needed
+anyway for link encryption, and thus for single-user clients further authentication
+seems extraneous in most cases.)
+Most Inferno services that run as file servers within a system (eg,
+.CW 9660srv )
+will, like Plan 9's, reply to
+.CW Tauth
+with an
+.CW Rerror
+stating ``authentication not required''.
+Access to them when exported is typically controlled as now by verifying the incoming connection.
+.NH 2
+Limbo interface changes
+.LP
+Because Limbo's interface to file service via
+.CW Sys
+and other modules uses Limbo
+.CW string
+for names, and that is inherently
+variable length, there are no interface changes required for that aspect of the protocol change,
+and consequently no source changes
+(in contrast to the introduction of 9P2000 in C implementations).
+Similarly the Inferno directory reading interfaces remain unchanged.
+.LP
+The `directory mode' bit previously called
+.CW CHDIR
+is now called
+.CW DMDIR .
+It is used
+.I only
+in
+.CW Dir.mode .
+.CW CHDIR
+is no longer defined, partly because it was used both
+in
+.CW Dir.mode
+and
+.CW Qid.path ,
+and the latter instances must change (discussed below).
+There are bits (new to Inferno) for
+.CW DMAPPEND
+(append-only file),
+.CW DMEXCL
+(exclusive-use file),
+and
+.CW DMAUTH
+(authentication file).
+The protocol can return the user name of the user that caused
+.CW mtime
+to be changed on a file; that is now available as
+.CW Dir.muid .
+.LP
+The structure of
+.CW Qid
+has changed.
+Previously a Qid had a 32-bit
+.CW path
+and a 32-bit version number,
+.CW vers .
+The top bit
+.CW CHDIR ) (
+of
+.CW path
+was set iff the Qid was that of a directory.
+The
+.CW path
+is now 64 bits (which is
+.CW big
+in Limbo and
+.CW vlong
+in the kernel), and there is no longer the convention that the top bit of
+.CW path
+must be 1 for a directory.
+Instead, there is a new, separate
+.CW type
+field (called
+.CW qtype
+in Limbo)
+that has the value of the top 8 bits of the file's mode.
+Each bit \f5DM\fIx\f1 in
+.CW Dir.mode ,
+has got a corresponding bit \f5QT\fIx\f1
+in
+.CW Qid.qtype :
+.CW QTDIR ,
+.CW QTAPPEND ,
+.CW QTEXCL
+and
+.CW QTAUTH .
+The bit
+.CW QTDIR
+.I must
+be set in the
+.CW Qid.qtype
+for a directory, and only then.
+There is an extra constant
+.CW QTFILE
+that is defined to be zero, and is used for clarity when neither
+.CW QTDIR
+nor
+.CW QTAUTH
+is set.
+.LP
+In Styx file servers, changes are required to reflect the slightly different set of message types
+and a few new parameters, but the main changes are:
+handling zero or more name elements at once in
+.CW Twalk
+and
+.CW Rwalk ;
+changing
+.CW CHDIR
+to
+.CW DMDIR
+in
+.CW Dir.mode
+(easy);
+the use of the new
+.CW Qid.qtype
+field
+and
+.CW QTDIR
+instead of
+.CW CHDIR
+in
+.CW Qid.path
+(a little more effort);
+and (typically) the insertion of casts to force
+.CW Qid.path
+to
+.CW int
+and thus ensure the use of 32-bit operations except where 64-bit paths really are needed
+(hardly ever in synthetic file servers).
+The new modules for use by file servers are discussed in the next section.
+.LP
+The revised definition of
+.CW Twstat
+in
+.I stat (5),
+and thus
+.CW sys->wstat ,
+provides for ``don't care'' values in
+.CW Dir
+that are tedious to provide directly; a new adt value
+.CW Sys->nulldir
+provides the right initial value for a
+.CW Dir
+which is then changed as needed for
+.CW wstat .
+.SH
+.I "Examples"
+.LP
+Create a directory:
+.P1
+	\fIold:\f5
+fd := sys->create(name, Sys->OREAD, Sys->CHDIR | 8r777);
+
+	\fInew:\f5
+fd := sys->create(name, Sys->OREAD, Sys->DMDIR | 8r777); # not CHDIR
+.P2
+.LP
+Make Qids
+for a file and a directory:
+.P1
+	\fIold:\f5
+Qdir, Qdata: con iota;
+qd := Sys->Qid(Sys->CHDIR | Qdir, 0);
+qf := Sys->Qid(Qdata, 0);
+
+	\fInew:\f5
+Qdir, Qdata: con iota;
+qd := Sys->Qid(big Qdir, 0, Sys->QTDIR);
+qf := Sys->Qid(big Qdata, 0, Sys->QTFILE);
+.P2
+.LP
+Test if a file is a directory:
+.P1
+	\fIold:\f5
+isdir(d: Sys->Dir): int
+{
+	return (d.mode & Sys->CHDIR) != 0;
+\fIOR:\f5
+	return (d.qid.path & Sys->CHDIR) != 0;
+}
+
+	\fInew:\f5
+isdir(d: Sys->Dir): int
+{
+	return (d.mode & Sys->DMDIR) != 0;
+\fIOR:\f5
+	return (d.qid.qtype & Sys->QTDIR) != 0;
+}
+.P2
+.LP
+If one wishes to have values
+.CW big
+only when required, one can write:
+.P1
+case int dir.qid.path {
+Qdir =>
+	...
+Qdata =>
+	...
+Qctl =>
+	...
+}
+.P2
+Of course with the Dis change mentioned above,
+.CW case
+can now be applied to
+.CW big
+values, so it is no longer necessary to add the cast (as it once was).
+Even so, 32-bit operations are faster when they suffice.
+.NH 2
+Styx protocol in Limbo: Styx and Styxservers
+.LP
+A new module
+.CW Styx ,
+defined by
+.CW styx.m ,
+provides access to the Styx protocol messages, as variants of pick adts
+.CW Tmsg
+and
+.CW Rmsg .
+(There was an old, undocumented
+.CW Styx
+module but this new interface is completely different.)
+It is used by several file servers, such as
+.CW dossrv ,
+.CW cdfs ,
+and the new
+.CW logfs .
+See the attached manual page.
+There are several implementations with the same signature, covering different
+combinations of old and new Inferno and old and new protocols, through
+the same interface.
+There are slight differences in the application code for old and new
+systems because of the changed
+type and structure of
+.CW Qid .
+The versions that talk the old protocol need to store some internal state,
+and are intended only to meet compatibility requirements during the transition.
+.LP
+Many file service applications, however, serve a simple name space,
+requiring more than can be done with
+.CW file2chan ,
+but wishing some help in handling the protocol details.
+Two new modules
+.CW Styxservers
+and
+.CW Nametree
+are provided to make such applications easier to write.
+They are closely related and thus both modules are defined by
+.CW styxservers.m .
+.LP
+.CW Styxservers
+provides help in handling fids and interpreting the Styx requests for navigating a
+name space, and provides a reasonable set of default actions,
+allowing the application to focus on implementing
+read and write access to the files in the name space.
+It uses
+.CW Styx
+to talk to the Styx client on a connection.
+It interacts with the application through a channel interface and
+the
+.CW Navigator
+adt to navigate an abstract
+representation of the application's name space.
+The module can be used on its own, with the application doing the work
+of replying to those queries itself, or it can get extra help in the common cases from
+.CW Nametree .
+.CW Nametree
+provides a
+.CW Tree
+adt and operations for the application to build an abstract representation of a name space
+and maintain it dynamically quite simply, and it exports the channel interface used by
+.CW Styxservers
+for navigation, thus connecting the two, but leaving the application in complete
+control of the name space contents viewed by Styx.
+See the manual pages
+.I styxservers (2)
+and
+.I styxservers-nametree (2),
+attached.
+The latter includes a short working example of combining the two modules.
+.LP
+The previous release of the system had a module
+.CW Styxlib
+that combined the functions of
+.CW Styx
+and
+.CW Styxservers .
+It remains for a time for transition, but newer applications should use either
+.CW Styx
+or
+.CW Styxservers .
+.LP
+A new command
+.I styxchat (8)
+exchanges Styx messages with a server, reading a textual representation of T-messages
+on standard input.
+It can be helpful when testing a Styx server implementation.
+(It was originally developed to test the
+.CW Styx
+module implementations in several configurations.)
+See the attached manual page for details.
+It also supports an option that allows it to act as a server,
+printing T-messages as they are received from clients, and
+reading R-messages in a textual form from standard input for replies.
+.NH 2
+Device driver changes
+.LP
+Most of the differences for most drivers are relatively minor
+(in
+.CW diff
+terms).
+.LP
+Throughout the hosted and emulated kernels:
+.IP \(bu
+.CW Qid
+now is the structure:
+.RS
+.P1
+struct Qid {
+    vlong   path;
+    ulong   vers;
+    uchar   type;
+};
+.P2
+The
+.CW type
+field has values
+.CW QTDIR ,
+.CW QTFILE ,
+.CW QTAPPEND ,
+etc.
+The test previously written
+.P1
+if(qid.path & CHDIR)
+.P2
+is now written
+.P1
+if(qid.type & QTDIR)
+.P2
+Because of that change, the various
+.CW switch
+statements in the drivers that previously read
+.P1
+switch(c->qid.path){
+.P2
+or
+.P1
+switch(c->qid.path & ~Sys->CHDIR){
+.P2
+now read
+.P1
+switch((ulong)c->qid.path){
+.P2
+to keep operations to 32 bits (except where otherwise required).
+.RE
+.IP \(bu
+The first entry of a driver's
+.CW Dirtab
+.I must
+be an entry for
+\f5"."\fP,
+if the driver uses
+.CW devgen
+to help implement
+.I walk ,
+.I stat ,
+.I devdirread
+or
+.I open
+operations.
+.IP \(bu
+Offsets passed to the driver's
+.I read
+and
+.I write
+entry points are
+64-bit
+.CW vlong ,
+not 32-bit
+.CW ulong .
+.IP \(bu
+The
+.I stat
+entry point has an extra buffer size parameter:
+.RS
+.P1
+int \fIxyz\f5stat(Chan *c, uchar *dp, int n)
+.P2
+It also returns an integer: the size of the result.
+.CW Devstat
+accepts the extra parameter and returns an appropriate result:
+.P1
+static int
+\fIxyz\f5stat(Chan *c, uchar *dp, int n)
+{
+	return devstat(c, dp, n, rtcdir, nelem(\fIxyz\f5dir), devgen);
+}
+.P2
+.RE
+.IP \(bu
+The biggest change is to
+.I walk .
+It has the signature:
+.RS
+.P1
+Walkqid *\fIxyz\f5walk(Chan *c, Chan *nc, char **names, int nname);
+.P2
+and it allows zero or more elements to be walked in a single call,
+returning its result in a newly-allocated
+.CW Walkqid
+structure:
+.P1
+struct Walkqid {
+	Chan*	clone;
+	int	nqid;
+	Qid	qid[1];
+};
+.P2
+Note that the array
+.CW Walkqid.qid
+must actually hold up to
+.I nname
+Qids, and thus is allocated as follows:
+.P1
+wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
+.P2
+The driver must take care that the space is reclaimed if
+.CW error
+is called before its
+.I walk
+function returns, by using
+.CW waserror
+as required.
+Fortunately,
+.CW devwalk
+looks after the details of
+.I walk
+and
+.CW walkqid
+for most drivers:
+.P1
+static Walkqid*	 
+\fIxyz\f5walk(Chan* c, Chan *nc, char** name, int nname)
+{
+	return devwalk(c, nc, name, nname, \fIxyz\f5dir,
+		nelem(\fIxyz\f5dir), devgen);
+}
+.P2
+.RE
+.IP \(bu
+The
+.I clone
+entry point has gone, since cloning is seen by a driver as a particular form of call to its
+.I walk
+entry,
+where the parameter values satisfy:
+.RS
+.P1
+c != nc && nwname == 0
+.P2
+One difference is that a node can be cloned and walked in a single operation,
+in other words
+.CW nwname
+can be non-zero,
+and the incoming
+.CW nc
+is often nil and a new
+.CW Chan
+must be allocated.
+Note that if the driver found it adequate to call
+.CW devclone
+previously, then
+the new
+.CW devwalk
+will
+generally look after it as well.
+.CW Devclone
+remains for use as a utility function for the few drivers that need to
+clone a channel themselves,
+in their
+.I walk
+operations or elsewhere.
+.RE
+.IP \(bu
+The
+.I detach
+entry has been renamed
+.I shutdown
+(it was never the opposite of
+.I attach ).
+The stub
+.CW devshutdown
+can be used by devices that do not need it.
+.LP
+For drivers that serve a simple name space using the functions of
+.CW dev.c
+(described in
+.I devattach (10.2)),
+only a handful of simple changes are required.
+Most are pointed out by the compilers as type clashes.
+The main exception is the need for a
+.CW Dirtab
+to have its first entry be an entry for \f5"."\fP if the
+.CW Dirtab
+will be passed to
+.CW devgen
+via
+.CW devwalk ,
+.CW devstat
+and
+.CW devdirread .
+.NH 1
+Sys module changes
+.LP
+.NH 2
+Sys: name change(s)
+.LP
+The name
+.CW ERRLEN
+has become
+.CW ERRMAX
+(since it is the limit to any error string, not its necessary length).
+.CW NAMELEN
+has been removed,
+to allow each instance to be found (by compilation) and either removed
+(where it was simply limiting the length of a file name), or replaced by
+.CW NAMEMAX
+where it was used as a buffer size to read in names such as
+.CW /dev/sysname
+or
+.CW /dev/user .
+.NH 2
+Sys: file sizes
+.LP
+The Styx protocol has always supported 64-bit file sizes and file offsets.
+The Inferno interface has not.
+.CW Sys
+has changed so that length and offset values become
+.CW big ,
+specifically:
+file size
+.CW Dir.length ,
+the offset parameter to
+.CW seek ,
+and
+.CW seek 's
+result.
+.LP
+These and the Qid changes account for quite a few changes in
+our own source tree.
+Typically, applications did things like this:
+.P1
+	\fIold:\f5
+buf := array[d.length] of byte;
+
+sys->seek(fd, 0, Sys->SEEKSTART);
+off := sys->seek(fd, 0, Sys->SEEKRELA);	rec := off + HDRLEN;
+for(offset := 0; offset < d.length; offset += RECSIZE){
+	sys->seek(fd, offset, Sys->SEEKSTART);
+	...
+}
+.P2
+The compiler now objects in each case because
+.CW big
+values are now appearing where
+.CW int
+is required, or conversely.
+In some cases it is obvious that adding a cast is correct;
+in others it is worth considering whether the calculation should indeed
+be
+.CW big
+because file sizes for instance can in practice exceed the range of a
+signed integer without too much trouble today, especially when the `file'
+is a storage device.
+The case that some people like and some dislike is:
+.P1
+if(sys->seek(fd, big offset, Sys->SEEKSTART) < big 0) ...
+.P2
+where the
+.CW "big 0"
+is needed because
+.CW sys->seek
+is
+.CW big ,
+and there are no `usual arithmetic conversions' as in C.
+(Given the tangle that several languages have made of such conversions, perhaps
+being strict is correct.)
+.NH 2
+Sys: export
+.LP
+.CW Sys->export
+now has the signature:
+.P1
+export:	fn(c: ref Sys->FD, dir: string, flag: int): int;
+.P2
+allowing a directory
+.I dir
+other than \f5"/"\f1
+to be exported.
+It replaces the
+.CW exportdir
+function of (later) Third Edition.
+.NH 2
+Sys: Styx support
+.LP
+The revision of Styx has caused three calls to be added:
+.P1
+fauth:    fn(fd: ref Sys->FD, aname: string): ref Sys->FD;
+fversion: fn(fd: ref Sys->FD, msize: int, version: string): (int, string);
+iounit:   fn(fd: ref Sys->FD): int;
+.P2
+.CW Fversion
+initialises a Styx session on connection
+.I fd ,
+sending the message size
+.I msize
+and protocol version string
+.I version ;
+it returns a tuple giving the message size and version returned by the Styx server.
+It is rarely called directly; the
+.CW mount
+operation does it automatically on an uninitialised connection.
+.LP
+.CW Fauth
+sends a Styx
+.CW Tauth
+message on connection
+.I fd ,
+and if successful, returns a file descriptor that
+refers to an authentication file provided by the file server,
+which may be read and written by
+.CW Sys->read
+and
+.CW Sys->write
+to implement the authentication protocol(s) supported by the server.
+.CW Fauth
+is needed only when the server requires authentication.
+.LP
+.CW Iounit
+returns the `atomic IO unit' suggested for the file
+.I fd
+by its file server when it was opened.
+.NH 2
+Sys: mount
+.LP
+The
+.CW mount
+system call has acquired a second file descriptor parameter:
+.P1
+mount: fn(fd: ref Sys->FD, afd: ref Sys->FD, on: string,
+          flags: int, spec: string): int;
+.P2
+.I Afd
+is nil if the file server is known not to require authentication within a Styx session.
+(The connection might itself have been authenticated previously, for instance,
+and most file servers such as
+.CW dossrv ,
+.CW ftpfs
+and
+.CW dbfs
+are invoked to provide services to an already-authenticated user, and therefore
+do not require authentication within a session.)
+If the server does require authentication,
+.I afd
+refers to a file descriptor returned by a previous
+.CW fauth
+on connection
+.I fd ,
+on which an authentication protocol has subsequently been executed as required by the file server connected to
+.I fd .
+.NH 2
+Sys: other new system calls
+.LP
+There are two more new system calls:
+.P1
+fd2path: fn(fd: ref Sys->FD): string;
+werrstr: fn(s: string): int;
+.P2
+.CW Fd2path
+returns the path name under which the file descriptor
+.I fd
+was originally opened (if known).
+One result is that
+.I workdir (2)
+produces reasonable results for the name of the current directory
+in the presence of mounts and binds.
+.LP
+.CW Werrstr
+sets the per-process system error string to
+.I s ,
+to allow a Limbo function to save and restore an error string over
+other system calls, to present a similar interface
+as the system calls on errors, or to annotate the error from a system call
+for its own caller.
+.NH 2
+Sys: directory reading
+.LP
+The
+.I sys-dirread (2)
+system call's signature has changed:
+.P1
+dirread: fn(fd: ref Sys->FD): (int, array of Sys->Dir);
+.P2
+Previously it accepted an array of
+.CW Dir
+to fill and returned a count;
+now it returns a tuple containing the count and the array of values read.
+The change was needed because the representation of directory entries
+is now variable length, and it is difficult to limit the number returned
+(it is possible, but all the methods have disadvantages).
+.CW Dirread
+still reads a directory incrementally, requesting a block of directory entries
+of reasonable size from the file server, and unpacking them into the returned array.
+Use
+.I readdir (2)
+to read whole directories at once.
+.NH 1
+Bufio
+.LP
+There are several changes to
+.CW Bufio :
+.P1
+Iobuf: adt {
+	...
+	seek:	fn(b: self ref Iobuf, n: big, where: int): big;
+	offset:	fn(b: self ref Iobuf): big;
+};
+# flush: fn();	# deleted
+.P2
+The module-level function
+.CW Bufio->flush
+has been removed
+(\fInot\fP
+.CW Iobuf.flush ),
+to allow concurrent use of a single
+.CW Bufio
+instance; applications must
+.CW close
+or
+.CW flush
+each output file explicitly.
+.LP
+As a result of the change to 64-bit offsets for
+.CW Sys->seek ,
+.CW Iobuf.seek
+also accepts and returns
+.CW big
+offsets.
+.CW Iobuf.offset
+is new, and returns the current file offset in bytes, taking account of any buffering.
+.LP
+.CW Iobuf.flush
+has been extended to flush any data buffered on input files.
+.NH 1
+Draw
+.LP
+The graphics model represented by the
+.I draw (3)
+device and the
+.CW Draw
+module is significantly different, including support for a range of pixel formats,
+and compositing in the drawing operations.
+Most source code that uses Images
+directly will require some changes, but the scope of them is limited: needing only extra
+or different parameter values to individual operations, not radical restructuring.
+The following changes affect most non-Tk graphics application code:
+.IP \(bu
+Pixels in an
+.CW Image
+can now be more than 8 bits and have a more flexible structure
+(eg, several colour channels, and an optional alpha channel, of up to 8 bits each).
+To support that, the old
+.CW ldepth
+field has gone, replaced by a channel descriptor
+.CW chans
+of type
+.CW Chans ,
+which describes the pixel structure, and an integer
+.CW depth
+field, which gives the total pixel size (depth) in bits.
+.IP \(bu
+The colour parameters are now 32-bit RGBA values
+(red, green, blue and alpha components, 8-bit each, and big-endian
+only when an
+.CW int ).
+.IP \(bu
+The graphics subsystem supports Porter-Duff compositing,
+combining a destination image with a source image (within an optional matte)
+according to a compositing operator.
+The interpretation of the old `mask' Image parameter to
+.CW draw
+and
+.CW gendraw
+has changed.
+Previously it provided a simple binary mask;
+it now provides a `matte', and its
+alpha channel shapes the source image and adds partial transparencies.
+If the matte parameter is nil, the source image is used unmodified.
+If it lacks an alpha channel, one is computed from the matte image colour channels.
+The drawing operations
+.CW draw ,
+.CW gendraw ,
+.CW line ,
+.CW text ,
+and so on,
+have all got variants
+.CW drawop ,
+.CW gendrawop ,
+.CW lineop ,
+.CW textop ,
+and so on,
+each taking an extra final parameter that specifies a Porter-Duff
+compositing operator from a set predefined by
+.CW Draw :
+.CW SoverD ,
+.CW SinD ,
+.CW DatopS ,
+and so on.
+In each case,
+.CW S
+refers to the source image (within a matte, if provided), and
+.CW D
+refers to the destination image.
+Most of them are useful only when either or both source or destination images have got
+alpha channels (or a matte is used to shape the source).
+The old function names without the
+.CW op
+suffix use the most common compositing operation
+.CW Draw->SoverD ,
+drawing the source image over the destination,
+taking account of the shaping of the source and destination images by their alpha channels,
+with the source further shaped by the optional matte.
+Thus
+.CW Image.draw
+continues to do the `obvious' thing.
+.IP \(bu
+There are new colour map conversion functions.
+.LP
+The
+.CW Chans
+adt is the following:
+.P1
+Chans: adt
+{
+	# interpret standard channel string
+	mk:    fn(s: string): Chans;
+	# standard printable form
+	text:  fn(c: self Chans): string;
+	# equality
+	eq:    fn(c: self Chans, d: Chans): int;
+	# bits per pixel
+	depth: fn(c: self Chans): int;
+};
+.P2
+Values are created by
+.CW Chans.mk ,
+which accepts a string that is a sequence of channel descriptors,
+each being a letter representing a channel type followed by an integer giving the channel's size (depth, width) in bits.
+The letters include:
+.CW r ,
+.CW g
+and
+.CW b
+for red, green and blue;
+.CW a
+for alpha;
+.CW k
+(!) for greyscale; and
+.CW x
+for padding (``unspecified'', ``don't care'').
+Thus
+.CW Chans.mk("r8g8b8a8")
+produces a descriptor for a 32-bit pixel with 8-bit colour and alpha components.
+The same descriptor is used in the revised
+.I image (6)
+format, although the older image file format with ldepth only is still recognised.
+Given a Chans value
+.I c ,
+\fIc\fP\f5.text()\fP returns such a descriptor for it as a string.
+.LP
+When
+.CW newimage
+previously was called with a specific value for
+.CW ldepth ,
+an appropriate
+.CW Chans
+value must replace it.
+A few common variants are defined as constants of type
+.CW Chans
+in
+.CW Draw .
+(We extended the Limbo compiler last year to support the use of
+.CW con
+with adt and tuple constants with this use in mind.)
+For example, the value
+.CW Draw->CMAP8
+is the descriptor for the 8-bit deep
+.I rgbv
+colour-mapped Image format previously used by Inferno.
+The list of predefined channels includes:
+.TS
+center;
+cfI cfI cfI cfI
+n lf(CW) n lw(3i) .
+Old ldepth	Name	Bit depth	Description
+0	GREY1	1	single 1-bit deep greyscale channel
+1	GREY2	2	single 2-bit deep greyscale
+2	GREY4	4	single 4-bit deep greyscale
+\-	GREY8	8	single 8-bit deep greyscale
+3	CMAP8	8	single 8-bit deep \fIrgbv\f1 colour-mapped channel
+\-	RGB15	15	three channels RGB: r5g5b5
+\-	RGB16	16	three channels RGB: r5g6b5
+\-	RGB24	24	three channels RGB: r8g8b8
+\-	RGBA32	32	four channels: RGB and alpha: r8g8b8a8
+.TE
+.LP
+The use of
+.CW Chans
+instead of
+.CW ldepth
+means that calls to
+.CW Display.newimage
+must be changed.
+For instance:
+.P1
+\fI(old)\f5
+buffer := display.newimage(r.inset(3), t.image.ldepth, 0, Draw->White);
+.P2
+becomes
+.P1
+\fI(new)\f5
+buffer := display.newimage(r.inset(3), t.image.chans, 0, Draw->White);
+.P2
+There is an obvious difference: the
+use of
+.CW t.image.chans
+instead of
+.CW t.image.ldepth
+to create a buffer Image with the same pixel structure as
+.CW t .
+There is, however, another difference.
+The final colour parameter to
+.CW newimage
+is also different in structure: in the new graphics model, it is a 32-bit integer value giving RGBA
+components,
+not a colour map index, and the name
+.CW Draw->White
+has the value
+.CW 16rFFFFFFFF
+not
+.CW 0 .
+Because a symbolic name was used, however, the source need not change.
+As another example,
+.CW Draw->Palegreyblue
+is
+.CW "int 16r4993DDFF" .
+Note the final
+.CW FF
+for the alpha component (creating a fully opaque colour).
+When the top bit is set, the
+.CW int
+cast shown here is needed to force the otherwise
+.CW big
+value to 32 bits.
+.LP
+The values of colour components are now uniformly expressed as
+intensity, so that a pixel with all zero colour components is black and
+one with all colour components at maximum (all ones, full intensity)
+is white.
+The
+.I rgbv
+map has therefore been reversed.
+Given a map index,
+.CW Display.cmap2rgba
+returns the 32-bit RGBA format used as a parameter in other calls.
+All colour components are
+.I linear
+values, as required for compositing to work properly;
+gamma correction is done as required by the display subsystem.
+.LP
+The colour components of a pixel with an alpha component are always
+.I pre-multiplied
+by the alpha value, following Porter and Duff, as further justified by Alvy Ray Smith and Jim Blinn.
+``Thus a 50% red is
+.CW 16r7F00007F
+not
+.CW 16rFF00007F .''
+The function
+.CW Draw->setalpha
+does the computation.
+.LP
+Because of the changes to colours and the replacement of simple masks by mattes, the Images
+.CW Display.ones
+and
+.CW Display.zeros
+are no longer defined.
+Instead, when they were intended to represent colours, the new Images
+.CW Display.black
+and
+.CW Display.white
+provide the obvious colours.
+When
+.CW ones
+and
+.CW zeros
+were used as masks, the new predefined Images
+.CW Display.opaque
+and
+.CW Display.transparent
+are used instead as constant mattes, with alpha channels (fully opaque and fully transparent, respectively).
+As noted above, where
+.CW Display.ones
+was used as a mask parameter in drawing operations, one can
+simply specify a nil Image as a matte (`no matte') instead.
+(That has been allowed for quite some time and is in use but might not be widely known.)
+.LP
+For example, Charon allocated a mask using:
+.P1
+dpicmask = display.newimage(pic.r, 0, 0, Draw->White);
+.P2
+which becomes
+.P1
+dpicmask = display.newimage(pic.r, Draw->GREY1, 0, Draw->Opaque);
+.P2
+where
+.CW GREY1
+is a constant value of the
+.CW Chans
+adt type, predefined by Draw, for Images that have a single 1-bit deep grey channel (ie, a bitmap).
+(Note that to form a fully-opaque matte,
+.CW Draw->Opaque
+was used for clarity, not
+.CW Draw->White ;
+.CW Draw->Transparent
+could also be used, as the basis for building a matte with transparency.)
+.LP
+A small if obscure change is that
+.CW Display.newwindow
+has a new parameter:
+.P1
+newwindow:	fn(screen: self ref Screen, r: Rect,
+	backing: int, color: int): ref Image;
+.P2
+The
+.I backing
+parameter should usually be
+.CW Draw->Refbackup ,
+except for windows allocated on an image that already has got backing store
+assigned, for instance because it is an image on a screen on an existing window image, in which case it should be
+.CW Draw->Refnone ,
+because the parent window already provides the backing.
+.LP
+As a small but helpful change, the adt
+.CW Draw->Pointer
+has a new element
+.CW msec
+that reports a
+relative time stamp in milliseconds.
+.LP
+The
+.CW Draw->Context
+content is significantly different, for the benefit of the new
+window system implementation.
+.NH 1
+Tk module
+.LP
+There is a new function in
+.CW Tk :
+.P1
+quote:   fn(s: string): string;
+.P2
+.CW Quote
+returns string
+.I s
+quoted according to Tk's `\f5{}\f1' quoting conventions.
+It replaces
+.CW Wmlib->tkquote .
+.LP
+There is a new widget type:
+.I panel (9).
+A panel instance can be packed and otherwise manipulated in the same way as any other Tk widget.
+An image is associated with it by calling
+.CW Tk->putimage
+defined in
+.I tk (2).
+The associated images can be drawn on directly by the application, using all the operations provided by
+.CW Draw .
+The coordinates of the changed rectangle must be given to Tk
+using the
+.CW panel
+widget command
+.CW dirty ;
+that part of the image will be redrawn if necessary at the next Tk
+.CW update .
+A panel has no default bindings.
+See
+.I panel (9)
+for details.
+.LP
+For example,
+.CW wm/coffee
+now uses the following:
+.P1
+r := Rect((0, 0), (400, 300));
+buffer := display.newimage(r, t.image.chans, 0, Draw->Black);
+tk->cmd(t, "panel .f.p -bd 3 -relief flat");
+tk->cmd(t, "pack .f.p -fill both -expand 1");
+tk->cmd(t, "update");
+org := buffer.r.min;
+tk->putimage(t, ".f.p", buffer, nil);
+.P2
+When it has updated the
+.CW buffer ,
+it tells Tk:
+.P1
+tk->cmd(t, ".f.p dirty; update");
+.P2
+In this case the whole image is marked dirty, but
+.CW dirty
+can be given an optional rectangle parameter to restrict redrawing.
+.LP
+.CW Tk->putimage
+and
+.CW Tk->getimage
+replace
+.CW imageput
+and
+.CW imageget .
+.NH 1
+Selectfile, Tabs and Dialog
+.LP
+The functions
+.CW filename ,
+.CW mktabs
+(and
+.CW tabsctl ),
+.CW dialog
+and
+.CW getstring
+have been moved to separate new modules, to allow those aspects of the
+user interface to be changed by replacing the implementations,
+and to allow standard modules to be provided for picking colours (for instance).
+.CW Selectfile
+acquires
+.CW filename ,
+.CW Tabs
+acquires the `tabs' Tk pseudo-widget, and
+.CW Dialog
+acquires
+.CW dialog ,
+which is renamed
+.CW prompt ,
+and
+.CW getstring .
+In cases where the functions took a
+.CW Tk->Toplevel
+as a parameter to specify a
+.CW parent
+window,
+they now take a
+.CW Draw->Context
+and (parent)
+.CW Image
+parameter;
+given a Toplevel
+.CW t ,
+use
+.CW t.image .
+See
+.I dialog (2),
+.I selectfile (2)
+and
+.I tabs (2).
+.TL
+Appendix A: Tk client conversion
+.LP
+.I Wm (1)
+applications now have to feed their own pointer and keyboard
+input to Tk. The window manager is now kept informed about the placement
+of windows.
+.LP
+A Tk toplevel now holds a window manager context:
+.P1
+Wmcontext: adt
+{
+	kbd: 		chan of int;		# incoming characters from keyboard
+	ptr: 		chan of ref Pointer;	# incoming stream of mouse positions
+	ctl:		chan of string;		# commands from wm to application
+	wctl:		chan of string;		# commands from application to wm
+	images:	chan of ref Image;	# exchange of images
+	connfd:	ref Sys->FD;		# connection control
+	ctxt:		ref Context;
+};
+.P2
+It contains some channels on which the window manager
+sends information to the application, and a file
+descriptor that can be used to write requests to the window
+manager.
+The channels used directly by the application are:
+.RS
+.IP \f(CWkbd\fP
+characters typed by the user (pass them to
+.CW Tk->pointer )
+.IP \f(CWptr\fP
+pointer events (pass them to
+.CW Tk->keyboard )
+.IP \f(CWctl\fP
+application control requests.
+Passing these to
+.CW Tkclient->wmctl
+will do the default action.
+Requests starting with an exclamation mark
+.CW ! ) (
+can cause the application's image to change.
+.RE
+.LP
+The toplevel also holds a channel
+.CW wreq
+on which it sends application
+control requests; these have the same form as those
+sent on
+.CW Wmcontext.ctl ,
+and can be forwarded to
+.CW Tkclient->wmctl
+in the same way.
+.LP
+Control requests currently understood by
+.I wm (1)
+are:
+.RS
+.IP "\f(CW!reshape \fItag\fP \fIreqid\fP \fIminx\fP \fIminy\fP \fImaxx\fP \fImaxy\fP [\fIhow\fP]\fR
+.br
+Reshape the window referenced by
+.I tag ,
+creating a new image if
+.I tag
+did not previously exist.
+.I Reqid
+is ignored.
+.I How
+can be one of:
+.RS
+.IP \f(CWplace\fP 15
+.I Wm
+attempts to find a suitable patch of screen real estate on which to place
+the window; the size of the given rectangle
+is taken to be the minimum size for that window.
+.IP \f(CWexact\fP
+Reshape to the exact rectangle requested.
+This is the default if
+.I how
+is not given.
+.IP \f(CWonscreen\fP
+The given rectangle is adjusted so that it is no bigger than the available
+screen space, and is entirely on screen.
+.RE
+.IP "\f(CWdelete \fItag\fP\fR
+.br
+Delete the image associated with
+.I tag .
+.IP "\f(CWraise\fP
+.br
+Raise the window
+.IP "\f(CWlower\fP
+.br
+Lower the window
+.IP "\f(CW!move \fItag\fP \fIreqid\fP \fIstartx\fP \fIstarty\fP\fR
+.br
+Request the user to move the window to a new place.
+.I Startx
+and
+.I starty
+are the coordinates of the pointer when the request was initiated.
+.IP "\f(CW!size \fItag\fP\fR
+.br
+Request the user to resize the window.
+.RE
+.LP
+To convert a typical Tk application, do the following.
+.IP 1.
+Use an editor to make the following changes:
+.RS
+.TS
+cfI cfI
+lf(CW) lf(CW) .
+Old	New
+Wmlib	Tkclient
+wmlib	tkclient
+tkclient->titlebar	tkclient->toplevel
+tkclient->titlectl	tkclient->wmctl
+tkclient->taskbar	tkclient->settitle
+tk->imageput	tk->putimage
+tk->imageget	tk->getimage
+.TE
+.RE
+.IP 2.
+Insert the following code at the top of the central
+.CW alt
+statement.
+The names
+.CW wmctl ' `
+and
+.CW top ` '
+will need changing to the appropriate variables in the program:
+.RS
+.P1
+s := <-top.ctxt.kbd =>
+	tk->keyboard(top, s);
+s := <-top.ctxt.ptr =>
+	tk->pointer(top, *s);
+s := <-top.ctxt.ctl or
+s = <-top.wreq or
+s = <-wmctl =>
+	tkclient->wmctl(top, s);
+.P2
+.RE
+.IP 3.
+Add the following just after the Tk configuration code and
+before the main processing starts:
+.RS
+.P1
+tkclient->onscreen(top, nil);
+tkclient->startinput(top, "kbd"::"ptr"::nil);
+.P2
+This is possibly the easiest part to forget.
+.RE
+.LP
+Be careful of cases where a blocking function is called
+from the main loop that relies on keyboard/mouse input.
+The easiest solution can be to spawn a thread to handle the
+keyboard and mouse independently.
binary files /dev/null b/doc/changes.pdf differ
--- /dev/null
+++ b/doc/compiler.ms
@@ -1,0 +1,1174 @@
+.TL
+Plan 9 C Compilers \(dg
+.AU
+.I "Ken Thompson"
+.AI
+ken@plan9.bell-labs.com
+.AB
+.FS
+\l'1i'
+.br
+\(dg Originally appeared, in a different form, in
+.I
+Proceedings of the Summer 1990 UKUUG Conference,
+.R
+pp. 41-51,
+London, 1990.
+This version first appeared in
+.I "Plan 9 Programmer's Manual, Volume 2 (Second Edition)" .
+The Plan 9 compiler suite forms the basis for the portable Inferno compiler suite,
+making this paper still relevant.
+.FE
+This paper describes the overall structure and function of the Plan 9 C compilers.
+A more detailed implementation document
+for any one of the compilers
+is yet to be written.
+.AE
+.NH
+Introduction
+.LP
+There are many compilers in the series.
+Eight of the compilers (MIPS 3000, SPARC, Intel 386, AMD64, Power PC, ARM, DEC Alpha, and Motorola 68020)
+are considered active and are used to compile
+current versions of Plan 9 or Inferno.
+Several others (Motorola 68000, Intel 960, AMD 29000) have had only limited use, such as
+to program peripherals or experimental devices.
+.NH
+Structure
+.LP
+The compiler is a single program that produces an
+object file.
+Combined in the compiler are the traditional
+roles of preprocessor, lexical analyzer, parser, code generator,
+local optimizer,
+and first half of the assembler.
+The object files are binary forms of assembly
+language,
+similar to what might be passed between
+the first and second passes of an assembler.
+.LP
+Object files and libraries
+are combined by a loader
+program to produce the executable binary.
+The loader combines the roles of second half
+of the assembler, global optimizer, and loader.
+The names of the compliers, loaders, and assemblers
+are as follows:
+.DS
+.ta 1.5i
+.de Ta
+\\$1	\f(CW\\$2\fP  \f(CW\\$3\fP  \f(CW\\$4\fP
+..
+.Ta SPARC kc kl ka
+.Ta PowerPC qc ql qa
+.Ta MIPS vc vl va
+.Ta Motorola\ 68000 1c 1l 1a
+.Ta Motorola\ 68020 2c 2l 2a
+.Ta ARM 5c 5l 5a
+.Ta AMD64 6c 6l 6a
+.Ta DEC\ Alpha 7c 7l 7a
+.Ta Intel\ 386 8c 8l 8a
+.Ta AMD\ 29000 9c 9l 9a
+.DE
+There is a further breakdown
+in the source of the compilers into
+object-independent and
+object-dependent
+parts.
+All of the object-independent parts
+are combined into source files in the
+directory
+.CW /sys/src/cmd/cc .
+The object-dependent parts are collected
+in a separate directory for each compiler,
+for example
+.CW /sys/src/cmd/vc .
+All of the code,
+both object-independent and
+object-dependent,
+is machine-independent
+and may be cross-compiled and executed on any
+of the architectures.
+.NH
+The Language
+.LP
+The compiler implements ANSI C with some
+restrictions and extensions
+[ANSI90].
+Most of the restrictions are due to
+personal preference, while
+most of the extensions were to help in
+the implementation of Plan 9.
+There are other departures from the standard,
+particularly in the libraries,
+that are beyond the scope of this
+paper.
+.NH 2
+Register, volatile, const
+.LP
+The keyword
+.CW register
+is recognized syntactically
+but is semantically ignored.
+Thus taking the address of a
+.CW register
+variable is not diagnosed.
+The keyword
+.CW volatile
+disables all optimizations, in particular registerization, of the corresponding variable.
+The keyword
+.CW const
+generates warnings (if warnings are enabled by the compiler's
+.CW -w
+option) of non-constant use of the variable,
+but does not affect the generated code.
+.NH 2
+The preprocessor
+.LP
+The C preprocessor is probably the
+biggest departure from the ANSI standard.
+.LP
+The preprocessor built into the Plan 9 compilers does not support
+.CW #if ,
+although it does handle
+.CW #ifdef
+and
+.CW #include .
+If it is necessary to be more standard,
+the source text can first be run through the separate ANSI C
+preprocessor,
+.CW cpp .
+.NH 2
+Unnamed substructures
+.LP
+The most important and most heavily used of the
+extensions is the declaration of an
+unnamed substructure or subunion.
+For example:
+.DS
+.CW
+.ta .1i .6i 1.1i 1.6i
+	typedef
+	struct	lock
+	{
+		int    locked;
+	} Lock;
+
+	typedef
+	struct	node
+	{
+		int	type;
+		union
+		{
+			double dval;
+			float  fval;
+			long   lval;
+		};
+		Lock;
+	} Node;
+
+	Lock*	lock;
+	Node*	node;
+.R
+.DE
+The declaration of
+.CW Node
+has an unnamed substructure of type
+.CW Lock
+and an unnamed subunion.
+One use of this feature allows references to elements of the
+subunit to be accessed as if they were in
+the outer structure.
+Thus
+.CW node->dval
+and
+.CW node->locked
+are legitimate references.
+.LP
+When an outer structure is used
+in a context that is only legal for
+an unnamed substructure,
+the compiler promotes the reference to the
+unnamed substructure.
+This is true for references to structures and
+to references to pointers to structures.
+This happens in assignment statements and
+in argument passing where prototypes have been
+declared.
+Thus, continuing with the example,
+.DS
+.CW
+.ta .1i .6i 1.1i 1.6i
+	lock = node;
+.R
+.DE
+would assign a pointer to the unnamed
+.CW Lock
+in
+the
+.CW Node
+to the variable
+.CW lock .
+Another example,
+.DS
+.CW
+.ta .1i .6i 1.1i 1.6i
+	extern void lock(Lock*);
+	func(...)
+	{
+		...
+		lock(node);
+		...
+	}
+.R
+.DE
+will pass a pointer to the
+.CW Lock
+substructure.
+.LP
+Finally, in places where context is insufficient to identify the unnamed structure,
+the type name (it must be a
+.CW typedef )
+of the unnamed structure can be used as an identifier.
+In our example,
+.CW &node->Lock
+gives the address of the anonymous
+.CW Lock
+structure.
+.NH 2
+Structure displays
+.LP
+A structure cast followed by a list of expressions in braces is
+an expression with the type of the structure and elements assigned from
+the corresponding list.
+Structures are now almost first-class citizens of the language.
+It is common to see code like this:
+.DS
+.CW
+.ta .1i
+	r = (Rectangle){point1, (Point){x,y+2}};
+.R
+.DE
+.NH 2
+Initialization indexes
+.LP
+In initializers of arrays,
+one may place a constant expression
+in square brackets before an initializer.
+This causes the next initializer to assign
+the indicated element.
+For example:
+.DS
+.CW
+.ta .1i .6i 1.6i
+	enum	errors
+	{
+		Etoobig,
+		Ealarm,
+		Egreg
+	};
+	char* errstrings[] =
+	{
+		[Ealarm]	"Alarm call",
+		[Egreg]	"Panic: out of mbufs",
+		[Etoobig]	"Arg list too long",
+	};
+.R
+.DE
+In the same way,
+individual structures members may
+be initialized in any order by preceding the initialization with
+.CW .tagname .
+Both forms allow an optional
+.CW = ,
+to be compatible with a proposed
+extension to ANSI C.
+.NH 2
+External register
+.LP
+The declaration
+.CW extern
+.CW register
+will dedicate a register to
+a variable on a global basis.
+It can be used only under special circumstances.
+External register variables must be identically
+declared in all modules and
+libraries.
+The feature is not intended for efficiency,
+although it can produce efficient code;
+rather it represents a unique storage class that
+would be hard to get any other way.
+On a shared-memory multi-processor,
+an external register is
+one-per-processor and neither one-per-procedure (automatic)
+or one-per-system (external).
+It is used for two variables in the Plan 9 kernel,
+.CW u
+and
+.CW m .
+.CW U
+is a pointer to the structure representing the currently running process
+and
+.CW m
+is a pointer to the per-machine data structure.
+.NH 2
+Long long
+.LP
+The compilers accept
+.CW long
+.CW long
+as a basic type meaning 64-bit integer.
+On all of the machines
+this type is synthesized from 32-bit instructions.
+.NH 2
+Pragma
+.LP
+The compilers accept
+.CW #pragma
+.CW lib
+.I libname
+and pass the
+library name string uninterpreted
+to the loader.
+The loader uses the library name to
+find libraries to load.
+If the name contains
+.CW $O ,
+it is replaced with
+the single character object type of the compiler
+(e.g.,
+.CW v
+for the MIPS).
+If the name contains
+.CW $M ,
+it is replaced with
+the architecture type for the compiler
+(e.g.,
+.CW mips
+for the MIPS).
+If the name starts with
+.CW /
+it is an absolute pathname;
+if it starts with
+.CW .
+then it is searched for in the loader's current directory.
+Otherwise, the name is searched from
+.CW /$M/lib .
+Such
+.CW #pragma
+statements in header files guarantee that the correct
+libraries are always linked with a program without the
+need to specify them explicitly at link time.
+.LP
+They also accept
+.CW #pragma
+.CW packed
+.CW on
+(or
+.CW yes
+or
+.CW 1 )
+to cause subsequently declared data, until
+.CW #pragma
+.CW packed
+.CW off
+(or
+.CW no
+or
+.CW 0 ),
+to be laid out in memory tightly packed in successive bytes, disregarding
+the usual alignment rules.
+Accessing such data can cause faults.
+.LP
+Similarly, 
+.CW #pragma
+.CW profile
+.CW off
+(or
+.CW no
+or
+.CW 0 )
+causes subsequently declared functions, until
+.CW #pragma
+.CW profile
+.CW on
+(or
+.CW yes
+or
+.CW 1 ),
+to be marked as unprofiled.
+Such functions will not be profiled when 
+profiling is enabled for the rest of the program.
+.LP
+Two
+.CW #pragma
+statements allow type-checking of
+.CW print -like
+functions.
+The first, of the form
+.P1
+#pragma varargck argpos error 2
+.P2
+tells the compiler that the second argument to
+.CW error
+is a
+.CW print
+format string (see the manual page
+.I print (2))
+that specifies how to format
+.CW error 's
+subsequent arguments.
+The second, of the form
+.P1
+#pragma varargck type "s" char*
+.P2
+says that the
+.CW print
+format verb
+.CW s
+processes an argument of
+type
+.CW char* .
+If the compiler's
+.CW -F
+option is enabled, the compiler will use this information
+to report type violations in the arguments to
+.CW print ,
+.CW error ,
+and similar routines.
+.NH
+Object module conventions
+.LP
+The overall conventions of the runtime environment
+are important
+to runtime efficiency.
+In this section,
+several of these conventions are discussed.
+.NH 2
+Register saving
+.LP
+In the Plan 9 compilers,
+the caller of a procedure saves the registers.
+With caller-saves,
+the leaf procedures can use all the
+registers and never save them.
+If you spend a lot of time at the leaves,
+this seems preferable.
+With callee-saves,
+the saving of the registers is done
+in the single point of entry and return.
+If you are interested in space,
+this seems preferable.
+In both,
+there is a degree of uncertainty
+about what registers need to be saved.
+Callee-saved registers make it difficult to
+find variables in registers in debuggers.
+Callee-saved registers also complicate
+the implementation of
+.CW longjmp .
+The convincing argument is
+that with caller-saves,
+the decision to registerize a variable
+can include the cost of saving the register
+across calls.
+For a further discussion of caller- vs. callee-saves,
+see the paper by Davidson and Whalley [Dav91].
+.LP
+In the Plan 9 operating system,
+calls to the kernel look like normal procedure
+calls, which means
+the caller
+has saved the registers and the system
+entry does not have to.
+This makes system calls considerably faster.
+Since this is a potential security hole,
+and can lead to non-determinism,
+the system may eventually save the registers
+on entry,
+or more likely clear the registers on return.
+.NH 2
+Calling convention
+.LP
+Older C compilers maintain a frame pointer, which is at a known constant
+offset from the stack pointer within each function.
+For machines where the stack grows towards zero,
+the argument pointer is at a known constant offset
+from the frame pointer.
+Since the stack grows down in Plan 9,
+the Plan 9 compilers
+keep neither an
+explicit frame pointer nor
+an explicit argument pointer;
+instead they generate addresses relative to the stack pointer.
+.LP
+On some architectures, the first argument to a subroutine is passed in a register.
+.NH 2
+Functions returning structures
+.LP
+Structures longer than one word are awkward to implement
+since they do not fit in registers and must
+be passed around in memory.
+Functions that return structures
+are particularly clumsy.
+The Plan 9 compilers pass the return address of
+a structure as the first argument of a
+function that has a structure return value.
+Thus
+.DS
+.CW
+.ta .1i .6i 1.1i 1.6i
+	x = f(...)
+.R
+.DE
+is rewritten as
+.DS
+.CW
+.ta .1i .6i 1.1i 1.6i
+	f(&x, ...)\f1.
+.R
+.DE
+This saves a copy and makes the compilation
+much less clumsy.
+A disadvantage is that if you call this
+function without an assignment,
+a dummy location must be invented.
+.LP
+There is also a danger of calling a function
+that returns a structure without declaring
+it as such.
+With ANSI C function prototypes,
+this error need never occur.
+.NH
+Implementation
+.LP
+The compiler is divided internally into
+four machine-independent passes,
+four machine-dependent passes,
+and an output pass.
+The next nine sections describe each pass in order.
+.NH 2
+Parsing
+.LP
+The first pass is a YACC-based parser
+[Joh79].
+Declarations are interpreted immediately,
+building a block structured symbol table.
+Executable statements are put into a parse tree
+and collected,
+without interpretation.
+At the end of each procedure,
+the parse tree for the function is
+examined by the other passes of the compiler.
+.LP
+The input stream of the parser is
+a pushdown list of input activations.
+The preprocessor
+expansions of
+macros
+and
+.CW #include
+are implemented as pushdowns.
+Thus there is no separate
+pass for preprocessing.
+.NH 2
+Typing
+.LP
+The next pass distributes typing information
+to every node of the tree.
+Implicit operations on the tree are added,
+such as type promotions and taking the
+address of arrays and functions.
+.NH 2
+Machine-independent optimization
+.LP
+The next pass performs optimizations
+and transformations of the tree, such as converting
+.CW &*x
+and
+.CW *&x
+into
+.CW x .
+Constant expressions are converted to constants in this pass.
+.NH 2
+Arithmetic rewrites
+.LP
+This is another machine-independent optimization.
+Subtrees of add, subtract, and multiply of integers are
+rewritten for easier compilation.
+The major transformation is factoring:
+.CW 4+8*a+16*b+5
+is transformed into
+.CW 9+8*(a+2*b) .
+Such expressions arise from address
+manipulation and array indexing.
+.NH 2
+Addressability
+.LP
+This is the first of the machine-dependent passes.
+The addressability of a processor is defined as the set of
+expressions that is legal in the address field
+of a machine language instruction.
+The addressability of different processors varies widely.
+At one end of the spectrum are the 68020 and VAX,
+which allow a complex mix of incrementing,
+decrementing,
+indexing, and relative addressing.
+At the other end is the MIPS,
+which allows only registers and constant offsets from the
+contents of a register.
+The addressability can be different for different instructions
+within the same processor.
+.LP
+It is important to the code generator to know when a
+subtree represents an address of a particular type.
+This is done with a bottom-up walk of the tree.
+In this pass, the leaves are labeled with small integers.
+When an internal node is encountered,
+it is labeled by consulting a table indexed by the
+labels on the left and right subtrees.
+For example,
+on the 68020 processor,
+it is possible to address an
+offset from a named location.
+In C, this is represented by the expression
+.CW *(&name+constant) .
+This is marked addressable by the following table.
+In the table,
+a node represented by the left column is marked
+with a small integer from the right column.
+Marks of the form
+.CW A\s-2\di\u\s0
+are addressable while
+marks of the form
+.CW N\s-2\di\u\s0
+are not addressable.
+.DS
+.B
+.ta .1i 1.1i
+	Node	Marked
+.CW
+	name	A\s-2\d1\u\s0
+	const	A\s-2\d2\u\s0
+	&A\s-2\d1\u\s0	A\s-2\d3\u\s0
+	A\s-2\d3\u\s0+A\s-2\d1\u\s0	N\s-2\d1\u\s0 \fR(note that this is not addressable)\fP
+	*N\s-2\d1\u\s0	A\s-2\d4\u\s0
+.R
+.DE
+Here there is a distinction between
+a node marked
+.CW A\s-2\d1\u\s0
+and a node marked
+.CW A\s-2\d4\u\s0
+because the address operator of an
+.CW A\s-2\d4\u\s0
+node is not addressable.
+So to extend the table:
+.DS
+.B
+.ta .1i 1.1i
+	Node	Marked
+.CW
+	&A\s-2\d4\u\s0	N\s-2\d2\u\s0
+	N\s-2\d2\u\s0+N\s-2\d1\u\s0	N\s-2\d1\u\s0
+.R
+.DE
+The full addressability of the 68020 is expressed
+in 18 rules like this,
+while the addressability of the MIPS is expressed
+in 11 rules.
+When one ports the compiler,
+this table is usually initialized
+so that leaves are labeled as addressable and nothing else.
+The code produced is poor,
+but porting is easy.
+The table can be extended later.
+.LP
+This pass also rewrites some complex operators
+into procedure calls.
+Examples include 64-bit multiply and divide.
+.LP
+In the same bottom-up pass of the tree,
+the nodes are labeled with a Sethi-Ullman complexity
+[Set70].
+This number is roughly the number of registers required
+to compile the tree on an ideal machine.
+An addressable node is marked 0.
+A function call is marked infinite.
+A unary operator is marked as the
+maximum of 1 and the mark of its subtree.
+A binary operator with equal marks on its subtrees is
+marked with a subtree mark plus 1.
+A binary operator with unequal marks on its subtrees is
+marked with the maximum mark of its subtrees.
+The actual values of the marks are not too important,
+but the relative values are.
+The goal is to compile the harder
+(larger mark)
+subtree first.
+.NH 2
+Code generation
+.LP
+Code is generated by recursive
+descent.
+The Sethi-Ullman complexity completely guides the
+order.
+The addressability defines the leaves.
+The only difficult part is compiling a tree
+that has two infinite (function call)
+subtrees.
+In this case,
+one subtree is compiled into the return register
+(usually the most convenient place for a function call)
+and then stored on the stack.
+The other subtree is compiled into the return register
+and then the operation is compiled with
+operands from the stack and the return register.
+.LP
+There is a separate boolean code generator that compiles
+conditional expressions.
+This is fundamentally different from compiling an arithmetic expression.
+The result of the boolean code generator is the
+position of the program counter and not an expression.
+The boolean code generator makes extensive use of De Morgan's rule.
+The boolean code generator is an expanded version of that described
+in chapter 8 of Aho, Sethi, and Ullman
+[Aho87].
+.LP
+There is a considerable amount of talk in the literature
+about automating this part of a compiler with a machine
+description.
+Since this code generator is so small
+(less than 500 lines of C)
+and easy,
+it hardly seems worth the effort.
+.NH 2
+Registerization
+.LP
+Up to now,
+the compiler has operated on syntax trees
+that are roughly equivalent to the original source language.
+The previous pass has produced machine language in an internal
+format.
+The next two passes operate on the internal machine language
+structures.
+The purpose of the next pass is to reintroduce
+registers for heavily used variables.
+.LP
+All of the variables that can be
+potentially registerized within a procedure are
+placed in a table.
+(Suitable variables are any automatic or external
+scalars that do not have their addresses extracted.
+Some constants that are hard to reference are also
+considered for registerization.)
+Four separate data flow equations are evaluated
+over the procedure on all of these variables.
+Two of the equations are the normal set-behind
+and used-ahead
+bits that define the life of a variable.
+The two new bits tell if a variable life
+crosses a function call ahead or behind.
+By examining a variable over its lifetime,
+it is possible to get a cost
+for registerizing.
+Loops are detected and the costs are multiplied
+by three for every level of loop nesting.
+Costs are sorted and the variables
+are replaced by available registers on a greedy basis.
+.LP
+The 68020 has two different
+types of registers.
+For the 68020,
+two different costs are calculated for
+each variable life and the register type that
+affords the better cost is used.
+Ties are broken by counting the number of available
+registers of each type.
+.LP
+Note that externals are registerized together with automatics.
+This is done by evaluating the semantics of a ``call'' instruction
+differently for externals and automatics.
+Since a call goes outside the local procedure,
+it is assumed that a call references all externals.
+Similarly,
+externals are assumed to be set before an ``entry'' instruction
+and assumed to be referenced after a ``return'' instruction.
+This makes sure that externals are in memory across calls.
+.LP
+The overall results are satisfactory.
+It would be nice to be able to do this processing in
+a machine-independent way,
+but it is impossible to get all of the costs and
+side effects of different choices by examining the parse tree.
+.LP
+Most of the code in the registerization pass is machine-independent.
+The major machine-dependency is in
+examining a machine instruction to ask if it sets or references
+a variable.
+.NH 2
+Machine code optimization
+.LP
+The next pass walks the machine code
+for opportunistic optimizations.
+For the most part,
+this is highly specific to a particular
+processor.
+One optimization that is performed
+on all of the processors is the
+removal of unnecessary ``move''
+instructions.
+Ironically,
+most of these instructions were inserted by
+the previous pass.
+There are two patterns that are repetitively
+matched and replaced until no more matches are
+found.
+The first tries to remove ``move'' instructions
+by relabeling variables.
+.LP
+When a ``move'' instruction is encountered,
+if the destination variable is set before the
+source variable is referenced,
+then all of the references to the destination
+variable can be renamed to the source and the ``move''
+can be deleted.
+This transformation uses the reverse data flow
+set up in the previous pass.
+.LP
+An example of this pattern is depicted in the following
+table.
+The pattern is in the left column and the
+replacement action is in the right column.
+.DS
+.CW
+.ta .1i .6i 1.6i 2.1i 2.6i
+	MOVE	a->b		\fR(remove)\fP
+.R
+	(sequence with no mention of \f(CWa\fP)
+.CW
+	USE	b		USE	a
+.R
+	(sequence with no mention of \f(CWa\fP)
+.CW
+	SET	b		SET	b
+.R
+.DE
+.LP
+Experiments have shown that it is marginally
+worthwhile to rename uses of the destination variable
+with uses of the source variable up to
+the first use of the source variable.
+.LP
+The second transform will do relabeling
+without deleting instructions.
+When a ``move'' instruction is encountered,
+if the source variable has been set prior
+to the use of the destination variable
+then all of the references to the source
+variable are replaced by the destination and
+the ``move'' is inverted.
+Typically,
+this transformation will alter two ``move''
+instructions and allow the first transformation
+another chance to remove code.
+This transformation uses the forward data flow
+set up in the previous pass.
+.LP
+Again,
+the following is a depiction of the transformation where
+the pattern is in the left column and the
+rewrite is in the right column.
+.DS
+.CW
+.ta .1i .6i 1.6i 2.1i 2.6i
+	SET	a		SET	b
+.R
+	(sequence with no use of \f(CWb\fP)
+.CW
+	USE	a		USE	b
+.R
+	(sequence with no use of \f(CWb\fP)
+.CW
+	MOVE	a->b		MOVE	b->a
+.R
+.DE
+Iterating these transformations
+will usually get rid of all redundant ``move'' instructions.
+.LP
+A problem with this organization is that the costs
+of registerization calculated in the previous pass
+must depend on how well this pass can detect and remove
+redundant instructions.
+Often,
+a fine candidate for registerization is rejected
+because of the cost of instructions that are later
+removed.
+.NH 2
+Writing the object file
+.LP
+The last pass walks the internal assembly language
+and writes the object file.
+The object file is reduced in size by about a factor
+of three with simple compression
+techniques.
+The most important aspect of the object file
+format is that it is independent of the compiling machine.
+All integer and floating numbers in the object
+code are converted to known formats and byte
+orders.
+.NH
+The loader
+.LP
+The loader is a multiple pass program that
+reads object files and libraries and produces
+an executable binary.
+The loader also does some minimal
+optimizations and code rewriting.
+Many of the operations performed by the
+loader are machine-dependent.
+.LP
+The first pass of the loader reads the
+object modules into an internal data
+structure that looks like binary assembly language.
+As the instructions are read,
+code is reordered to remove
+unconditional branch instructions.
+Conditional branch instructions are inverted
+to prevent the insertion of unconditional branches.
+The loader will also make a copy of a few instructions
+to remove an unconditional branch.
+.LP
+The next pass allocates addresses for
+all external data.
+Typical of processors is the MIPS,
+which can reference ±32K bytes from a
+register.
+The loader allocates the register
+.CW R30
+as the static pointer.
+The value placed in
+.CW R30
+is the base of the data segment plus 32K.
+It is then cheap to reference all data in the
+first 64K of the data segment.
+External variables are allocated to
+the data segment
+with the smallest variables allocated first.
+If all of the data cannot fit into the first
+64K of the data segment,
+then usually only a few large arrays
+need more expensive addressing modes.
+.LP
+For the MIPS processor,
+the loader makes a pass over the internal
+structures,
+exchanging instructions to try
+to fill ``delay slots'' with useful work.
+If a useful instruction cannot be found
+to fill a delay slot,
+the loader will insert
+``noop''
+instructions.
+This pass is very expensive and does not
+do a good job.
+About 40% of all instructions are in
+delay slots.
+About 65% of these are useful instructions and
+35% are ``noops.''
+The vendor-supplied assembler does this job
+more effectively,
+filling about 80%
+of the delay slots with useful instructions.
+.LP
+On the 68020 processor,
+branch instructions come in a variety of
+sizes depending on the relative distance
+of the branch.
+Thus the size of branch instructions
+can be mutually dependent.
+The loader uses a multiple pass algorithm
+to resolve the branch lengths
+[Szy78].
+Initially, all branches are assumed minimal length.
+On each subsequent pass,
+the branches are reassessed
+and expanded if necessary.
+When no more expansions occur,
+the locations of the instructions in
+the text segment are known.
+.LP
+On the MIPS processor,
+all instructions are one size.
+A single pass over the instructions will
+determine the locations of all addresses
+in the text segment.
+.LP
+The last pass of the loader produces the
+executable binary.
+A symbol table and other tables are
+produced to help the debugger to
+interpret the binary symbolically.
+.LP
+The loader places absolute source line numbers in the symbol table.
+The name and absolute line number of all
+.CW #include
+files is also placed in the
+symbol table so that the debuggers can
+associate object code to source files.
+.NH
+Performance
+.LP
+The following is a table of the source size of the MIPS
+compiler.
+.DS
+.ta .1i .6i
+	lines	module
+	\0509	machine-independent headers
+	1070	machine-independent YACC source
+	6090	machine-independent C source
+
+	\0545	machine-dependent headers
+	6532	machine-dependent C source
+
+	\0298	loader headers
+	5215	loader C source
+.DE
+.LP
+The following table shows timing
+of a test program
+that plays checkers, running on a MIPS R4000.
+The test program is 26 files totaling 12600 lines of C.
+The execution time does not significantly
+depend on library implementation.
+Since no other compiler runs on Plan 9,
+the Plan 9 tests were done with the Plan 9 operating system;
+the other tests were done on the vendor's operating system.
+The hardware was identical in both cases.
+The optimizer in the vendor's compiler
+is reputed to be extremely good.
+.DS
+.ta .1i .9i
+	\0\04.49s	Plan 9 \f(CWvc\fP \f(CW-N\fP compile time (opposite of \f(CW-O\fP)
+	\0\01.72s	Plan 9 \f(CWvc\fP \f(CW-N\fP load time
+	148.69s	Plan 9 \f(CWvc\fP \f(CW-N\fP run time
+
+	\015.07s	Plan 9 \f(CWvc\fP compile time (\f(CW-O\fP implicit)
+	\0\01.66s	Plan 9 \f(CWvc\fP load time
+	\089.96s	Plan 9 \f(CWvc\fP run time
+
+	\014.83s	vendor \f(CWcc\fP compile time
+	\0\00.38s	vendor \f(CWcc\fP load time
+	104.75s	vendor \f(CWcc\fP run time
+
+	\043.59s	vendor \f(CWcc\fP \f(CW-O\fP compile time
+	\0\00.38s	vendor \f(CWcc\fP \f(CW-O\fP load time
+	\076.19s	vendor \f(CWcc\fP \f(CW-O\fP run time
+
+	\0\08.19s	vendor \f(CWcc\fP \f(CW-O3\fP compile time
+	\035.97s	vendor \f(CWcc\fP \f(CW-O3\fP load time
+	\071.16s	vendor \f(CWcc\fP \f(CW-O3\fP run time
+.DE
+.LP
+To compare the Intel compiler,
+a program that is about 40% bit manipulation and
+about 60% single precision floating point was
+run on the same 33 MHz 486, once under Windows
+compiled with the Watcom compiler, version 10.0,
+in 16-bit mode and once under
+Plan 9 in 32-bit mode.
+The Plan 9 execution time was 27 sec while the Windows
+execution time was 31 sec.
+.NH
+Conclusions
+.LP
+The new compilers compile
+quickly,
+load slowly,
+and produce
+medium quality
+object code.
+The compilers are relatively
+portable,
+requiring but a couple of weeks' work to
+produce a compiler for a different computer.
+For Plan 9,
+where we needed several compilers
+with specialized features and
+our own object formats,
+this project was indispensable.
+It is also necessary for us to
+be able to freely distribute our compilers
+with the Plan 9 distribution.
+.LP
+Two problems have come up in retrospect.
+The first has to do with the
+division of labor between compiler and loader.
+Plan 9 runs on multi-processors and as such
+compilations are often done in parallel.
+Unfortunately,
+all compilations must be complete before loading
+can begin.
+The load is then single-threaded.
+With this model,
+any shift of work from compile to load
+results in a significant increase in real time.
+The same is true of libraries that are compiled
+infrequently and loaded often.
+In the future,
+we may try to put some of the loader work
+back into the compiler.
+.LP
+The second problem comes from
+the various optimizations performed over several
+passes.
+Often optimizations in different passes depend
+on each other.
+Iterating the passes could compromise efficiency,
+or even loop.
+We see no real solution to this problem.
+.NH
+References
+.LP
+[Aho87] A. V. Aho, R. Sethi, and J. D. Ullman,
+.I
+Compilers \- Principles, Techniques, and Tools,
+.R
+Addison Wesley,
+Reading, MA,
+1987.
+.LP
+[ANSI90] \f2American National Standard for Information Systems \-
+Programming Language C\f1, American National Standards Institute, Inc.,
+New York, 1990.
+.LP
+[Dav91] J. W. Davidson and D. B. Whalley,
+``Methods for Saving and Restoring Register Values across Function Calls'',
+.I
+Software\-Practice and Experience,
+.R
+Vol 21(2), pp. 149-165, February 1991.
+.LP
+[Joh79] S. C. Johnson,
+``YACC \- Yet Another Compiler Compiler'',
+.I
+UNIX Programmer's Manual, Seventh Ed., Vol. 2A,
+.R
+AT&T Bell Laboratories,
+Murray Hill, NJ,
+1979.
+.LP
+[Set70] R. Sethi and J. D. Ullman,
+``The Generation of Optimal Code for Arithmetic Expressions'',
+.I
+Journal of the ACM,
+.R
+Vol 17(4), pp. 715-728, 1970.
+.LP
+[Szy78] T. G. Szymanski,
+``Assembling Code for Machines with Span-dependent Instructions'',
+.I
+Communications of the ACM,
+.R
+Vol 21(4), pp. 300-308, 1978.
binary files /dev/null b/doc/compiler.pdf differ
--- /dev/null
+++ b/doc/descent/descent.ms
@@ -1,0 +1,2056 @@
+.de EX
+.nr x \\$1v
+\\!h0c n \\nx 0
+..
+.de FG		\" start figure caption: .FG filename.ps verticalsize
+.KF
+.BP \\$1 \\$2
+.sp .5v
+.EX \\$2v
+.ps -1
+.vs -1
+..
+.de fg		\" end figure caption (yes, it is clumsy)
+.ps
+.vs
+.br
+.KE
+..
+.TL
+A Descent into Limbo
+.AU
+Brian W. Kernighan
+.AI
+bwk@bell-labs.com
+.br
+Revised April 2005 by Vita Nuova
+.AB
+.DS B
+.ps -2
+.vs -1
+``If, reader, you are slow now to believe
+What I shall tell, that is no cause for wonder,
+For I who saw it hardly can accept it.''
+.ft R
+	Dante Alighieri, \fIInferno\fP, Canto XXV.
+.ps +2
+.vs +1
+.DE
+.LP
+Limbo is a new programming language, designed by
+Sean Dorward, Phil Winterbottom, and Rob Pike.
+Limbo borrows from, among other things,
+C (expression syntax and control flow),
+Pascal (declarations), 
+Winterbottom's Alef (abstract data types and channels),
+and Hoare's CSP and Pike's Newsqueak (processes).
+Limbo is strongly typed, provides automatic garbage collection,
+supports only very restricted pointers,
+and compiles into machine-independent byte code for execution on
+a virtual machine.
+.LP
+This paper is a brief introduction to Limbo.
+Since Limbo is an integral part of the Inferno system,
+the examples here illustrate not only
+the language but also a certain amount about how to write
+programs to run within Inferno.
+.AE
+.NH 1
+Introduction
+.LP
+This document is a quick look at the basics
+of Limbo; it is not a replacement for the reference manual.
+The first section is a short overview of
+concepts and constructs;
+subsequent sections illustrate the language with examples.
+Although Limbo is intended to be used in Inferno,
+which emphasizes networking and graphical interfaces,
+the discussion here begins with standard text-manipulation
+examples, since they require less background to understand.
+.SH
+Modules:
+.LP
+A Limbo program is a set of modules that cooperate
+to perform a task.
+In source form, a module consists of a
+.CW "module" 
+declaration that specifies the public interface \- the functions,
+abstract data types,
+and constants that the module makes visible to other modules \-
+and an implementation that provides the actual code.
+By convention, the module declaration is usually placed in a separate
+.CW ".m" 
+file so it can be included by other modules,
+and the implementation is stored in a
+.CW ".b" 
+file.
+Modules may have multiple implementations,
+each in a separate implementation file.
+.LP
+Modules are always loaded dynamically, at run time: the Limbo
+.CW "load" 
+operator fetches the code and performs run-time type checking.
+Once a module has been loaded, its functions can be called.
+Several instances of the same module type can be in use at once,
+with possibly different implementations.
+.LP
+Limbo is strongly typed; programs are checked at compile time,
+and further when modules are loaded.
+The Limbo compiler compiles each source file into a
+machine-independent byte-coded 
+.CW ".dis" 
+file that can be loaded at run time.
+.SH
+Functions and variables:
+.LP
+Functions are associated with specific modules, either directly or
+as members of abstract data types within a module.
+Functions are visible outside their module only
+if they are part of the module interface.
+If the target module is loaded, specific names
+can be used in a qualified form like
+.CW "sys->print" 
+or without the qualifier if imported with an explicit
+.CW "import" 
+statement.
+.LP
+Besides normal block structure within functions,
+variables may have global scope within a module;
+module data can be accessed via the module pointer.
+.SH
+Data:
+.LP
+The numeric types are:
+.RS
+.TS
+lf(CW) lf(R)w(3i) .
+byte	unsigned, 8 bits
+int	signed, 32 bits
+big	signed, 64 bits
+real	IEEE long float, 64 bits
+.TE
+.RE
+The size and signedness of integral types are
+as specified above, and will be the same everywhere.
+Character constants are enclosed in single quotes
+and may use escapes like
+.CW "'\en'" 
+or
+.CW "'\eudddd'" ,
+but the characters themselves
+are in Unicode and have type
+.CW "int" .
+There is no enumeration type, but there is a
+.CW "con" 
+declaration that creates a named constant, and a special
+.CW "iota"
+operation that can be used to generate unique values.
+.LP
+Limbo also provides
+Unicode strings,
+arrays of arbitrary types,
+lists of arbitrary types,
+tuples (in effect, unnamed structures with unnamed members of arbitrary types),
+abstract data types or adt's (in effect, named structures with function
+members as well as data members),
+reference types (in effect, restricted pointers that can point only to adt objects),
+and 
+typed channels (for passing objects between processes).
+.LP
+A channel is a mechanism for synchronized communication.
+It provides a place for one process to send or receive
+an object of a specific type;
+the attempt to send or receive blocks until a matching receive or send
+is attempted by another process.
+The 
+.CW "alt" 
+statement selects randomly but fairly among channels
+that are ready to read or write.
+The
+.CW "spawn" 
+statement creates a new process that,
+except for its stack, shares memory with other processes.
+Processes are pre-emptively scheduled by the Inferno kernel.
+(Inferno processes are sometimes called ``threads'' in
+other operating systems.)
+.LP
+Limbo performs automatic garbage collection, so there is no
+need to free dynamically created objects.
+Objects are deleted and their resources freed when
+the last reference to them goes away.
+This release of resources happens immediately
+(``instant free'') for non-cyclic structures;
+release of cyclic data structures might be delayed but will happen eventually.
+(The language allows the programmer to ensure a given structure is non-cyclic
+when required.)
+.SH
+Operators and expressions:
+.LP
+Limbo provides many of C's operators,
+but not the
+.CW "?:" 
+or
+`comma' (sequential execution) operators.
+Pointers, or `references', created with
+.CW "ref" ,
+are restricted compared to C: they can only refer to adt values on the heap.
+There is no
+.CW "&" 
+(address of) operator, nor is address arithmetic possible.
+Arrays are also reference types, however,
+and since
+array slicing is supported, that replaces
+many of C's pointer constructions.
+.LP
+There are no implicit coercions between types,
+and only a handful of explicit casts.
+The numeric types
+.CW "byte" ,
+.CW "int" ,
+etc., can be used to convert a numeric expression, as in
+.P1
+nl := byte 10;
+.P2
+and
+.CW "string" 
+can be used as a unary operator to convert any numeric expression
+to a string (in
+.CW "%g" 
+format) and to convert an array of bytes in UTF-8 format to a Limbo
+.CW string
+value.
+In the other direction, the cast
+.CW "array of byte"
+converts a string to its UTF-8 representation in an array of bytes.
+.SH
+Statements:
+.LP
+Statements and control flow in Limbo are similar to those in C.
+A statement is an expression followed by a semicolon,
+or a sequence of statements enclosed in braces.
+The similar control flow statements are
+.P1
+if (\fIexpr\fP) \fIstat\fP
+if (\fIexpr\fP) \fIstat\fP else \fIstat\fP
+while (\fIexpr\fP) \fIstat\fP
+for (\fIexpr\fP; \fIexpr\fP; \fIexpr\fP) \fIstat\fP
+do \fIstat\fP while (\fIexpr\fP) ;
+return \fIexpr\fP ;
+exit ;
+.P2
+The
+.CW "exit" 
+statement terminates a process and frees its resources.
+There is also a 
+.CW "case" 
+statement analogous to C's
+.CW "switch" ,
+but it differs in that it also supports string and range tests,
+and more critically, control flow does not ``flow through'' one arm of the case to another
+but stops without requiring an explicit
+.CW break
+(in that respect it is closer to Pascal's
+.CW case
+statement, hence the change of name).
+A
+.CW "break" 
+or
+.CW "continue" 
+followed by a label
+causes a break out of, or the next iteration of, the enclosing
+construct that is labeled with the same label.
+.LP
+Comments begin with
+.CW "#" 
+and extend to the end of the line.
+There is no preprocessor, but an
+.CW "include" 
+statement can be used to include source code, usually module declaration files.
+.SH
+Libraries:
+.LP
+Limbo has an extensive and growing set of standard libraries,
+each implemented as a module.
+A handful of these
+(notably
+.CW "Sys" ,
+.CW "Draw" ,
+and
+.CW "Tk" )
+are included in the Inferno kernel because they will be
+needed to support almost any Limbo program.
+Among the others are
+.CW "Bufio" ,
+a buffered I/O package based on Plan 9's Bio;
+.CW "Regex" ,
+for regular expressions;
+and
+.CW "Math" ,
+for mathematical functions.
+Some of the examples that follow provide the sort
+of functionality that might be a suitable module.
+.NH 1
+Examples
+.LP
+The examples in this section are each complete, in the sense that they
+will run as presented; I have tried to avoid code fragments
+that merely illustrate syntax.
+.NH 2
+Hello, World
+.LP
+The first example is the traditional ``hello, world'',
+in the file
+.CW "hello.b" :
+.P1
+implement Hello;
+
+include "sys.m";
+	sys: Sys;
+include "draw.m";
+
+Hello: module
+{
+	init:	fn(ctxt: ref Draw->Context, args: list of string);
+};
+
+init(ctxt: ref Draw->Context, args: list of string)
+{
+	sys = load Sys Sys->PATH;
+	sys->print("hello, world\en");
+}
+.P2
+An implementation file implements a single module,
+named in the
+.CW "implement" 
+declaration at the top of the file.
+The two 
+.CW "include" 
+lines copy interface definitions from two other modules,
+.CW "Sys" 
+(which describes a variety of system functions like
+.CW "print" ),
+and
+.CW "Draw" 
+(which describes a variety of graphics types and functions,
+only one of which,
+.CW "Context" ,
+is used here).
+.LP
+The 
+.CW "module" 
+declaration defines the external interface that this module
+presents to the rest of the world.
+In this case, it's a single function named
+.CW "init" .
+Since this module is to be called from a command interpreter
+(shell), by convention its 
+.CW "init" 
+function takes two arguments,
+the graphical context
+and a list of strings, the command-line arguments,
+though neither is used here.
+This is like
+.CW "main" 
+in a C program.
+Essentially all of the other examples begin with this standard code.
+Commands are unusual, though, in that a command's module declaration
+appears in the same file as its implementation.
+.LP
+Most modules have a more extensive set of declarations; for example, 
+.CW "draw.m" 
+is 298 lines of constants, function prototypes, and
+type declarations for graphics types like
+.CW "Point" 
+and 
+.CW "Rect" ,
+and
+.CW "sys.m" 
+is 160 lines of declarations for functions like
+.CW "open" ,
+.CW "read" ,
+and
+.CW "print" .
+Most module declarations are therefore stored in separate files,
+conventionally suffixed with
+.CW ".m" ,
+so they can be included in other modules.
+The system library module declaration files are collected in the
+.CW module
+directory at the root of the Inferno source tree.
+Modules that are components of a single program are typically
+stored in that program's source directory.
+.LP
+The last few lines of
+.CW "hello.b" 
+are the implementation of the
+.CW "init" 
+function, which loads the
+.CW "Sys" 
+module, then calls its 
+.CW "print" 
+function.
+By convention, each module declaration includes a pathname constant
+that points to the code for the module; this is the second parameter
+.CW "Sys->PATH" 
+of the
+.CW "load" 
+statement.
+Note that the
+.CW Draw
+module is not loaded because none of its functions is used, but
+it is included to define the type
+.CW Draw->Context .
+.SH
+Compiling and Running Limbo Programs
+.LP
+With this much of the language described,
+we can compile and run this program.
+On Unix or Windows, the command
+.P1
+$ limbo -g hello.b
+.P2
+creates
+.CW "hello.dis" ,
+a byte-coded version of the program for the Dis
+virtual machine.
+The
+.CW "-g" 
+argument adds a symbol table, useful for subsequent debugging.
+(Another common option is
+.CW -w ,
+which causes the compiler to produce helpful warnings about possible errors.)
+The program can then be run as
+.CW "hello" 
+in Inferno; this shows execution under the Inferno emulator
+on a Unix system:
+.P1
+$ limbo -g hello.b
+$ emu
+; /usr/bwk/hello
+hello, world
+; 
+.P2
+From within Inferno, it's also possible to run a
+program by selecting it from a menu.
+In any case, as the program runs, it loads as necessary other modules that it uses.
+.NH 2
+A Graphical "Hello World"
+.LP
+The following module creates and displays a window containing only
+a button with the label ``hello, world'' as shown in the screen shot in Figure 1.
+.P1
+implement Hello2;
+
+include "sys.m";
+	sys: Sys;
+include "draw.m";
+	draw: Draw;
+include "tk.m";
+	tk: Tk;
+include "tkclient.m";
+	tkclient: Tkclient;
+
+Hello2: module
+{
+        init:   fn(ctxt: ref Draw->Context, args: list of string);
+};
+
+init(ctxt: ref Draw->Context, args: list of string)
+{
+	sys = load Sys Sys->PATH;
+	tk = load Tk Tk->PATH;
+	tkclient = load Tkclient Tkclient->PATH;
+
+	tkclient->init();
+
+	(t, nil) := tkclient->toplevel(ctxt, "", "Hello", Tkclient->Plain);
+
+	tk->cmd(t, "button .b -text {hello, world}");
+	tk->cmd(t, "pack .b");
+	tk->cmd(t, "update");
+
+	tkclient->onscreen(t, nil);
+
+	sys->sleep(10000);	# wait 10 seconds
+}
+.P2
+.FG "f1.ps" 3i
+.ce
+.I "Figure 1.  `Hello, world' button."
+.fg
+This is not very exciting, but it illustrates the absolute
+minimum required to get a picture on the screen.
+The
+.CW "Tk" 
+module is modeled closely after John Ousterhout's Tk interface toolkit,
+but Limbo is used as the programming language instead of Tcl.
+The Inferno version
+is similar in functionality to the original Tk
+but it does not support any Tcl constructs,
+such as variables, procedures, or expression evaluation,
+since all processing is done using Limbo.
+There are ten functions in the
+.CW "Tk" 
+interface, only one of which
+is used here:
+.CW "cmd" ,
+which executes a command string.
+(It is the most commonly used
+.CW Tk
+function.)
+.LP
+Tk itself displays graphics and handles mouse and keyboard interaction
+within a window.
+There can however be many different windows on a display.
+A separate window manager,
+.CW wm ,
+multiplexes control of input and output among those windows.
+The module
+.CW Tkclient
+provides the interface between the window manager and Tk.
+Its function
+.CW "toplevel" ,
+used above,
+makes a top-level window and returns a reference to it, for subsequent use by Tk.
+The contents of the window are prepared by calls to
+.CW tk->cmd
+before the window is finally displayed by the call to
+.CW onscreen .
+(The second parameter to
+.CW onscreen ,
+a string,
+controls the position and style of window;
+here we take the default by making that
+.CW nil .)
+.LP
+Note that
+.CW Tkclient
+must also be explicitly initialized by calling its
+.CW init
+function after loading.
+This is a common convention, although some modules do
+not require it (typically those built in
+to the system, such as
+.CW Sys
+or
+.CW Tk ).
+.LP
+The
+.CW "sleep" 
+delays exit for 10 seconds so the button can be seen.
+If you try to interact with the window, for instance by pressing the button,
+you will see no response.
+That is because the program has not done what is required to receive mouse or keyboard input in the window.
+In a real application, some action would also be bound to pressing the button.
+Such actions are handled by setting up a connection (a `channel') from
+the Tk module to one's own code, and processing the
+messages (`events') that appear on this channel.
+The Tk module and its interface to the window manager
+is explained in more detail later,
+as are a couple of other constructions,
+after we have introduced processes and channels.
+.NH 2
+Echo
+.LP
+The next example,
+.CW "echo" ,
+prints its command-line arguments.
+Declarations are the same as in the first 
+example, and have been omitted.
+.P1
+# declarations omitted...
+
+init(ctxt: ref Draw->Context, args: list of string)
+{
+	sys = load Sys Sys->PATH;
+
+	args = tl args;		# skip over program name
+	for (s := ""; args != nil; args = tl args)
+		s += " " + hd args;
+	if (s != "")		# something was stored in s
+		sys->print("%s\en", s[1:]);
+}
+.P2
+The arguments are stored in a 
+.CW "list" .
+Lists may be of any type;
+.CW "args" 
+is a
+.CW "list" 
+.CW "of" 
+.CW "string" .
+There are three list operators:
+.CW "hd" 
+and
+.CW "tl" 
+return the head and tail of a list, and
+.CW "::" 
+adds a new element to the head.
+In this example, the
+.CW "for" 
+loop walks along the
+.CW "args" 
+list until the end,
+printing the head element
+.CW "hd args" ), (
+then advancing
+.CW "args = tl args" ). (
+.LP
+The value
+.CW "nil" 
+is the ``undefined'' or ``explicitly empty'' value
+for non-numeric types.
+.LP
+The operator
+.CW ":=" 
+combines the declaration of a variable and assignment of a value to it.
+The type of the variable on the left of
+.CW ":=" 
+is the type
+of the expression on the right.
+Thus, the expression
+.P1
+s := ""
+.P2
+in the 
+.CW "for" 
+statement
+declares a string
+.CW "s" 
+and initializes it to empty;
+if after the loop,
+.CW "s" 
+is not empty,
+something has been written in it.
+By the way, there is no distinction between the values
+.CW "nil" 
+and
+\f5""\fP
+for strings.
+.LP
+The
+.CW "+" 
+and
+.CW "+=" 
+operators concatenate strings.
+The expression
+.CW "s[1:]" 
+is a
+.I slice
+of the string
+.CW "s" 
+that starts at index 1
+(the second character of the string) and goes
+to the end; this excludes the unwanted
+blank at the beginning of
+.CW "s" .
+.NH 2
+Word Count
+.LP
+The word count program
+.CW "wc" 
+reads its standard input
+and counts the number of lines, words, and characters.
+Declarations have again been omitted.
+.P1
+# declarations omitted...
+
+init(nil: ref Draw->Context, args: list of string)
+{
+	sys = load Sys Sys->PATH;
+	buf := array[1] of byte;
+
+	stdin := sys->fildes(0);
+
+	OUT: con 0;
+	IN: con 1;
+
+	state := OUT;
+	nl := 0; nw := 0; nc := 0;
+	for (;;) {
+		n := sys->read(stdin, buf, 1);
+		if (n <= 0)
+			break;
+		c := int buf[0];
+		nc++;
+		if (c == '\en')
+			nl++;
+		if (c == ' ' || c == '\et' || c == '\en')
+			state = OUT;
+		else if (state == OUT) {
+			state = IN;
+			nw++;
+		}
+	}
+	sys->print("%d %d %d\en", nl, nw, nc);
+}
+.P2
+.LP
+This program contains several instances of the
+.CW ":=" 
+operator.
+For example, the line
+.P1
+	nl := 0; nw := 0; nc := 0;
+.P2
+declares three integer variables
+and assigns zero to each.
+.LP
+A Limbo program starts with three open files for standard
+input, standard output, and standard error, as in Unix.
+The line
+.P1
+	stdin := sys->fildes(0);
+.P2
+declares a variable
+.CW "stdin" 
+and assigns the corresponding file descriptor to it.
+The type of
+.CW "stdin" 
+is whatever the type of
+.CW "sys->fildes(0)" 
+is, and it's possible to get by without
+ever knowing the name of that type.
+(We will return to this shortly.)
+.NE 3v
+.LP
+The lines
+.P1
+        OUT: con 0;
+        IN: con 1;
+.P2
+declare two integer constants with values zero and one.
+There is no
+.CW "enum" 
+type in Limbo; the
+.CW "con" 
+declaration is the closest equivalent.
+When the values are arbitrary, a different form is normally used:
+.P1
+	OUT, IN: con iota;
+.P2
+The operator
+.CW "iota" ,
+when used in
+.CW con
+declarations will produce the sequence of values 0, 1, ....,
+one value in turn for each name declared in the same declaration.
+It can appear in more complex expressions:
+.P1
+	M1, M2, M4, M8: con 1 << iota;
+	N1, N3, N5, N7: con (2*iota)+1;
+.P2
+The first example generates a set of bitmask values; the second generates a
+sequence of odd numbers.
+.LP
+Given the declarations of
+.CW "IN" 
+and
+.CW "OUT" ,
+the line
+.P1
+	state := OUT;
+.P2
+declares 
+.CW "state" 
+to be an integer with initial value zero.
+.LP
+The line
+.P1
+        buf := array[1] of byte;
+.P2
+declares 
+.CW "buf" 
+to be a one-element array of 
+.CW "byte" s.
+Arrays are indexed from zero, so
+.CW "buf[0]" 
+is the only element.
+Arrays in Limbo are dynamic, so this array is created at
+the point of the declaration.
+An alternative would be to declare the array and
+create it in separate statements:
+.P1
+	buf : array of byte;	# no size at declaration
+
+	buf = array[1] of byte;	# size needed at creation
+.P2
+.LP
+Limbo does no automatic coercions between types,
+so an explicit coercion is required to convert the
+single byte read from 
+.CW "stdin" 
+into an
+.CW "int" 
+that can be used in subsequent comparisons with
+.CW "int" 's;
+this is done by the line
+.P1
+	c := int buf[0];
+.P2
+which declares
+.CW "c" 
+and assigns the integer value of the input byte to it.
+.NH 2
+Word Count Version 2
+.LP
+The word count program above tacitly assumes that its input is
+in the ASCII subset of Unicode, since it reads
+input one byte at a time instead of one Unicode character
+at a time.
+If the input contains any multi-byte Unicode characters,
+this code is plain wrong.
+The assignment to 
+.CW "c" 
+is a specific example: the integer value of the first byte
+of a multi-byte Unicode character is not the character.
+.LP
+There are several ways to address this shortcoming.
+Among the possibilities are
+rewriting to use the
+.CW "Bufio" 
+module, which does string I/O,
+or checking each input byte sequence to see if it is
+a multi-byte character.
+The second version of word counting uses 
+.CW "Bufio" .
+This example will also illustrate rules for accessing objects
+within modules.
+.P1
+# declarations omitted...
+
+include "bufio.m";
+	bufio: Bufio;
+	Iobuf: import bufio;
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+	sys = load Sys Sys->PATH;
+	bufio = load Bufio Bufio->PATH;
+	if (bufio == nil) {
+		sys->fprint(sys->fildes(2), "wc: can't load %s: %r\en", Bufio->PATH);
+		raise "fail:load";
+	}
+
+	stdin := sys->fildes(0);
+	iob := bufio->fopen(stdin, bufio->OREAD);
+	if (iob == nil) {
+		sys->fprint(sys->fildes(2), "wc: can't open stdin: %r\en");
+		raise "fail:open";
+	}
+
+	OUT, IN: con iota;
+
+	state := OUT;
+	nl := big 0; nw := big 0; nc := big 0;
+	for (;;) {
+		c := iob.getc();
+		if (c == Bufio->EOF)
+			break;
+		nc++;
+		if (c == '\en')
+			nl++;
+		if (c == ' ' || c == '\et' || c == '\en')
+			state = OUT;
+		else if (state == OUT) {
+			state = IN;
+			nw++;
+		}
+	}
+	sys->print("%bd %bd %bd\en", nl, nw, nc);
+}
+.P2
+The lines
+.P1
+include "bufio.m";
+	bufio: Bufio;
+.P2
+include the declarations from
+.CW "bufio.m" 
+and declare a variable
+.CW "bufio" 
+that will serve as a handle when we load an implementation of the
+.CW "Bufio" 
+module.
+(The use of a module's type in lower case as the name of a loaded instance is a common convention in Limbo programs.)
+With this handle, we can
+refer to the functions and types
+the module defines, which are in the file
+.CW "/usr/inferno/module/bufio.m"
+(the full name might be different on your system).
+Parts of this declaration are shown here:
+.P1
+Bufio: module	# edited to fit your screen
+{
+	PATH:	con "/dis/bufio.dis";
+	EOF:	con -1;
+	Iobuf: adt {
+		fd:	ref Sys->FD;	# the file
+		buffer:	array of byte;	# the buffer
+					# other variables omitted
+		getc:	fn(b: self ref Iobuf) : int;
+		gets:	fn(b: self ref Iobuf, sep: int) : string;
+		close:	fn(b: self ref Iobuf);
+	};
+	open:	fn(name: string, mode: int) : ref Iobuf;
+	fopen:	fn(fd: ref Sys->FD, mode: int) : ref Iobuf;
+};
+.P2
+.LP
+The
+.CW "bufio" 
+module defines 
+.CW "open" 
+and
+.CW "fopen" 
+functions that return references to an
+.CW "Iobuf" ;
+this is much like a
+.CW "FILE*" 
+in the C standard I/O library.
+A reference is necessary so that all uses
+refer to the same entity, the object maintained by the module.
+.LP
+Given the name of a module (e.g., 
+.CW "Bufio" ),
+how do we refer to its contents?
+It is always possible to use fully-qualified names,
+and the
+.CW "import" 
+statement permits certain abbreviations.
+We must also distinguish between the name of the module itself
+and a specific implementation returned by
+.CW "load" ,
+such as
+.CW "bufio" .
+.LP
+The fully-qualified name of a type or constant from a module
+is
+.P1
+\fIModulename\fP->\fIname\fP
+.P2
+as in
+.CW "Bufio->Iobuf" 
+or
+.CW "Bufio->EOF" .
+To refer to members of an adt or functions or variables from a module, however,
+it is necessary to use a module value instead of a module name:
+although the interface
+is always the same, the implementations of different instances
+of a module will be different, and we must refer to a specific
+implementation.
+A fully-qualified name is
+.P1
+\fImoduleval\fP->\fIfunctionname\fP
+\fImoduleval\fP->\fIvariablename\fP
+\fImoduleval\fP->\fIadtname\fP.\fImembername\fP
+.P2
+where adt members can be variables or functions.
+Thus:
+.P1
+iob: ref bufio->Iobuf;
+...
+bufio->open(...)
+bufio->iob.getc()
+bufio->iob.fd
+.P2
+It is also legal to refer to module types, constants, and variables
+with a module handle, as in
+.CW "bufio->EOF" .
+.LP
+An
+.CW "import" 
+statement makes a specific list of names from
+a module accessible without need for a fully-qualified name.
+Each name must be imported explicitly, and adt member names
+can not be imported.
+Thus, the line
+.P1
+Iobuf: import bufio;
+.P2
+imports the adt name
+.CW "Iobuf" ,
+which means that functions within that adt (like
+.CW "getc)" 
+can be used
+without module qualification, i.e., without
+.CW "bufio->" .
+(It is still necessary to say
+.CW "iob.getc()"
+for reasons given below.)
+In all cases, imported names must be unique.
+.LP
+The second parameter of
+.CW "load" 
+is a string giving the location of the module implementation,
+typically a
+.CW ".dis" 
+file.
+(The string need not be static.)
+Some modules are part of the system;
+these have location names that begin with
+.CW "$" 
+but are otherwise the same for users.
+By convention, modules include a constant called
+.CW "PATH" 
+that points to their default location.
+.LP
+The call to
+.CW "bufio->fopen" 
+attaches the I/O buffer to the already open file
+.CW "stdin" ;
+this is rather like
+.CW "freopen" 
+in
+.CW "stdio" .
+.LP
+The function
+.CW "iob.getc" 
+returns the next Unicode character,
+or
+.CW "bufio->EOF" 
+if end of file was encountered.
+.LP
+A close look at the calls to
+.CW "sys->print" 
+shows a new format conversion character,
+.CW "%r" ,
+for which there is no corresponding argument in the
+expression list.
+The value of
+.CW "%r" 
+is the text of the most recent system error message.
+.LP
+Several other small changes were made as realistic examples:
+it keeps the counts as
+.CW big
+to cope with larger files (hence the use of
+.CW %bd
+as the output format);
+it prints diagnostics on the standard error stream,
+.CW sys->fildes(2) ,
+using
+.CW sys->fprint ,
+a variant of
+.CW sys->print
+that takes an explicit file descriptor;
+and it returns an error status to its caller (typically the shell) by
+raising an exception.
+.NH 2
+An Associative Array Module
+.LP
+This section describes a module that implements a conventional
+associative array (a hash table
+pointing to chained lists of name-value strings).
+This module is meant to be part of a larger program,
+not a standalone program like the previous examples.
+.LP
+The 
+.CW "Hashtab" 
+module stores a name-value pair as a tuple of
+.CW "(string," 
+.CW "string)" .
+A tuple is a type consisting of an ordered collection
+of objects, each with its own type.
+The hash table implementation uses several different tuples.
+.LP
+The hash table module defines a type to hold the
+data, using an
+.CW "adt" 
+declaration.
+An adt defines a type and optionally a set of functions 
+that manipulate an object of that type.
+Since it provides only the ability to group variables and functions, 
+it is like a really slimmed-down version of a C++ class,
+or a slightly fancier C
+.CW "struct" .
+In particular, an adt does not provide information hiding
+(all member names are visible if the adt itself is visible),
+does not support inheritance,
+and has no constructors, destructors or overloaded method names.
+It is different from C or C++, however: when an adt is declared by a
+.CW module
+declaration, the adt's implementation (the bodies of its functions)
+will be defined by the module's implementation, and there can be more than one.
+To create an instance of an adt,
+.P1
+\fIadtvar\fP := \fIadtname\fP(\fIlist of values for all members, in order\fP);
+\fIadtvar\fP := ref \fIadtname\fP(\fIlist of values for all members, in order\fP);
+.P2
+Technically these are casts, from tuple to adt;
+that is, the adt is created from a tuple that
+specifies all of its members in order.
+.LP
+The 
+.CW "Hashtab" 
+module contains an
+.CW "adt" 
+declaration for a type
+.CW "Table" ;
+the operations are a function
+.CW "alloc" 
+for initial allocation
+(in effect a constructor),
+a hash function, and methods to add and look up elements by name.
+Here is the module declaration, which is contained in file
+.CW "hashtab.m" :
+.nr dT 4
+.nr dP \n(dP+1
+.P1
+Hashtab: module
+{
+	PATH:	con "/usr/bwk/hashtab.dis";  # temporary name
+
+	Table: adt {
+		tab: array of list of (string, string);
+
+		alloc: fn(n: int) : ref Table;
+
+		hash: fn(ht: self ref Table, name: string) : int;
+		add: fn(ht: self ref Table, name: string, val: string);
+		lookup: fn(ht: self ref Table, name: string) : (int, string);
+	};
+};
+.P2
+.nr dT 8
+.nr dP \n(dP-1
+The implementation is in file
+.CW "hashtab.b" :
+.P1
+implement Hashtab;
+
+include "hashtab.m";
+
+Table.alloc(n: int) : ref Table
+{
+	return ref Table(array[n] of list of (string,string));
+}
+
+Table.hash(ht: self ref Table, s: string) : int
+{
+	h := 0;
+	for (i := 0; i < len s; i++)
+		h = (h << 1) ^ int s[i];
+	h %= len ht.tab;
+	if (h < 0)
+		h += len ht.tab;
+	return h;
+}
+
+Table.add(ht: self ref Table, name: string, val: string)
+{
+	h := ht.hash(name);
+	for (p := ht.tab[h]; p != nil; p = tl p) {
+		(tname, nil) := hd p;
+		if (tname == name) {
+			# illegal: hd p = (tname, val);
+			return;
+		}
+	}
+	ht.tab[h] = (name, val) :: ht.tab[h];
+}
+
+Table.lookup(ht: self ref Table, name: string) : (int, string)
+{
+	h := ht.hash(name);
+	for (p := ht.tab[h]; p != nil; p = tl p) {
+		(tname, tval) := hd p;
+		if (tname == name)
+			return (1, tval);
+	}
+	return (0, "");
+}
+
+.P2
+This is intentionally simple-minded, to focus on the language
+rather than efficiency or flexibility.
+The function
+.CW "Table.alloc" 
+creates and returns a 
+.CW "Table" 
+with a specified size and an array of elements,
+each of which is a list of
+.CW "(string," 
+.CW "string)" .
+.LP
+The
+.CW "hash" 
+function is trivial; the only interesting point
+is the
+.CW "len" 
+operator, which returns the number of items in a string, array or list.
+For a string, 
+.CW "len" 
+.CW "s" 
+is the number of Unicode characters.
+.LP
+The
+.CW "self" 
+declaration says that the first
+argument of every call of this function is implicit, and refers to the
+value itself; this argument does not appear in the actual parameter list at any call site.
+.CW "Self" 
+is similar to
+.CW "this" 
+in C++.
+.LP
+The 
+.CW "lookup" 
+function searches down the appropriate list for
+an instance of the
+.CW "name" 
+argument.
+If a match is found, 
+.CW "lookup" 
+returns a tuple consisting of 1 and the value field;
+if no match is found, it returns a tuple of 0 and an empty string.
+These return types match the function return type,
+.CW "(int," 
+.CW "string)" .
+.LP
+The line
+.P1
+	(tname, tval) := hd p;
+.P2
+shows a tuple on the left side of a declaration-assignment.
+This splits the pair of strings referred to by
+.CW "hd" 
+.CW "p" 
+into components and assigns them to the newly declared variables
+.CW "tname" 
+and 
+.CW "tval" .
+.LP
+The
+.CW "add" 
+function is similar;
+it searches the right list for an instance of
+the name.
+If none is found,
+.P1
+	ht.tab[h] = (name, val) :: ht.tab[h];
+.P2
+combines the name and value into a tuple, then uses
+.CW "::" 
+to stick it on the front of the proper list.
+.LP
+The line
+.P1
+	(tname, nil) := hd p;
+.P2
+in the loop body is a less obvious use of a tuple.
+In this case, only the first component, the name,
+is assigned, to a variable
+.CW "tname" 
+that is declared here.
+The other component is ``assigned'' to 
+.CW "nil" ,
+which causes it to be ignored.
+.LP
+The line
+.P1
+	# illegal: hd p = (tname, val);
+.P2
+is commented out because it's illegal:
+Limbo does not permit the assignment of a new name-value
+to a list element;
+list elements are immutable.
+.LP
+To create a new 
+.CW "Table" ,
+add some values, then retrieve one, we can write:
+.P1
+	nvtab = Table.alloc(101);	# make a Table
+
+	nvtab.add("Rob", "Pike");
+	nvtab.add("Howard", "Trickey");
+	(p, phil) := nvtab.lookup("Phil");
+	(q, sean) := nvtab.lookup("Sean");
+.P2
+Note that the
+.CW "ref" 
+.CW "Table" 
+argument does not appear in these calls;
+the
+.CW "self" 
+mechanism renders it unnecessary.
+Remember that a module using
+.CW Table
+must
+.CW import
+it from some instance of
+.CW Hashtab ,
+or qualify all references to it by a module value.
+.NH 2
+An AWK-like Input Module
+.LP
+This example presents a simple module based on Awk's input mechanism:
+it reads input a line at a time from a list of of files,
+splits each line into an array of
+.CW "NF+1" 
+strings (the original input line and the individual fields), and
+sets
+.CW "NF" ,
+.CW "NR" ,
+and
+.CW "FILENAME" .
+It comes in the usual two parts, a module:
+.P1
+.nr dP \n(dP+1
+.nr dT 4
+Awk: module
+{
+	PATH:		con "/usr/bwk/awk.dis";
+
+	init:		fn(args: list of string);
+	getline:	fn() : array of string;
+	NR:		fn() : int;
+	NF:		fn() : int;
+	FILENAME:	fn() : string;
+};
+.P2
+.nr dP \n(dP-1
+.nr dT 8
+and an implementation:
+.nr dP \n(dP+1
+.nr dT 4
+.P1
+implement Awk;
+
+include "sys.m";
+	sys:	Sys;
+include "bufio.m";
+	bufio: Bufio;
+Iobuf: import bufio;
+	iobuf:	ref Iobuf;
+
+include "awk.m";
+
+_NR:		int;
+_NF:		int;
+_FILENAME:	string;
+args:		list of string;
+
+.P3
+init(av: list of string)
+{
+	args = tl av;
+	if (len args == 0)	# no args => stdin
+		args = "-" :: nil;
+
+	sys = load Sys Sys->PATH;
+	bufio = load Bufio Bufio->PATH;
+}
+
+.P3
+getline() : array of string
+{
+	t := array[100] of string;
+	fl: list of string;
+
+  top:
+	while (args != nil) {
+		if (_FILENAME == nil) {	# advance to next file
+			_FILENAME = hd args;
+			if (_FILENAME == "-")
+				iobuf = bufio->fopen(sys->fildes(0), bufio->OREAD);
+			else
+				iobuf = bufio->open(_FILENAME, bufio->OREAD);
+			if (iobuf == nil) {
+				sys->fprint(sys->fildes(2), "can't open %s: %r\en", _FILENAME);
+				args = nil;
+				return nil;
+			}
+		}
+
+.P3
+		s := iobuf.gets('\en');
+		if (s == nil) {
+			iobuf.close();
+			_FILENAME = nil;
+			args = tl args;
+			continue top;
+		}
+
+.P3
+		t[0] = s[0:len s - 1];
+		_NR++;
+		(_NF, fl) = sys->tokenize(t[0], " \et\en\er");
+		for (i := 1; fl != nil; fl = tl fl)
+			t[i++] = hd fl;
+		return t[0:i];
+	}
+	return nil;
+}
+
+NR() : int  { return _NR; }
+NF() : int  { return _NF; }
+FILENAME() : string { return _FILENAME; }
+.P2
+.nr dT 8
+.nr dP \n(dP-1
+Since 
+.CW "NR" ,
+.CW "NF" 
+and
+.CW "FILENAME" 
+should not be modified by users, they
+are accessed as functions; the actual variables have
+related names like
+.CW "_NF" .
+It would also be possible to make them ordinary variables
+in the 
+.CW "Awk" 
+module, and refer to them via a module value (i.e.,
+.CW awk->NR ).
+.LP
+The 
+.CW "tokenize" 
+function in the line
+.P1
+	(_NF, fl) = sys->tokenize(t[0], " \et\en\er");
+.P2
+breaks the argument string
+.CW "t[0]" 
+into tokens, as separated by the characters of the second argument.
+It returns a tuple consisting of a length and a list
+of tokens.
+Note that this module has an
+.CW "init" 
+function that must be called explicitly before
+any of its other functions are called.
+.NH 2
+A Simple Formatter
+.LP
+This program is a simple-minded text formatter, modeled after
+.CW "fmt" ,
+that tests the Awk module:
+.P1
+implement Fmt;
+
+include "sys.m";
+	sys: Sys;
+include "draw.m";
+
+Fmt: module
+{
+	init:	fn(nil: ref Draw->Context, args: list of string);
+};
+
+include "awk.m";
+	awk: Awk;
+	getline, NF: import awk;
+
+out:	array of string;
+nout:	int;
+length: int;
+linelen := 65;
+
+.P3
+init(nil: ref Draw->Context, args: list of string)
+{
+	t: array of string;
+	out = array[100] of string;
+
+	sys = load Sys Sys->PATH;
+	awk = load Awk Awk->PATH;
+	if (awk == nil) {
+		sys->fprint(sys->fildes(2), "fmt: can't load %s: %r\en",
+			Awk->PATH);
+		raise "fail:load";
+	}
+	awk->init(args);
+
+	nout = 0;
+	length = 0;
+	while ((t = getline()) != nil) {
+		nf := NF();
+		if (nf == 0) {
+			printline();
+			sys->print("\en");
+		} else for (i := 1; i <= nf; i++) {
+			if (length + len t[i] > linelen)
+				printline();
+			out[nout++] = t[i];
+			length += len t[i] + 1;
+		}
+	}
+	printline();
+}
+.P3
+printline()
+{
+	if (nout == 0)
+		return;
+	for (i := 0; i < nout-1; i++)
+		sys->print("%s ", out[i]);
+	sys->print("%s\en", out[i]);
+	nout = 0;
+	length = 0;
+}
+.P2
+The functions
+.CW "getline" 
+and
+.CW "NF" 
+have been imported so their names need no qualification.
+It is more usual Limbo style to use explicit references such as
+.CW sys->read
+or
+.CW Bufio->EOF
+for clarity, and import only adts (and perhaps commonly used constants).
+.NH 2
+Channels and Communications
+.LP
+Another approach to a formatter is to use one process to fetch words and 
+pass them to another process that formats and prints them.
+This is easily done with a channel, as in this
+alternative version:
+.P1
+# declarations omitted...
+
+WORD, BREAK, EOF: con iota;
+wds: chan of (int, string);
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+	sys = load Sys Sys->PATH;
+	bufio = load Bufio Bufio->PATH;
+
+	stdin := sys->fildes(0);
+	iob = bufio->fopen(stdin, bufio->OREAD);
+
+	wds = chan of (int, string);
+	spawn getword(wds);
+	putword(wds);
+}
+
+.P3
+getword(wds: chan of (int, string))
+{
+	while ((s := iob.gets('\en')) != nil) {
+		(n, fl) := sys->tokenize(s, " \et\en");
+		if (n == 0)
+			wds <-= (BREAK, "");
+		else for ( ; fl != nil; fl = tl fl)
+			wds <-= (WORD, hd fl);
+	}
+	wds <-= (EOF, "");
+}
+
+.P3
+putword(wds: chan of (int, string))
+{
+	for (length := 0;;) {
+		(wd, s) := <-wds;
+		case wd {
+		BREAK =>
+			sys->print("\en\en");
+			length = 0;
+		WORD =>
+			if (length + len s > 65) {
+				sys->print("\en");
+				length = 0;
+			}
+			sys->print("%s ", s);
+			length += len s + 1;
+		EOF =>
+			sys->print("\en");
+			exit;
+		}
+	}
+}
+.P2
+This omits declarations and error checking in the interest
+of brevity.
+.LP
+The channel passes a tuple of
+.CW "int" , (
+.CW "string" );
+the
+.CW "int" 
+indicates what kind of string is present \-
+a real word, a break caused by an empty input line,
+or
+.CW "EOF" .
+.LP
+The
+.CW "spawn" 
+statement creates a separate process by calling the specified function;
+except for its own stack,
+this process shares memory with the process that spawned it.
+Any synchronization between processes is handled by channels.
+.LP
+The operator
+.CW "<-=" 
+sends an expression to a channel;
+the operator
+.CW "<-" 
+receives from a channel.
+(Receive is combined here with
+.CW ":="
+to receive a tuple, and assign its elements to newly-declared variables.)
+In this example, 
+.CW "getword" 
+and
+.CW "putword" 
+alternate, because each input word
+is sent immediately on the shared channel,
+and no subsequent word is processed until the previous one has been
+received and printed.
+.LP
+The 
+.CW "case" 
+statement consists of a list of case values,
+which must be string or numeric constants, followed by
+.CW "=>" 
+and associated code.
+The value 
+.CW "*" 
+(not used here) labels the default.
+Multiple labels can be used, separated by the
+.CW "or" 
+operator,
+and ranges of values can appear delimited by
+.CW "to" ,
+as in
+.P1
+	'a' to 'z' or 'A' to 'Z' =>
+.P2
+Remember that control does not flow from one case arm to the next, unlike C,
+thus no
+.CW break
+statements appear.
+.NH 2
+Tk and Interface Construction
+.LP
+Inferno supports a rather complete implementation of
+the Tk interface toolkit developed by John Ousterhout.
+In other environments, Tk is normally accessed from
+Tcl programs, although there are also versions for Perl,
+Scheme and other languages that call Ousterhout's C code.
+The Inferno Tk was implemented from scratch, and is meant to be called
+from Limbo programs.
+As we saw earlier,
+there is a module declaration
+.CW "tk.m" 
+and a kernel module 
+.CW "Tk" .
+.LP
+The
+.CW "Tk" 
+module provides all the widgets of the original Tk
+with almost all their options,
+the 
+.CW "pack" 
+command for geometry management,
+and the
+.CW "bind" 
+command for attaching code to user actions.
+It also provides a
+.CW grid
+command to simplify the common case of objects arranged in a matrix or grid.
+In this implementation
+.CW "Tk" 
+commands are
+written as strings and presented to one function,
+.CW "tk->cmd" ;
+Limbo calls this function and captures
+its return value, which is the string that the Tk command produces.
+For example, widget creation commands like
+.CW "button" 
+return the widget name, so this will be the string
+returned by
+.CW "tk->cmd" .
+.LP
+There is one unconventional aspect:
+the use of channels to send data and events from the interface
+into the Limbo program.
+To create a widget, as we saw earlier, one writes
+.P1
+tk->cmd("button .b -text {Push me} -command {send cmd .bpush}");
+.P2
+to create a button
+.CW ".b" 
+and attach a command to be executed when the button is pushed.
+That command sends
+the (arbitrary) string
+.CW ".bpush" 
+on the channel named
+.CW "cmd" .
+The Limbo code that reads from this channel will look
+for the string
+.CW ".bpush" 
+and act accordingly.
+The function
+.CW "tk->namechan" 
+establishes a correspondence between a Limbo channel value
+and a channel named as a string in the Tk module.
+When an event occurs in a Tk widget with a
+.CW "-command" 
+option,
+.CW "send" 
+causes the string to be sent on the channel and the Limbo code
+can act on it.
+The program will often use a
+.CW "case" 
+to process the strings that might appear on the channel,
+particularly when the same channel is used for several widgets.
+.LP
+We observed earlier that
+.CW Tk
+provides a user interface for an application's window,
+but there might be many windows on the screen.
+Normally, a graphical application is meant to run under
+the window manager
+.CW "wm" 
+as a window that can be managed,
+reshaped, etc.
+This is done by calling functions in the module
+.CW "Tkclient" ,
+which provides the interface between
+.CW Tk
+and
+.CW wm .
+.LP
+Several functions must be called to create a window,
+put it on the screen, and start giving it input.
+We have already seen
+.CW Tkclient 's
+.CW toplevel
+for window creation and
+.CW onscreen
+to give a window space on the screen.
+Input arrives from several sources:
+from the mouse and keyboard, from the
+higher-level Tk widgets such as buttons,
+and from the window manager itself.
+In Limbo, each input source is represented by a channel, either given to the program
+by the window manager, or associated with one by
+.CW namechan ,
+as above.
+.LP
+This is all illustrated in the complete program below, which
+implements a trivial version of Etch-a-Sketch, shown in action in Figure 2.
+.FG "f3.ps" 4.8i
+.ce
+.I "Figure 2. Etch-a-Sketch display."
+.fg
+.nr dT 4
+.nr dP \n(dP+1
+.P1
+implement Etch;
+
+include "sys.m";
+	sys: Sys;
+include "draw.m";
+include "tk.m";
+	tk: Tk;
+include "tkclient.m";
+	tkclient: Tkclient;
+
+Etch: module
+{
+        init:   fn(ctxt: ref Draw->Context, args: list of string);
+};
+.P3
+init(ctxt: ref Draw->Context, nil: list of string)
+{
+	sys = load Sys Sys->PATH;
+	tk = load Tk Tk->PATH;
+	tkclient = load Tkclient Tkclient->PATH;
+
+	tkclient->init();
+
+	(t, winctl) := tkclient->toplevel(ctxt, nil, "Etch", Tkclient->Appl);
+
+	cmd := chan of string;
+	tk->namechan(t, cmd, "cmd");
+	tk->cmd(t, "canvas .c -height 400 -width 600 -background white");
+	tk->cmd(t, "frame .f");
+	tk->cmd(t, "button .f.c -text {Clear} -command {send cmd clear}");
+	tk->cmd(t, "button .f.d -text {Done} -command {send cmd quit}");
+	tk->cmd(t, "pack .f.c .f.d -side left -fill x -expand 1");
+	tk->cmd(t, "pack .c .f -side top -fill x");
+	tk->cmd(t, "bind .c <ButtonPress-1> {send cmd b1down %x %y}");
+	tk->cmd(t, "bind .c <Button-1-Motion> {send cmd b1motion %x %y}");
+	tk->cmd(t, "update");
+
+	tkclient->startinput(t, "ptr" :: "kbd" :: nil);
+	tkclient->onscreen(t, nil);
+
+	lastx, lasty: int;
+	for (;;) {
+		alt {
+	    	s := <-cmd =>
+			(nil, cmdstr) := sys->tokenize(s, " \et\en");
+			case hd cmdstr {
+			"quit" =>
+				exit;
+			"clear" =>
+				tk->cmd(t, ".c delete all; update");
+			"b1down" =>
+				lastx = int hd tl cmdstr;
+				lasty = int hd tl tl cmdstr;
+				cstr := sys->sprint(".c create line %d %d %d %d -width 2",
+					lastx, lasty, lastx, lasty);
+				tk->cmd(t, cstr);
+			"b1motion" =>
+				x := int hd tl cmdstr;
+				y := int hd tl tl cmdstr;
+				cstr := sys->sprint(".c create line %d %d %d %d -width 2",
+					lastx, lasty, x, y);
+				tk->cmd(t, cstr);
+				lastx = x; lasty = y;
+			}
+
+		p := <-t.ctxt.ptr =>
+			tk->pointer(t, *p);
+
+		c := <-t.ctxt.kbd =>
+			tk->keyboard(t, c);
+
+		ctl := <-winctl or
+		ctl = <-t.ctxt.ctl or
+		ctl = <-t.wreq =>
+			tkclient->wmctl(t, ctl);
+ 		}
+		tk->cmd(t, "update");
+	}
+}
+.P2
+.nr dT 8
+.nr dP \n(dP-1
+.LP
+The function
+.CW "toplevel" 
+returns a tuple containing the
+.CW Tk->Toplevel
+for the new window and a channel upon which the
+window manager will send messages for events such as
+hitting the exit button.
+An earlier example assigned the channel value to
+.CW nil ,
+discarding it; here it is assigned the name
+.CW winctl .
+The parameters to
+.CW toplevel
+includes a graphics context
+.CW ctxt
+where the window will be created,
+a configuration string (simply
+.CW nil
+here),
+the program name (which appears in the window's ``title bar'' if it has one),
+and a value
+.CW Tkclient->Appl
+that denotes a style of window suitable for most applications.
+Note that
+.CW ctxt
+was one of the arguments to
+.CW init .
+(We do not use the argument list for
+.CW init ,
+and so declare it as
+.CW nil ).
+.LP
+The program creates a canvas for drawing,
+a button to clear the canvas, and a button to quit.
+The sequence of calls to
+.CW "tk->cmd" 
+creates the picture and sets up the bindings.
+The buttons are created with a
+.CW -command
+to send a suitable string on channel
+.CW cmd ,
+and two
+.CW bind
+commands make the same channel the target
+for messages about mouse button presses and movement in the canvas.
+Note the
+.CW %x
+and
+.CW %y
+parameters in the latter case to include the mouse's coordinates in the string.
+.LP
+The window manager sends keyboard and mouse input
+to the currently selected window using two more channels
+.CW t.ctxt.kbd
+and
+.CW t.ctxt.ptr .
+A further channel
+.CW t.wreq
+is used by the
+.CW Tk
+module itself to request changes to the window displaying
+.CW Toplevel
+.CW t .
+.LP
+Now there are many channels watching events:
+one for the buttons and canvas created by the drawing program
+itself, one for the mouse,
+and three for window management.
+We use an
+.CW "alt" 
+statement to select from events on any of those channels.
+The expression
+.P1
+s := <-cmd
+.P2
+declares a variable 
+.CW "s" 
+of the type carried by the channel
+.CW "cmd" ,
+i.e., a
+.CW "string" ;
+when a string is received on the channel, the assignment is executed,
+and the subsequent
+.CW case
+decodes the message.
+The channel
+.CW t.ctxt.ptr
+carries references to
+.CW Draw->Pointer
+values, which give the state and position of the pointing device
+(mouse or stylus).
+They are handed as received to
+.CW tk->pointer
+for processing by Tk.
+Similarly, Unicode characters from the keyboard are given to Tk using
+.CW tk->keyboard .
+Internally, Tk hands those values on to the various widgets for processing, possibly
+resulting in messages being sent on one of the other channels.
+Finally, a value received from any of the
+.CW "winctl" ,
+.CW t.ctxt.ctl
+or
+.CW t.wreq
+channels is passed back to
+.CW Tkclient 's
+.CW "wmctl" 
+function to be handled there.
+.LP
+As another example,
+here is the startup code for an implementation of
+Othello, adapted from a Java version
+by Muffy Barkocy, Arthur van Hoff, and Ben Fry.
+.nr dT 4
+.nr dP \n(dP+1
+.P1
+init(ctxt: ref Draw->Context, args: list of string)
+{
+	sys = load Sys Sys->PATH;
+	tk = load Tk Tk->PATH;
+	tkclient = load Tkclient Tkclient->PATH;
+
+	sys->pctl(Sys->NEWPGRP, nil);
+
+	tkclient->init();
+.P3
+	(t, winctl) := tkclient->toplevel(ctxt, nil, "Othello", Tkclient->Appl);
+.P3
+	cmd := chan of string;
+	tk->namechan(t, cmd, "cmd");
+	tk->cmd(t, "canvas .c -height 400 -width 400 -background green");
+	tk->cmd(t, "frame .f");
+	tk->cmd(t, "label .f.l -text {Othello?} -background white");
+	tk->cmd(t, "button .f.c -text {Reset} -command {send cmd Reset}");
+	tk->cmd(t, "button .f.d -text {Quit} -command {send cmd Quit}");
+	tk->cmd(t, "pack .f.l .f.c .f.d -side left -fill x -expand 1");
+	tk->cmd(t, "pack .c .f -side top -fill x");
+	tk->cmd(t, "bind .c <ButtonRelease-1> {send cmd B1up %x %y}");
+
+	for (i := 1; i < 9; i++)
+	for (j := 1; j < 9; j++) {
+		coord := sys->sprint("%d %d %d %d",
+			SQ*i, SQ*j, SQ*(i+1), SQ*(j+1));
+		tk->cmd(t, ".c create rectangle " + coord +
+			" -outline black -width 2");
+	}
+	tk->cmd(t, "update");
+	lasterror(t, "init");
+	tkclient->startinput(t, "ptr" :: "kbd" :: nil);
+	tkclient->onscreen(t, nil);
+
+	board = array[10] of {* => array[10] of int};
+	score = array[10] of {* => array[10] of int};
+	reinit();
+.P3
+	for (;;) {
+		alt {
+		s := <- cmd =>
+			(n, l) := sys->tokenize(s, " \et");
+			case hd l {
+			"Quit" =>
+				exit;
+			"Reset" =>
+				reinit();
+			"B1up" =>
+				x := int hd tl l;
+				y := int hd tl tl l;
+				mouseUp(int x, int y);
+			}
+
+		p := <-t.ctxt.ptr =>
+			tk->pointer(t, *p);
+
+		c := <-t.ctxt.kbd =>
+			tk->keyboard(t, c);
+
+		ctl := <-winctl or
+		ctl = <-t.ctxt.ctl or
+		ctl = <-t.wreq =>
+			tkclient->wmctl(t, ctl);
+ 		}
+	}
+}
+.P2
+.nr dP \n(dP-1
+.nr dT 4
+.FG "f2.ps" 4.8i
+.ce
+.I "Figure 3. Screen shot of Inferno display showing Othello window."
+.fg
+.LP
+If some call to the
+.CW "Tk" 
+module results in an error,
+an error string is made available in a pseudo-variable
+.CW "lasterror" 
+maintained by
+.CW "Tk" .
+When this variable is read, it is reset.
+The function 
+.CW "lasterror" 
+shows how to test and print this variable:
+.P1
+lasterror(t: ref Tk->Toplevel, where: string)
+{
+	s := tk->cmd(t, "variable lasterror");
+	if (s != nil)
+		sys->print("%s: tk error %s\en", where, s);
+}
+.P2
+In general, the Inferno implementation of
+.CW "Tk" 
+does not provide variables except for a few special ones like this.
+The most common instance is a variable that links
+a set of radiobuttons.
+.NH 2
+Acknowledgements
+.LP
+I am very grateful to
+Steven Breitstein,
+Ken Clarkson,
+Sean Dorward,
+Eric Grosse,
+Doug McIlroy,
+Rob Pike,
+Jon Riecke,
+Dennis Ritchie,
+Howard Trickey,
+Phil Winterbottom,
+and
+Margaret Wright
+for explaining mysteries of Limbo and Inferno
+and for valuable suggestions on this paper.
binary files /dev/null b/doc/descent/descent.pdf differ
--- /dev/null
+++ b/doc/descent/mkfile
@@ -1,0 +1,15 @@
+<../fonts.pal
+
+descent.pdf:D:	descent.ps
+
+descent.ps:D:	descent.ms f1.ps f2.ps f3.ps mkfile
+	{echo $FONTS; cat descent.ms} | tbl | troff -mpm -mpictures | dpost >$target
+
+%.ps:	%.gif
+	dpost <$stem.gif >$stem.ps
+
+%.ps:	%.bit
+	aux/p9bitpost -b100 <$stem.bit >$stem.ps
+
+%.pdf: %.ps
+	ps2pdf <$stem.ps >$stem.pdf
--- /dev/null
+++ b/doc/dev.ms
@@ -1,0 +1,497 @@
+.TL
+Program Development under Inferno
+.AU
+Roger Peppé
+rog@vitanuova.com
+.SH
+Introduction
+.PP
+Inferno provides a set of programs that, used in
+combination, provide a powerful development environment
+in which to write Limbo programs.
+.I Limbo (1)
+is the compiler for the Limbo language; there
+are versions that run inside and outside the Inferno
+environment.
+.I Acme (1)
+is an integrated window system and editor, and the
+preferred source-code editing tool within Inferno.
+The Limbo debugger,
+.I wm-debug (1),
+allows interactive inspection of running Limbo programs.
+.I Stack (1)
+allows a quick inspection of the execution stack of a
+currently running process.
+.SH
+Getting started
+.PP
+This document assumes that you have already managed
+to install Inferno and have managed to obtain an Inferno
+window, running the Inferno window manager,
+.I wm (1).
+The document
+\&``Installing Inferno'' in this volume has details on this.
+If running within emu, it is worth giving Inferno
+as large a window as possible, as it cannot be resized later.
+This paper assumes that you are using a three-button mouse, as it is
+not feasible to use Acme without a three-button mouse.
+(if you have a two button mouse with a ``mouse wheel'',
+the wheel can be used as the middle button).
+The first thing to do is to get Acme going. By clicking
+on the Vita Nuova logo at the bottom left of the window,
+you can display a menu naming some preconfigured commands.
+If this has an ``Acme'' entry, then just clicking on that entry
+will start acme. If not, then click on the ``Shell'' entry,
+and type
+.P1
+acme
+.P2
+to start it up. The Acme window should then appear,
+filling most of the screen (the window manager toolbar
+should still be visible).
+.SH
+Acme basics
+.PP
+For a general overview and the rationale behind Acme, see ``Acme:
+A User Interface for Programmers'', elsewhere in this volume,
+and for detailed documentation, see
+.I acme (1).
+The basics are as follows:
+.PP
+Acme windows are text-only and organised into columns.
+A distinctive feature of Acme is that there are no graphical
+title bars to windows; instead, each window (and additionally
+each column, and the whole Acme window itself) has
+a textual
+.I tag ,
+which can be edited at will, and is initially primed to contain
+a few appropriate commands.
+.PP
+An Acme command is just represented by text; any textual
+command word may be executed simply by clicking with the middle
+mouse button on the word. (See ``Acme mouse commands'', below).
+If Acme recognizes the word that has been clicked on
+as one of its internal commands (e.g. Put, Undo), then it will take the appropriate
+action; otherwise it will run the text as a shell command.
+(See
+.I sh (1)).
+.SH
+Acme mouse commands
+.PP
+Mouse usage within Acme is somewhat more versatile
+than in most other window systems. Each of the three
+mouse buttons has its own action, and there are also
+actions bound to
+.I chords
+of mouse buttons (i.e. mouse buttons depressed simultaneously).
+Mouse buttons are numbered from left (1) to right (3).
+Button 1 follows similar conventions to other window systems -
+it selects text; a double click will select a line if at the beginning or end
+of a line, or match brackets if on a bracket character, or select
+a word otherwise.
+Button 2, as mentioned above, executes an
+Acme command; a single click with button 2 will execute
+the single word under the click, otherwise the swept text
+will be executed.
+Button 3 is a general ``look'' operator; if the text under the
+click represents a filename, then Acme will open a new
+window for the file and read it in, otherwise it will search
+within the current window for the next occurrence of the
+text.
+Clicking button 2 or button 3 on some text already selected
+by button 1 causes the click to refer exactly to the text
+selected, rather than gathering likely-looking characters
+from around the click as is the default.
+.PP
+There are two mouse chord sequences which are
+commonly used in Acme (and you will find that some
+other programs in the system also recognise these sequences,
+e.g.
+.I wm-sh (1)).
+They are both available once some text
+has been selected by dragging the mouse with button 1,
+but before the button has been released. At this point,
+touching button 2 will delete the selected text and save
+it in Acme's
+.I snarf
+buffer; clicking button 3 replaces the selected text with the contents
+of the snarf buffer. Before button 1 has been released,
+these two buttons reverse each other's actions, so, for
+example, selecting some text with button 1, keeping button 1
+held down, then clicking button 2 and button 3 in succession,
+will save the selected text in the snarf buffer while leaving the
+original intact.
+The following table summarises the mouse commands in
+Acme:
+.KS
+.TS
+center box;
+l l .
+B1	Select text.
+B2	Execute text.
+B3	Open file or search for text.
+B1-B2	Cut text.
+B1-B3	Paste text.
+B2-B3	Cancel the pending B2 action.
+B3-B2	Cancel the pending B3 action.
+.TE
+.ce
+.I "Acme mouse command summary"
+.KE
+
+.SH
+Scrolling and resizing Acme windows
+.PP
+The scroll bars in Acme are somewhat different from
+conventional scroll bars (including the scroll bars found
+in other parts of Inferno). Clicking, or dragging, with
+button-2 on the scrollbar acts the most like the conventional
+behaviour, namely that the further down the scroll bar
+you click, the further down the file you are shown.
+.PP
+True to form, however, Acme doesn't omit to make
+the other buttons useful: button-1 and button-3
+move backwards and forwards through the file respectively.
+The nearer the top of the scrollbar the mouse, the
+slower the movement. Holding one of these buttons
+down on the scrollbar will cause the scrolling motion
+to auto-repeat, so it is easy to scroll gently through the
+entire file, for instance.
+.PP
+The small square at the top left of each Acme window is
+the handle for resizing the window. Dragging this square
+from one place to another (within Acme) will move the
+window to the new place. A single button click in this square
+will grow the window: button 1 grows it a little bit; button 2
+grows it as much as possible without obscuring the other
+window titles in the column; button 3 grows it so it covers
+the whole column (all other windows in the column are
+obscured).
+.SH
+Creating a new file
+.PP
+All Limbo programs are composed of
+.I modules
+and each module is stored in its own file. To write a Limbo
+program, you need to write at least one module,
+the Limbo
+.I "source file" ,
+which will then be compiled into Dis code which can
+then be run by the Inferno Virtual Machine (VM).
+The first step is to decide where to store the file.
+When Acme starts up, it creates a new window containing
+a list of all the files in the directory in which it was started
+(usually your home directory). As a consequence of the
+mouse rules above, a click of button-3 on any of those
+filenames in that window will open a new window
+showing that file or, if it is a directory, a list of the
+files and directories it contains.
+.PP
+An important aspect in Acme's mouse commands, is
+that the command is interpreted
+.I "relative to the window's current directory",
+where the current directory is determined from
+the filename in the window's tag. For instance,
+Acme commands executed in the tag or body of
+a window on the file
+.CW "/usr/joebloggs/myfile.txt"
+would run in the directory
+.CW /usr/joebloggs .
+.PP
+So, to create a new file in Acme, first open the
+directory in which to create the file. (If this is
+your home directory, then it's probably already on the screen;
+otherwise, you can just type (anywhere) the name of
+the directory, and button-3 click on it. If the directory
+does not exist, then no window will be created.
+Then, within the directory's window or its tag,
+choose a name,
+.I filename ,
+for your file (I'll use
+.CW myprog
+from here on,
+for explanatory convenience)
+, type the text:
+.P1
+New \fIfilename\fP.b
+.P2
+select this text (the Escape key can also be used to highlight
+text that you have just typed), and button-2 click on it.
+This should create a new empty window in which you
+can edit your Limbo source file. It will also create a
+window giving a warning that the file does not
+currently exist - you can get rid of this by clicking
+with button-2 on the text
+.CW Del
+in the tag of that window.
+.SH
+Editing the source file
+.PP
+You can now edit text in the new window.
+Type in the following program:
+.P1
+implement Myprog;
+include "sys.m";
+	sys: Sys;
+include "draw.m";
+
+Myprog: module {
+	init: fn(nil: ref Draw->Context, argv: list of string);
+};
+
+init(nil: ref Draw->Context, argv: list of string)
+{
+	sys = load Sys Sys->PATH;
+	sys->print("Hello, world\en");
+}
+.P2
+When typing it in, note that two new commands have appeared
+in the tag of the new window:
+.CW Put
+and
+.CW Undo .
+.CW Put
+saves the file;
+.CW Undo
+undoes the last change to the file, and successive
+executions of
+.CW Undo
+will move further back in time. In case you move
+too far back accidentally, there is also
+.CW Redo ,
+which redoes a change that you have just undone.
+Changes in the body of any window in Acme can be undone
+this way.
+.PP
+Click with button-2 on the
+.CW Put
+command, and the file is now saved and ready to be
+compiled. If you have problems at this point (say
+Acme complains about not being able to write the
+file), you have probably chosen an inappropriate
+directory, one in which you do not have write permission,
+in which to put the file. In this case you can change the
+name of the file simply by editing its name in the window's
+tag, and clicking on
+.CW Put
+again.
+.SH
+Compiling the source file
+.PP
+Now, you are in a position to compile the Limbo program.
+Although you can execute the Limbo compiler directly
+from the tag of the new file's window, it is usually more
+convenient to do it from a shell window. To start a shell
+window, type
+.CW win '' ``
+at the right of the tag of the new file's window, select
+it, and click with button-2 on it.
+A new window should appear showing a shell prompt (usually
+.CW "; " '' ``
+or
+.CW "% " ''). ``
+At this, you can type any of the commands mentioned
+in Section 1 of the Programmer's Manual.
+Note that, following Acme's usual rule, the shell has
+started up in the same directory as the new file;
+typing
+.P1
+lc
+.P2
+at the prompt will show all the files in the directory,
+including hopefully the newly written Limbo file.
+.PP
+Type the following command to the shell:
+.P1
+limbo -g myprog.b
+.P2
+If you typed in the example program correctly,
+then you'll get a short pause, and then another shell
+prompt. This indicates a successful compilation (no
+news is good news), in which case you will now have
+two new files in the current directory,
+.CW myprog.sbl
+and
+.CW myprog.dis .
+The
+.CW -g
+option to the
+.CW limbo
+command directed it to produce the
+.CW myprog.sbl
+file, which contains symbolic information
+relating the source code to the Dis executable file.
+The
+.CW myprog.dis
+file contains the actual executable file.
+At this point, if you type
+.CW lc ,
+to get a listing of the files in the current directory,
+and then click with button-2 on the
+.CW myprog.dis
+file, and you should see the output ``Hello, world''.
+You could also just type
+.CW myprog
+at the shell prompt.
+.PP
+If you are normal, however, the above compilation
+probably failed because of some mistyped characters
+in the source code; and for larger newly created programs,
+in my experience, this
+is almost invariably the case.
+If you got no errors in the above
+compilation, try changing
+.CW sys->print
+to
+.CW print ,
+saving the file again,
+and continue with the next section.
+.SH
+Finding compilation errors
+.PP
+When the Limbo compiler finds errors, it prints
+the errors, one per line, each one looking something
+like the following:
+.P1
+myprog.b:13: print is not declared
+.P2
+This shows the filename where the error has occurred,
+its line number in the file, and a description of the error.
+Acme's button-3 mouse clicking makes it extremely easy
+to see where in the source code the error has occurred.
+Click with button-3 anywhere in the filename on the
+line of the compilation error, and Acme will automatically
+take the cursor to the file of that name and highlight
+the correct line.
+.PP
+If there had been no currently appropriate open Acme
+window representing the file, then a new one would
+be created, and the appropriate line selected.
+.PP
+Edit
+.CW myprog.b
+until you have a program that compiles successfully
+and produces the ``Hello, world'' output.
+For a program as simple as this, that's all there
+is to it - you now know the essential stages involved in
+writing a Limbo program; there's just the small matter
+of absorbing the Limbo language and familiarising
+yourself with the libraries (``The Limbo Programming Language''
+elsewhere in this volume,
+and
+.I intro (2)
+are the two essential starting points here).
+.SH
+Finding run-time errors
+.PP
+For larger programs, there is the problem of programs
+that die unexpectedly with a run-time error. This
+will happen when, for instance, a Limbo program uses a reference
+that has not been initialised, or refers to an out-of-bounds
+array element.
+.PP
+When a Limbo program dies with a run-time exception,
+it does not go away completely, but remains hanging
+around, dormant, in a
+.I broken
+state; the state that it was in when it died may
+now be examined at leisure. To experiment with this,
+edit the Myprog module above to delete the line
+that loads the
+.CW Sys
+module
+.CW "sys = load Sys" ...), (
+and recompile the program.
+.PP
+This time when you come to run
+.CW myprog ,
+it will die, printing a message like:
+.P1
+sh: 319 "Myprog":module not loaded
+.P2
+The number
+.CW 319
+is the
+.I "process id"
+(or just
+.I pid )
+of the broken process. The command
+.CW ps ,
+which shows all currently running processes,
+can be used at this point - you will see a line like this:
+.P1
+     319      245        rog     broken    64K Myprog
+.P2
+The first number is the pid of the process;
+the second is the
+.I "process group"
+id of the process; the third field gives the
+owner of the process; the fourth gives its state
+(broken, in this case); the fifth shows the current
+size of the process, and the last gives the name
+of the module that the process is currently running.
+.PP
+The
+.CW stack
+command can be used to quickly find the line
+at which the process has broken; type:
+.P1
+	stack \fIpid\fP
+.P2
+where
+.I pid
+is the number mentioned in the ``module not loaded''
+message (319 in this case).
+It produces something like the following output:
+.P1
+init() myprog.b:12.1, 29
+unknown fn() Module /dis/sh.dis PC 1706
+.P2
+As usual, a quick button-3 click on the
+.CW myprog.b
+part of the first line takes you to the appropriate
+part of the source file. The reason that the program
+has died here is that, in Limbo, all external modules
+must be explicitly loaded before they can be used; to
+try to call an uninitialised module is an error
+and causes an exception.
+.SH
+More sophisticated debugging
+.PP
+.CW Stack
+is fine for getting a quick summary of the state
+in which a program has died, but there are
+times when such a simple post-mortem analysis
+is inadequate. The
+.CW wm/deb
+(see
+.I wm-deb\fR(1))\fP
+command provides an interactive windowing
+debugger for such occasions.
+It runs outside Acme,
+in the default window system. A convenient way
+to start debugging an existing process is
+to raise 
+.CW wm/task
+(``Task Manager'' on the
+main menu), select with the mouse the process
+to debug, and click ``Debug''. This will start
+.CW wm/deb
+on that process. Before it can start, the debugger will ask
+for the names of any source files that it has not been
+able to find (usually this includes the source for
+the shell, as the module being debugged is often
+started by the shell, and so the top-level function will
+be in the shell's module).
+.PP
+.CW Wm/deb
+can be used to debug multiple threads, to inspect
+the data structures in a thread, and to interactively
+step through the running of a thread (single stepping).
+See
+.I wm-deb (1)
+for details.
+
+\" further afield?
+\" other development tools?
+\" tools to come?
binary files /dev/null b/doc/dev.pdf differ
--- /dev/null
+++ b/doc/dis.ms
@@ -1,0 +1,1824 @@
+.so /sys/lib/tmac/tmac.uni
+.TL
+Dis Virtual Machine Specification
+.AU
+.I "Lucent Technologies Inc"
+.I "30 September 1999"
+
+.I "Extensively revised by Vita Nuova Limited"
+.I "5 June 2000, 9 January 2003"
+.NH 1
+Introduction
+.LP
+The Dis virtual machine provides the execution environment for programs running under the Inferno operating system. The virtual machine models a CISC-like, three operand, memory-to-memory architecture. Code can either be interpreted by a C library or compiled on-the-fly into machine code for the target architecture.
+.LP
+This paper defines the virtual machine informally.
+A separate paper by Winterbottom and Pike[2] discusses its design.
+The Dis object file format is also defined here.
+Literals and keywords are in
+.CW typewriter
+typeface.
+.NH 1
+Addressing Modes
+.SH
+Operand Size
+.LP
+Operand sizes are defined as follows: a byte is 8 bits, a word or pointer is 32 bits, a float is 64 bits, a big integer is 64 bits. The operand size of each instruction is encoded explicitly by the operand code. The operand size and type are specified by the last character of the instruction mnemonic:
+.IP
+.TS
+lf(CW) lfR .
+W	word, 32-bit two's complement
+B	byte, 8-bit unsigned
+F	float, 64-bit IEEE format
+L	big, 64-bit two's complement
+P	pointer
+C	Unicode string encoded in UTF-8
+M	memory
+MP	memory containing pointers
+.TE
+.LP
+Two more operand types are defined to provide `short'
+types for use by languages other than Limbo:
+signed 16-bit integers, called `short word'
+here, and 32-bit IEEE format floating-point numbers, called `short float' or `short real' here.
+Support for them is limited to conversion to and from words or floats respectively;
+the instructions are marked below with a dagger (†).
+.SH
+Memory Organization
+.LP
+Memory for a thread is divided into several separate regions. The code segment stores either a decoded virtual machine instruction stream suitable for execution by the interpreter or flash compiled native machine code for the host CPU. Neither type of code segment is addressable from the instruction set. At the object code level, PC values are offsets, counted in instructions, from the beginning of the code space.
+.LP
+Data memory is a linear array of bytes, addressed using 32-bit pointers. Words are stored in the native representation of the host CPU. Data types larger than a byte must be stored at addresses aligned to
+a multiple of the data size. A thread executing a module has access to two regions of addressable data memory. A module pointer
+.CW "mp" \& (
+register) defines a region of global storage for a particular module, a frame pointer
+.CW "fp" \& (
+register) defines the current activation record or frame for the thread. Frames are allocated dynamically from a stack by function call and return instructions. The stack is extended automatically from the heap.
+.LP
+The
+.CW mp
+and
+.CW fp
+registers cannot be addressed directly, and therefore, can be modified only by call and return instructions.
+.SH
+Effective Addresses
+.LP
+Each instruction can potentially address three operands. The source and destination operands are general, but the middle operand can use any address mode except double indirect. If the middle operand of a three address instruction is omitted, it is assumed to be the same as the destination operand.
+.LP
+The general operands generate an effective address from three basic modes: immediate, indirect and double indirect. The assembler syntax for each mode is:
+.IP
+.TS
+lf(CW) lfR .
+10(fp)	30-bit signed indirect from fp
+20(mp)	30-bit signed indirect from mp
+$0x123	30-bit signed immediate value
+10(20(fp))	two 16-bit unsigned offsets double indirect from fp
+10(20(mp))	two 16-bit unsigned offsets double indirect from mp
+.TE
+.SH
+Garbage Collection
+.LP
+The Dis machine performs both reference counted and real time mark and sweep garbage collection. This hyrbrid approach allows code to be generated in several styles: pure reference counted, mark and sweep, or a hybrid of the two approaches. Compiler writers have the freedom to choose how specific types are handled by the machine to optimize code for performance or language implementation. Instruction selection determines which algorithm will be applied to specific types.
+.LP
+When using reference counting, pointers are a special operand type and should only be manipulated using the pointer instructions in order to ensure the correct functioning of the garbage collector. Every memory location that stores a pointer must be known to the interpreter so that it can be initialized and deallocated correctly. The information is transmitted in the form of type descriptors in the object module. Each type descriptor contains a bit vector for a particular type where each bit corresponds to a word in memory. Type descriptors are generated automatically by the Limbo compiler. The assembler syntax for a type descriptor is:
+.P1
+desc	$10, 132, "001F"
+.P2
+The first parameter is the descriptor number, the second is the size in bytes, and the third a pointer map. The map contains a list of hex bytes where each byte maps eight 32 bit words. The most significant bit represents the lowest memory address.
+A one bit indicates a pointer in memory. The map need not have an entry for every byte and unspecified bytes are assumed zero.
+.LP
+Throughout this description, the symbolic constant
+.CW H
+refers to a nil pointer.
+.NH 1
+Instruction Set
+.SH
+add\fIx\fP \- Add
+.P1
+Syntax:		addb	src1, src2, dst
+		addf	src1, src2, dst
+		addw	src1, src2, dst
+		addl	src1, src2, dst
+Function:	dst = src1 + src2
+.P2
+.LP
+The 
+.CW "add"
+instructions compute the sum of the operands addressed by 
+.CW "src1"
+and 
+.CW "src2"
+and stores the result in the
+.CW " dst"
+operand. For 
+.CW "addb"
+the result is truncated to eight bits.
+.SH
+addc \- Add strings
+.P1
+Syntax:		addc	src1, src2, dst
+Function:	dst = src1 + src2
+.P2
+.LP
+The 
+.CW "addc"
+instruction concatenates the two UTF strings pointed to by
+.CW " src1"
+and 
+.CW "src2" ;
+the result is placed in the pointer addressed by 
+.CW "dst" .
+If both pointers are 
+.CW "H"
+the result will be a zero length string rather than 
+.CW "H" .
+.SH
+alt \- Alternate between communications
+.P1
+Syntax:		alt	src, dst
+.P2
+The 
+.CW "alt"
+instruction selects between a set of channels ready to communicate. The
+.CW src
+argument is the address of a structure of the following form:
+.P1
+struct Alt {
+	int nsend;		/* Number of senders */
+	int nrecv;		/* Number of receivers */
+	struct {
+		Channel* c;		/* Channel */
+		void*	val;	/* Address of lval/rval */
+	} entry[];
+};
+.P2
+The vector is divided into two sections; the first lists the channels ready to send values, the second lists channels either ready to receive or an array of channels each of which may be ready to receive. The counts of the sender and receiver channels are stored as the first and second words addressed by
+.CW src .
+An 
+.CW "alt"
+instruction proceeds by testing each channel for readiness to communicate. A ready channel is added to a list. If the list is empty after each channel has been considered, the thread blocks at the 
+.CW "alt"
+instruction waiting for a channel to become ready; otherwise, a channel is picked at random from the ready set.
+.LP
+The
+.CW "alt"
+instruction then uses the selected channel to perform the communication using the 
+.CW "val"
+address as either a source for send or a destination for receive. The numeric index of the selected vector element is placed in 
+.CW "dst" .
+.SH
+and\fIx\fP \- Logical AND
+.P1
+Syntax:		andb	src1, src2, dst
+		andw	src1, src2, dst
+		andl	src1, src2, dst
+Function:	dst = src1 & src2
+.P2
+The instructions compute the bitwise AND of the two operands addressed by 
+.CW "src1"
+and 
+.CW "src2"
+and stores the result in the 
+.CW "dst"
+operand.
+.SH
+beq\fIx\fP \- Branch equal
+.P1
+Syntax:		beqb	src1, src2, dst
+		beqc	src1, src2, dst
+		beqf	src1, src2, dst
+		beqw	src1, src2, dst
+		beql	src1, src2, dst
+Function:	if src1 == src2 then pc = dst
+.P2
+If the 
+.CW "src1"
+operand is equal to the 
+.CW "src2"
+operand, then control is transferred to the program counter specified by the 
+.CW "dst"
+operand.
+.SH
+bge\fIx\fP \- Branch greater or equal
+.P1
+Syntax:		bgeb	src1, src2, dst
+		bgec	src1, src2, dst
+		bgef	src1, src2, dst
+		bgew	src1, src2, dst
+		bgel	src1, src2, dst
+Function:	if src1 >= src2 then pc = dst
+.P2
+If the 
+.CW "src1"
+operand is greater than or equal to the 
+.CW "src2"
+operand, then control is transferred to program counter specified by the 
+.CW "dst"
+operand. This instruction performs a signed comparison.
+.SH
+bgt\fIx\fP \- Branch greater
+.P1
+Syntax:		bgtb	src1, src2, dst
+		bgtc	src1, src2, dst
+		bgtf	src1, src2, dst
+		bgtw	src1, src2, dst
+		bgtl	src1, src2, dst
+Function:	if src1 > src2 then pc = dst
+.P2
+If the 
+.CW "src1"
+operand is greater than the 
+.CW "src2"
+operand, then control is transferred to the program counter specified by the 
+.CW "dst"
+operand. This instruction performs a signed comparison.
+.SH
+ble\fIx\fP \- Branch less than or equal
+.P1
+Syntax:		bleb	src1, src2, dst
+		blec	src1, src2, dst
+		blef	src1, src2, dst
+		blew	src1, src2, dst
+		blel	src1, src2, dst
+Function:	if src1 <= src2 then pc = dst
+.P2
+If the 
+.CW "src1"
+operand is less than or equal to the 
+.CW "src2"
+operand, then control is transferred to the program counter specified by the 
+.CW "dst"
+operand. This instruction performs a signed comparison.
+.SH
+blt\fIx\fP \- Branch less than
+.P1
+Syntax:		bltb	src1, src2, dst
+		bltc	src1, src2, dst
+		bltf	src1, src2, dst
+		bltw	src1, src2, dst
+		bltl	src1, src2, dst
+Function:	if src1 < src2 then pc = dst
+.P2
+If the 
+.CW "src1"
+operand is less than the 
+.CW "src2"
+operand, then control is transferred to the program counter specified by the 
+.CW "dst"
+operand.
+.SH
+bne\fIx\fP \- Branch not equal
+.P1
+Syntax:		bneb	src1, src2, dst
+		bnec	src1, src2, dst
+		bnef	src1, src2, dst
+		bnew	src1, src2, dst
+		bnel	src1, src2, dst
+Function:	if src1 != src2 then pc = dst
+.P2
+If the 
+.CW "src1"
+operand is not equal to the 
+.CW "src2"
+operand, then control is transferred to the program counter specified by the 
+.CW "dst"
+operand.
+.SH
+call \- Call local function
+.P1
+Syntax:		call	src, dst
+Function:	link(src) = pc
+		frame(src) = fp
+		mod(src) = 0
+		fp = src
+		pc = dst
+.P2
+The 
+.CW "call"
+instruction performs a function call to a routine in the same module. The 
+.CW "src"
+argument specifies a frame created by 
+.CW "new" .
+The current value of 
+.CW "pc"
+is stored in link(src), the current value of 
+.CW "fp"
+is stored in frame(src) and the module link register is set to 0. The value of 
+.CW "fp"
+is then set to 
+.CW "src"
+and control is transferred to the program counter specified by
+.CW dst .
+.SH
+case \- Case compare integer and branch
+.P1
+Syntax:		case	src, dst
+Function:	pc = 0..i: dst[i].pc where
+		  dst[i].lo >= src && dst[i].hi < src
+.P2
+The 
+.CW "case"
+instruction jumps to a new location specified by a range of values. The 
+.CW "dst"
+operand points to a table in memory containing a table of 
+.CW "i"
+values. Each value is three words long: the first word specifies a low value, the second word specifies a high value, and the third word specifies a program counter. The first word of the table gives the number of entries. The 
+.CW "case"
+instruction searches the table for the first matching value where the 
+.CW "src"
+operand is greater than or equal to the low word and less than the high word. Control is transferred to the program counter stored in the first word of the matching entry.
+.SH
+casec \- Case compare string and branch
+.P1
+Syntax:		casec	src, dst
+Function:	pc = 0..i: dst[i].pc where
+		   dst[i].lo >= src && dst[i].hi < src
+.P2
+The 
+.CW "casec"
+instruction jumps to a new location specified by a range of string constants. The table is the same as described for the
+.CW case
+instruction.
+.SH
+cons\fIx\fP \- Allocate new list element
+.P1
+Syntax:		consb	src, dst
+		consc	src, dst
+		consf	src, dst
+		consl	src, dst
+		consm	src, dst
+		consmp	src, dst
+		consp	src, dst
+		consw	src, dst
+Function:	p = new(src, dst)
+		dst = p
+.P2
+The 
+.CW "cons"
+instructions add a new element to the head of a list. A new list element is composed from the 
+.CW "src"
+operand and a pointer to the head of an extant list specified by 
+.CW "dst" .
+The resulting element is stored back into 
+.CW "dst" .
+.SH
+cvtac \- Convert byte array to string
+.P1
+Syntax:		cvtac	src, dst
+Function:	dst = string(src)
+.P2
+The 
+.CW "src"
+operand must be an array of bytes, which is converted into a character string and stored in 
+.CW "dst" .
+The new string is a copy of the bytes in 
+.CW "src" .
+.SH
+cvtbw \- Convert byte to word
+.P1
+Syntax:		cvtbw	src, dst
+Function:	dst = src & 0xff
+.P2
+A byte is fetched from the 
+.CW "src"
+operand extended to the size of a word and then stored into 
+.CW "dst" .
+.SH
+cvtca \- Convert string to byte array
+.P1
+Syntax:		cvtca	src, dst
+Function:	dst = array(src)
+.P2
+The 
+.CW "src"
+operand must be a string which is converted into an array of bytes and stored in 
+.CW "dst" .
+The new array is a copy of the characters in src.
+.SH
+cvtcf \- Convert string to real
+.P1
+Syntax:		cvtcf	src, dst
+Function:	dst = (float)src
+.P2
+The string addressed by the 
+.CW "src"
+operand is converted to a floating point value and stored in the 
+.CW "dst"
+operand. Initial white space is ignored; conversion ceases at the first character in the string that is not part of the representation of the floating point value.
+.SH
+cvtcl \- Convert string to big
+.P1
+Syntax:		cvtcl	src, dst
+Function:	dst = (big)src
+.P2
+The string addressed by the 
+.CW "src"
+operand is converted to a big integer and stored in the 
+.CW "dst"
+operand. Initial white space is ignored; conversion ceases at the first non-digit in the string.
+.SH
+cvtcw \- Convert string to word
+.P1
+Syntax:		cvtcw	src, dst
+Function:	dst = (int)src
+.P2
+The string addressed by the 
+.CW "src"
+operand is converted to a word and stored in the 
+.CW "dst"
+operand. Initial white space is ignored; after a possible sign, conversion ceases at the first non-digit in the string.
+.SH
+cvtfc \- Convert real to string
+.P1
+Syntax:		cvtfc	src, dst
+Function:	dst = string(src)
+.P2
+The floating point value addressed by the 
+.CW "src"
+operand is converted to a string and stored in the 
+.CW "dst"
+operand. The string is a floating point representation of the value.
+.SH
+cvtfw \- Convert real to word
+.P1
+Syntax:		cvtfw	src, dst
+Function:	dst = (int)src
+.P2
+The floating point value addressed by 
+.CW "src"
+is converted into a word and stored into 
+.CW "dst" .
+The floating point value is rounded to the nearest integer.
+.SH
+cvtfl \- Convert real to big
+.P1
+Syntax:		cvtfl	src, dst
+Function:	dst = (big)src
+.P2
+The floating point value addressed by 
+.CW "src"
+is converted into a big integer and stored into 
+.CW "dst" .
+The floating point value is rounded to the nearest integer.
+.SH
+cvtfr \- Convert real to short real†
+.P1
+Syntax:		cvtfr	src, dst
+Function:	dst = (short float)src
+.P2
+The floating point value addressed by 
+.CW "src"
+is converted to a short (32-bit) floating point value and stored into 
+.CW "dst" .
+The floating point value is rounded to the nearest integer.
+.SH
+cvtlc \- Convert big to string
+.P1
+Syntax:		cvtlc	src, dst
+Function:	dst = string(src)
+.P2
+The big integer addressed by the 
+.CW "src"
+operand is converted to a string and stored in the 
+.CW "dst"
+operand. The string is the decimal representation of the big integer.
+.SH
+cvtlw \- Convert big to word
+.P1
+Syntax:		cvtlw	src, dst
+Function:	dst = (int)src
+.P2
+The big integer addressed by the 
+.CW "src"
+operand is converted to a word and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtsw \- Convert short word to word†
+.P1
+Syntax:		cvtsw	src, dst
+Function:	dst = (int)src
+.P2
+The short word addressed by the 
+.CW "src"
+operand is converted to a word and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtwb \- Convert word to byte
+.P1
+Syntax:		cvtwb	src, dst
+Function:	dst = (byte)src;
+.P2
+The 
+.CW "src"
+operand is converted to a byte and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtwc \- Convert word to string
+.P1
+Syntax:		cvtwc	src, dst
+Function:	dst = string(src)
+.P2
+The word addressed by the 
+.CW "src"
+operand is converted to a string and stored in the 
+.CW "dst"
+operand. The string is the decimal representation of the word.
+.SH
+cvtwl \- Convert word to big
+.P1
+Syntax:		cvtwl	src, dst
+Function:	dst = (big)src;
+.P2
+The word addressed by the 
+.CW "src"
+operand is converted to a big integer and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtwf \- Convert word to real
+.P1
+Syntax:		cvtwf	src, dst
+Function:	dst = (float)src;
+.P2
+The word addressed by the 
+.CW "src"
+operand is converted to a floating point value and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtws \- Convert word to short word†
+.P1
+Syntax:		cvtws	src, dst
+Function:	dst = (short)src;
+.P2
+The word addressed by the 
+.CW "src"
+operand is converted to a short word and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtlf \- Convert big to real
+.P1
+Syntax:		cvtlf	src, dst
+Function:	dst = (float)src;
+.P2
+The big integer addressed by the 
+.CW "src"
+operand is converted to a floating point value and stored in the 
+.CW "dst"
+operand.
+.SH
+cvtrf \- Convert short real to real†
+.P1
+Syntax:		cvtrf	src, dst
+Function:	dst = (float)src;
+.P2
+The short (32 bit) floating point value addressed by the 
+.CW "src"
+operand is converted to a 64-bit floating point value and stored in the 
+.CW "dst"
+operand.
+.SH
+div\fIx\fP \- Divide
+.P1
+Syntax:		divb	src1, src2, dst
+		divf	src1, src2, dst
+		divw	src1, src2, dst
+		divl	src1, src2, dst
+Function:	dst = src2/src1
+.P2
+The 
+.CW "src2"
+operand is divided by the 
+.CW "src1"
+operand and the quotient is stored in the 
+.CW "dst"
+operand. Division by zero causes the thread to terminate.
+.SH
+exit \- Terminate thread
+.P1
+Syntax:		exit
+Function:	exit()
+.P2
+The executing thread terminates. All resources held in the stack are deallocated.
+.SH
+frame \- Allocate frame for local call
+.P1
+Syntax:		frame	src1, src2
+Function:	src2 = fp + src1->size
+		initmem(src2, src1);
+.P2
+The frame instruction creates a new stack frame
+for a call to a function in the same module. The frame is initialized according to the type descriptor supplied as the
+.CW src1
+operand. A pointer to the newly created frame is stored in the
+.CW src2
+operand.
+.SH
+goto \- Computed goto
+.P1
+Syntax:		goto	src, dst
+Function:	pc = dst[src]
+.P2
+The 
+.CW "goto"
+instruction performs a computed goto. The 
+.CW "src"
+operand must be an integer index into a table of PC values specified by the 
+.CW "dst"
+operand.
+.SH
+head\fIx\fP \- Head of list
+.P1
+Syntax:		headb	src, dst
+		headf	src, dst
+		headm	src, dst
+		headmp	src, dst
+		headp	src, dst
+		headw	src, dst
+		headl	src, dst
+Function:	dst = hd src
+.P2
+The 
+.CW "head"
+instructions make a copy of the first data item stored in a list. The 
+.CW "src"
+operand must be a list of the correct type. The first item is copied into the 
+.CW "dst"
+operand. The list is not modified.
+.SH
+indc \- Index by character
+.P1
+Syntax:		indc	src1, src2, dst	
+Function:	dst = src1[src2]
+.P2
+The 
+.CW "indc"
+instruction indexes Unicode strings. The 
+.CW "src1"
+instruction must be a string. The 
+.CW "src2"
+operand must be an integer specifying the origin-0 index in
+.CW src1
+of the (Unicode) character to store in the 
+.CW "dst"
+operand.
+.SH
+indx \- Array index
+.P1
+Syntax:		indx	src1, dst, src2
+Function:	dst = &src1[src2]
+.P2
+The 
+.CW "indx"
+instruction computes the effective address of an array element. The 
+.CW "src1"
+operand must be an array created by the 
+.CW "newa"
+instruction. The 
+.CW "src2"
+operand must be an integer. The effective address of the 
+.CW "src2"
+element of the array is stored in the 
+.CW "dst"
+operand.
+.SH
+ind\fIx\fP \- Index by type
+.P1
+Syntax:		indb	src1, dst, src2
+		indw	src1, dst, src2
+		indf	src1, dst, src2
+		indl	src1, dst, src2
+Function:	dst = &src1[src2]
+.P2
+The 
+.CW "indb" , 
+.CW "indw" , 
+.CW "indf"
+and 
+.CW "indl"
+instructions index arrays of the basic types. The 
+.CW "src1"
+operand must be an array created by the 
+.CW "newa"
+instruction. The 
+.CW "src2"
+operand must be a non-negative integer index less than the array size. The effective address of the element at the index is stored in the 
+.CW "dst"
+operand.
+.SH
+insc \- Insert character into string
+.P1
+Syntax:		insc	src1, src2, dst
+Function:	src1[src2] = dst
+.P2
+The 
+.CW "insc"
+instruction inserts a character into an existing string.
+The index in
+.CW "src2"
+must be a non-negative integer less than the length of the string plus one.
+(The character will be appended to the string if the index is equal to
+the string's length.)
+The
+.CW "src1"
+operand must be a string (or nil).
+The character to insert must be a valid 21-bit unicode value represented as a word.
+.SH
+jmp \- Branch always
+.P1
+Syntax:		jmp	dst
+Function:	pc = dst
+.P2
+Control is transferred to the location specified by the 
+.CW "dst"
+operand.
+.SH
+lea \- Load effective address
+.P1
+Syntax:		lea	src, dst
+Function:	dst = &src
+.P2
+The 
+.CW "lea"
+instruction computes the effective address of the 
+.CW "src"
+operand and stores it in the 
+.CW "dst"
+operand.
+.SH
+lena \- Length of array
+.P1
+Syntax:		lena	src, dst
+Function:	dst = nelem(src)
+.P2
+The 
+.CW "lena"
+instruction computes the length of the array specified by the 
+.CW "src"
+operand and stores it in the 
+.CW "dst"
+operand.
+.SH
+lenc \- Length of string
+.P1
+Syntax:		lenc	src, dst
+Function:	dst = utflen(src)
+.P2
+The 
+.CW "lenc"
+instruction computes the number of characters in the UTF string addressed by the 
+.CW "src"
+operand and stores it in the 
+.CW "dst"
+operand.
+.SH
+lenl \- Length of list
+.P1
+Syntax:		lenl	src, dst
+Function:	dst = 0;
+		for(l = src; l; l = tl l)
+			dst++;
+.P2
+The 
+.CW "lenl"
+instruction computes the number of elements in the list addressed by the 
+.CW "src"
+operand and stores the result in the 
+.CW "dst"
+operand.
+.SH
+load \- Load module
+.P1
+Syntax:		load	src1, src2, dst
+Function:	dst = load src2 src1
+.P2
+The 
+.CW "load"
+instruction loads a new module into the heap. The module might optionally be compiled into machine code depending on the module header. The 
+.CW "src1"
+operand is a pathname to the file containing the object code for the module. The 
+.CW "src2"
+operand specifies the address
+of a linkage descriptor for the module (see below).
+A reference to the newly loaded module is stored in the 
+.CW "dst"
+operand.
+If the module could not be loaded for any reason, then 
+.CW "dst"
+will be set to
+.CW H .
+.LP
+The linkage descriptor referenced by the
+.CW src2
+operand is a table in data space that lists the functions
+imported by the current module from the module to be loaded.
+It has the following layout:
+.P1
+int nentries;
+struct {	/* word aligned */
+	int	sig;
+	byte	name[];	/* UTF encoded name, 0-terminated */
+} entry[];
+.P2
+The
+.CW nentries
+value gives the number of entries in the table and can be zero.
+It is followed by that many linkage entries.
+Each entry is aligned on a word boundary; there can therefore
+be padding before each structure.
+The entry names the imported function in the UTF-encoded string in
+.CW name ,
+which is terminated by a byte containing zero.
+The MD5 hash of the function's type signature is given in the value
+.CW sig .
+For each entry,
+.CW load
+instruction checks that a function with the same name in the newly loaded
+exists, with the same signature.
+Otherwise the load will fail and
+.CW dst
+will be set to
+.CW H .
+.LP
+The entries in the linkage descriptor form an array of linkage records
+(internal to the virtual machine) associated with the
+module pointer returned in
+.CW dst ,
+that is indexed by operators
+.CW mframe ,
+.CW mcall
+and
+.CW mspawn
+to refer to functions in that module.
+The linkage scheme provides a level of indirection that allows
+a module to be loaded using any module declaration that is a valid
+subset of the implementation module's declaration,
+and allows entry points to be added to modules without invalidating
+calling modules.
+.SH
+lsr\fIx\fP \- Logical shift right
+.P1
+Syntax:		lsrw	src1, src2, dst
+		lsrl	src1, src2, dst
+Function:	dst = (unsigned)src2 >> src1
+.P2
+The 
+.CW "lsr"
+instructions shift the 
+.CW "src2"
+operand right by the number of bits specified by the 
+.CW "src1"
+operand, replacing the vacated bits by 0, and store the result in the 
+.CW "dst"
+operand. Shift counts less than 0 or greater than the number of bits in the object have undefined results.
+This instruction is included for support of languages other than Limbo,
+and is not used by the Limbo compiler.
+.SH
+mcall \- Inter-module call
+.P1
+Syntax:		mcall	src1, src2, src3
+Function:	link(src1) = pc
+		frame(src1) = fp
+		mod(src1) = current_moduleptr
+		current_moduleptr = src3->moduleptr
+		fp = src1
+		pc = src3->links[src2]->pc
+.P2
+The 
+.CW "mcall"
+instruction calls a function in another module. The first argument specifies a new frame for the called procedure and must have been built using the 
+.CW "mframe"
+instruction.
+The 
+.CW "src3"
+operand is a module reference generated by a successful 
+.CW "load"
+instruction.
+The 
+.CW "src2"
+operand specifies the index for the called
+function in the array of linkage records associated with that module reference
+(see the
+.CW load
+instruction).
+.SH
+mframe \- Allocate inter-module frame
+.P1
+Syntax:		mframe	src1, src2, dst
+Function:	dst = fp + src1->links[src2]->t->size
+		initmem(dst, src1->links[src2])
+.P2
+The
+.CW mframe
+instruction allocates a new frame for a procedure call into another module. The
+.CW src1
+operand specifies the location of a module pointer created as the result of a successful load instruction. The
+.CW src2
+operand specifies the index for the called function in
+the array of linkage records associated
+with that module pointer (see the
+.CW load
+instruction).
+A pointer to the initialized frame is stored in
+.CW dst .
+The
+.CW src2
+operand specifies the linkage number of the function to be called in the module specified by
+.CW src1 .
+.SH
+mnewz \- Allocate object given type from another module
+.P1
+Syntax:		mnewz	src1, src2, dst
+Function:	dst = malloc(src1->types[src2]->size)
+		initmem(dst, src1->types[src2]->map)
+.P2
+The
+.CW mnewz
+instruction allocates and initializes storage to a new
+area of memory.
+The
+.CW src1
+operand specifies the location of a module pointer created as the result of a successful load instruction.
+The size of the new memory area and the location of
+pointers within it are specified by the
+.CW src2
+operand, which gives a
+type descriptor number within that module.
+Space not occupied by pointers is initialized to zero.
+A pointer to the initialized object is stored in
+.CW dst .
+This instruction is not used by Limbo; it was added to implement other languages.
+.SH
+mod\fIx\fP \- Modulus
+.P1
+Syntax:		modb	src1, src2, dst
+		modw	src1, src2, dst
+		modl	src1, src2, dst
+Function:	dst = src2 % src1
+.P2
+The modulus instructions compute the remainder of the 
+.CW "src2"
+operand divided by the 
+.CW "src1"
+operand and store the result in 
+.CW "dst" .
+The operator preserves the condition that the absolute value of a%b is less than the absolute value of 
+.CW "b" ; 
+.CW "(a/b)*b + a%b"
+is always equal to
+.CW a .
+.SH
+mov\fIx\fP \- Move scalar
+.P1
+Syntax:		movb	src, dst
+		movw	src, dst
+		movf	src, dst
+		movl	src, dst
+Function:	dst = src
+.P2
+The move operators perform assignment. The value specified by the 
+.CW "src"
+operand is copied to the 
+.CW "dst"
+operand.
+.SH
+movm \- Move memory
+.P1
+Syntax:		movm	src1, src2, dst
+Function:	memmove(&dst, &src1, src2)
+.P2
+The 
+.CW "movm"
+instruction copies memory from the 
+.CW "src1"
+operand to the 
+.CW "dst"
+operand for 
+.CW "src2"
+bytes. The 
+.CW "src1"
+and 
+.CW "dst"
+operands specify the effective address of the memory rather than a pointer to the memory.
+.SH
+movmp \- Move memory and update reference counts
+.P1
+Syntax:		movmp	src1, src2, dst
+Function:	decmem(&dst, src2)
+		memmove(&dst, &src1, src2->size)
+		incmem(&src, src2)
+.P2
+The 
+.CW "movmp"
+instructions performs the same function as the 
+.CW "movm"
+instruction but increments the reference count of pointers contained in the data type. For each pointer specified by the 
+.CW "src2"
+type descriptor, the corresponding pointer reference count in the destination is decremented. The 
+.CW "movmp"
+instruction then copies memory from the 
+.CW "src1"
+operand to the 
+.CW "dst"
+operand for the number of bytes described by the type descriptor. For each pointer specified by the type descriptor the corresponding pointer reference count in the source is incremented.
+.SH
+movp \- Move pointer
+.P1
+Syntax:		movp	src, dst
+Function:	destroy(dst)
+		dst = src
+		incref(src)
+.P2
+The 
+.CW "movp"
+instruction copies a pointer adjusting the reference counts to reflect the new pointers.
+.SH
+movpc \- Move program counter
+.P1
+Syntax:		movpc	src, dst
+Function:	dst = PC(src);
+.P2
+The 
+.CW "movpc"
+instruction computes the actual address of an immediate PC value. The 
+.CW "dst"
+operand is set to the actual machine address of the instruction addressed by the 
+.CW "src"
+operand. This instruction must be used to calculate PC values for computed branches.
+.SH
+mspawn \- Module spawn function
+.P1
+Syntax:		mspawn	src1, src2, src3
+Function:	fork();
+		if(child){
+			link(src1) = 0
+			frame(src1) = 0
+			mod(src1) = src3->moduleptr
+			current_moduleptr = src3->moduleptr
+			fp = src1
+			pc = src3->links[src2]->pc
+		}
+.P2
+The 
+.CW "mspawn"
+instruction creates a new thread, which starts executing a function in another module.
+The first argument specifies a new frame for the called procedure and must have been built using the 
+.CW "mframe"
+instruction.
+The 
+.CW "src3"
+operand is a module reference generated by a successful 
+.CW "load"
+instruction.
+The
+.CW "src2"
+operand specifies the index for the called function in
+the array of linkage records associated with that module reference (see the
+.CW load
+instruction above).
+.SH
+mul\fIx\fP - Multiply
+.P1
+Syntax:		mulb	src1, src2, dst
+		mulw	src1, src2, dst
+		mulf	src1, src2, dst
+		mull	src1, src2, dst
+Function:	dst = src1 * src2
+.P2
+The
+.CW src1
+operand is multiplied by the
+.CW src2
+operand and the product is stored in the
+.CW dst
+operand.
+.SH
+nbalt \- Non blocking alternate
+.P1
+Syntax:		nbalt	src, dst
+.P2
+The 
+.CW "nbalt"
+instruction has the same operands and function as 
+.CW "alt"
+, except that if no channel is ready to communicate, the instruction does not block. When no channels are ready, control is transferred to the PC in the last element of the table addressed by
+.CW dst .
+.SH
+negf \- Negate real
+.P1
+Syntax:		negf	src, dst
+Function:	dst = -src
+.P2
+The floating point value addressed by the 
+.CW "src"
+operand is negated and stored in the 
+.CW "dst"
+operand.
+.SH
+new, newz \- Allocate object
+.P1
+Syntax:		new	src, dst
+		newz	src, dst
+Function:	dst = malloc(src->size);
+		initmem(dst, src->map);
+.P2
+The 
+.CW "new"
+instruction allocates and initializes storage to a new area of memory. The size and locations of pointers are specified by the type descriptor number given as the 
+.CW "src"
+operand. A pointer to the newly allocated object is placed in 
+.CW "dst" .
+Any space not occupied by pointers has undefined value.
+.LP
+The
+.CW "newz"
+instruction additionally guarantees that all non-pointer values are set to zero.
+It is not used by Limbo.
+.SH
+newa, newaz \- Allocate array
+.P1
+Syntax:		newa	src1, src2, dst
+		newaz	src1, src2, dst
+Function:	dst = malloc(src2->size * src1);
+		for(i = 0; i < src1; i++)
+			initmem(dst + i*src2->size, src2->map);
+.P2
+The 
+.CW "newa"
+instruction allocates and initializes an array. The number of elements is specified by the 
+.CW "src1"
+operand. The type of each element is specified by the type descriptor number given as the 
+.CW "src2"
+operand.
+Space not occupied by pointers has undefined value.
+The
+.CW newaz
+instruction additionally guarantees that all non-pointer values are set to zero;
+it is not used by Limbo.
+.SH
+newc\fIx\fP \- Allocate channel
+.P1
+Syntax:		newcw	dst
+		newcb	dst
+		newcl	dst
+		newcf	dst
+		newcp	dst
+		newcm	src, dst
+		newcmp	src, dst
+Function:	dst = new(Channel)
+.P2
+The 
+.CW "newc"
+instruction allocates a new channel of the specified type and stores a reference to the channel in 
+.CW "dst" .
+For the 
+.CW "newcm"
+instruction the source specifies the number of bytes of memory used by values sent on the channel (see the
+.CW movm
+instruction above).
+For the 
+.CW "newcmp"
+instruction the first operand specifies a type descriptor giving the length of the structure and the location of pointers within the structure (see the
+.CW movmp
+instruction above).
+.SH
+or\fIx\fP \- Logical OR
+.P1
+Syntax:		orb	src1, src2, dst
+		orw	src1, src2, dst
+		orl	src1, src2, dst
+Function:	dst = src1 | src
+.P2
+These instructions compute the bitwise OR of the two operands addressed by 
+.CW "src1"
+and 
+.CW "src2"
+and store the result in the 
+.CW "dst"
+operand.
+.SH
+recv \- Receive from channel
+.P1
+Syntax:		recv	src, dst
+Function:	dst = <-src
+.P2
+The 
+.CW "recv"
+instruction receives a value from some other thread on the channel specified by the 
+.CW "src"
+operand. Communication is synchronous, so the calling thread will block until a corresponding 
+.CW "send"
+or 
+.CW "alt"
+is performed on the channel. The type of the received value is determined by the channel type and the 
+.CW "dst"
+operand specifies where to place the received value.
+.SH
+ret \- Return from function
+.P1
+Syntax:		ret
+Function:	npc = link(fp)
+		mod = mod(fp)
+		fp = frame(fp)
+		pc = npc
+.P2
+The 
+.CW "ret"
+instruction returns control to the instruction after the call of the current function.
+.SH
+send \- Send to channel
+.P1
+Syntax:		send	src, dst
+Function:	dst <-= src
+.P2
+The 
+.CW "send"
+instruction sends a value from this thread to some other thread on the channel specified by the 
+.CW "dst"
+operand. Communication is synchronous so the calling thread will block until a corresponding 
+.CW "recv"
+or 
+.CW "alt"
+is performed on the channel. The type of the sent value is determined by the channel type and the 
+.CW "dst"
+operand specifies where to retrieve the sent value.
+.SH
+shl\fIx\fP \- Shift left arithmetic
+.P1
+Syntax:		shlb	src1, src2, dst
+		shlw	src1, src2, dst
+		shll	src1, src2, dst
+Function:	dst = src2 << src1
+.P2
+The 
+.CW "shl"
+instructions shift the 
+.CW "src2"
+operand left by the number of bits specified by the 
+.CW "src1"
+operand and store the result in the 
+.CW "dst"
+operand. Shift counts less than 0 or greater than the number of bits in the object have undefined results.
+.SH
+shr\fIx\fP \- Shift right arithmetic
+.P1
+Syntax:		shrb	src1, src2, dst
+		shrw	src1, src2, dst
+		shrl	src1, src2, dst
+Function:	dst = src2 >> src1
+.P2
+The 
+.CW "shr"
+instructions shift the 
+.CW "src2"
+operand right by the number of bits specified by the 
+.CW "src1"
+operand and store the result in the 
+.CW "dst"
+operand. Shift counts less than 0 or greater than the number of bits in the object have undefined results.
+.SH
+slicea \- Slice array
+.P1
+Syntax:		slicea	src1, src2, dst
+Function:	dst = dst[src1:src2]
+.P2
+The 
+.CW "slicea"
+instruction creates a new array, which contains the elements from the index at 
+.CW "src1"
+to the index
+.CW "src2-1" .
+The new array is a reference array which points at the elements in the initial array. The initial array will remain allocated until both arrays are no longer referenced.
+.SH
+slicec \- Slice string
+.P1
+Syntax:		slicec	src1, src2, dst
+Function:	dst = dst[src1:src2]
+.P2
+The 
+.CW "slicec"
+instruction creates a new string, which contains characters from the index at 
+.CW "src1"
+to the index
+.CW "src2-1" .
+Unlike 
+.CW "slicea"
+, the new string is a copy of the elements from the initial string.
+.SH
+slicela \- Assign to array slice
+.P1
+Syntax:		slicela	  src1, src2, dst
+Function:	dst[src2:] = src1
+.P2
+The 
+.CW "src1"
+and 
+.CW "dst"
+operands must be arrays of equal types. The 
+.CW "src2"
+operand is a non-negative integer index. The 
+.CW "src1"
+array is assigned to the array slice 
+.CW "dst[src2:]" ; 
+.CW "src2 + nelem(src1)"
+must not exceed 
+.CW "nelem(dst)" .
+.SH
+spawn \- Spawn function
+.P1
+Syntax:		spawn	src, dst
+Function:	fork();
+		if(child)
+			dst(src);
+.P2
+The 
+.CW "spawn"
+instruction creates a new thread and calls the function specified by the 
+.CW "dst"
+operand. The argument frame passed to the thread function is specified by the 
+.CW "src"
+operand and should have been created by the 
+.CW "frame"
+instruction.
+.SH
+sub\fIx\fP \- Subtract	
+.P1
+Syntax:		subb	src1, src2, dst
+		subf	src1, src2, dst
+		subw	src1, src2, dst
+		subl	src1, src2, dst
+Function:	dst = src2 - src1
+.P2
+The 
+.CW "sub"
+instructions subtract the operands addressed by 
+.CW "src1"
+and 
+.CW "src2"
+and stores the result in the 
+.CW "dst"
+operand. For 
+.CW "subb" ,
+the result is truncated to eight bits.
+.SH
+tail \- Tail of list
+.P1
+Syntax:		tail	src, dst
+Function:	dst = src->next
+.P2
+The 
+.CW "tail"
+instruction takes the list specified by the 
+.CW "src"
+operand and creates a reference to a new list with the head removed, which is stored in the 
+.CW "dst"
+operand.
+.SH
+tcmp \- Compare types
+.P1
+Syntax:		tcmp	src, dst
+Function:	if(typeof(src) != typeof(dst))
+			error("typecheck");
+.P2
+The 
+.CW "tcmp"
+instruction compares the types of the two pointers supplied by the 
+.CW "src"
+and 
+.CW "dst"
+operands. The comparison will succeed if the two pointers were created from the same type descriptor or the 
+.CW "src"
+operand is 
+.CW "nil" ;
+otherwise, the program will error. The 
+.CW "dst"
+operand must be a valid pointer.
+.SH
+xor\fIx\fP \- Exclusive OR
+.P1
+Syntax:		xorb	src1, src2, dst
+		xorw	src1, src2, dst
+		xorl	src1, src2, dst
+Function:	dst = src1 ^ src2
+.P2
+These instructions compute the bitwise exclusive-OR of the two operands addressed by 
+.CW "src1"
+and 
+.CW "src2"
+and store the result in the 
+.CW "dst"
+operand.
+.NH 1
+Object File Format
+.LP
+An object file defines a single module. The file has the following structure:
+.P1
+Objfile
+{
+	Header;
+	Code_section;
+	Type_section;
+	Data_section;
+	Module_name;
+	Link_section;
+};
+.P2
+The following data types are used in the description of the file encoding:
+.IP
+.TS
+lf(CW) lw(4i)fR .
+OP	T{
+encoded integer operand, encoding selected by the two most significant bits as follows:
+.nf
+00 signed 7 bits, 1 byte
+.br
+10 signed 14 bits, 2 bytes
+.br
+11 signed 30 bits, 4 bytes
+T}
+B	unsigned byte
+W	32 bit signed integer
+F	canonicalized 64-bit IEEE754 floating point value
+SO	16 bit unsigned small offset from register
+SI	16 bit signed immediate value
+LO	30 bit signed large offset from register
+.TE
+.LP
+All binary values are encoded in two's complement format, most significant byte first.
+.SH
+The Header Section
+.P1
+Header
+{
+	OP: magic_number;
+	Signature;
+	OP: runtime_flag;
+	OP: stack_extent;
+	OP: code_size;
+	OP: data_size;
+	OP: type_size;
+	OP: link_size;
+	OP: entry_pc;
+	OP: entry_type;
+};
+.P2
+The magic number is defined as 819248
+(symbolically
+.CW XMAGIC ),
+for modules that have not been signed cryptographically, and 923426
+(symbolically
+.CW "SMAGIC" ),
+for modules that contain a signature.
+On the Inferno system, the symbolic names
+.CW "XMAGIC"
+and
+.CW SMAGIC
+are defined by the C include file
+.CW "/include/isa.h"
+and the Limbo module
+.CW /module/dis.m .
+.LP
+The signature field is only present if the magic number is
+.CW "SMAGIC" .
+It has the form:
+.P1
+Signature
+{
+	OP: length;
+	array[length] of byte: signature;
+};
+.P2
+A digital signature is defined by a length, followed by an array of untyped bytes.
+Data within the signature should identify the signing authority, algorithm, and data to be signed.
+.LP
+The
+.CW runtime_flag
+is a bit mask that defines various execution options for a Dis module. The flags currently defined are:
+.P1
+MUSTCOMPILE	= 1<<0
+DONTCOMPILE	= 1<<1
+SHAREMP		= 1<<2
+.P2
+The 
+.CW "MUSTCOMPILE"
+flag indicates that a 
+.CW "load"
+instruction should draw an error if the implementation is unable to compile the module into native instructions using a just-in-time compiler.
+.LP
+The 
+.CW "DONTCOMPILE"
+flag indicates that the module should not be compiled into native instructions, even though it is the default for the runtime environment. This flag may be set to allow debugging or to save memory.
+.LP
+The 
+.CW "SHAREMP"
+flag indicates that each instance of the module should use the same module data for all instances of the module. There is no implicit synchronization between threads using the shared data.
+.LP
+The
+.CW stack_extent
+value indicates the number of bytes by which the thread stack of this module should be extended in the event that procedure calls exhaust the allocated stack. While stack extension is transparent to programs, increasing this value may improve the efficiency of execution at the expense of using more memory.
+.LP
+The
+.CW code_size
+is a count of the number of instructions stored in the Code_section.
+.LP
+The
+.CW data_size
+gives the size in bytes of the module's global data, which is initialized
+by evaluating the contents of the data section.
+.LP
+The
+.CW type_size
+is a count of the number of type descriptors stored in the Type_section.
+.LP
+The
+.CW link_size
+is a count of the number of external linkage directives stored in the Link_section.
+.LP
+The
+.CW entry_pc
+is an integer index into the instruction stream that is the default entry point for this module. The
+.CW entry_pc
+should point to the first instruction of a function. Instructions are numbered from a program counter value of zero.
+.LP
+The
+.CW entry_type
+is the index of the type descriptor that corresponds to the function entry point set by
+.CW entry_pc .
+.SH
+The Code Section
+.LP
+The code section describes a sequence of instructions for the virtual machine. An instruction is encoded as follows:
+.P1
+Instruction
+{
+	B: opcode;
+	B: address_mode;
+	Middle_data;
+	Source_data;
+	Dest_data;
+};
+.P2
+.LP
+The
+.CW opcode
+specifies the instruction to execute, encoded as follows:
+.IP
+.TS
+tab(:);
+l l l l l .
+00 nop:20 headb:40 mulw:60 blew:80 shrl
+01 alt:21 headw:41 mulf:61 bgtw:81 bnel
+02 nbalt:22 headp:42 divb:62 bgew:82 bltl
+03 goto:23 headf:43 divw:63 beqf:83 blel
+04 call:24 headm:44 divf:64 bnef:84 bgtl
+05 frame:25 headmp:45 modw:65 bltf:85 bgel
+06 spawn:26 tail:46 modb:66 blef:86 beql
+07 runt:27 lea:47 andb:67 bgtf:87 cvtlf
+08 load:28 indx:48 andw:68 bgef:88 cvtfl
+09 mcall:29 movp:49 orb:69 beqc:89 cvtlw
+0A mspawn:2A movm:4A orw:6A bnec:8A cvtwl
+0B mframe:2B movmp:4B xorb:6B bltc:8B cvtlc
+0C ret:2C movb:4C xorw:6C blec:8C cvtcl
+0D jmp:2D movw:4D shlb:6D bgtc:8D headl
+0E case:2E movf:4E shlw:6E bgec:8E consl
+0F exit:2F cvtbw:4F shrb:6F slicea:8F newcl
+10 new:30 cvtwb:50 shrw:70 slicela:90 casec
+11 newa:31 cvtfw:51 insc:71 slicec:91 indl
+12 newcb:32 cvtwf:52 indc:72 indw:92 movpc
+13 newcw:33 cvtca:53 addc:73 indf:93 tcmp
+14 newcf:34 cvtac:54 lenc:74 indb:94 mnewz
+15 newcp:35 cvtwc:55 lena:75 negf:95 cvtrf
+16 newcm:36 cvtcw:56 lenl:76 movl:96 cvtfr
+17 newcmp:37 cvtfc:57 beqb:77 addl:97 cvtws
+18 send:38 cvtcf:58 bneb:78 subl:98 cvtsw
+19 recv:39 addb:59 bltb:79 divl:99 lsrw
+1A consb:3A addw:5A bleb:7A modl:9A lsrl
+1B consw:3B addf:5B bgtb:7B mull:9B eclr
+1C consp:3C subb:5C bgeb:7C andl:9C newz
+1D consf:3D subw:5D beqw:7D orl:9D newaz
+1E consm:3E subf:5E bnew:7E xorl
+1F consmp:3F mulb:5F bltw:7F shll
+.TE
+.LP
+The
+.CW address_mode
+byte specifies the addressing mode of each of the three operands: middle, source and destination. The source and destination operands are encoded by three bits and the middle operand by two bits. The bits are packed as follows:
+.P1
+bit	 7  6  5  4  3  2  1  0
+	m1 m0 s2 s1 s0 d2 d1 d0
+.P2
+The middle operand is encoded as follows:
+.IP
+.TS
+lf(CW) lf(CW)	lw(3i)fR .
+00	\fInone\fP	no middle operand	
+01	$SI	small immediate
+10	SO(FP)	small offset indirect from FP
+11	SO(MP)	small offset indirect from MP
+.TE
+.LP
+The source and destination operands are encoded as follows:
+.IP
+.TS
+lf(CW) lf(CW)	lw(3i)fR .
+000	LO(MP)	offset indirect from MP
+001	LO(FP)	offset indirect from FP
+010	$OP	30 bit immediate
+011	\fInone\fP	no operand
+100	SO(SO(MP))	double indirect from MP
+101	SO(SO(FP))	double indirect from FP
+110	\fIreserved\fP
+111	\fIreserved\fP
+.TE
+.LP
+The
+.CW middle_data
+field is only present if the middle operand specifier of the address_mode is not  `none'.
+If the field is present it is encoded as an 
+.CW "OP" .
+.LP
+The
+.CW source_data
+and
+.CW dest_data
+fields are present only if the corresponding
+.CW address_mode
+field is not `none'.
+For offset indirect and immediate modes the field contains a single 
+.CW "OP" .
+For double indirect modes the values are encoded as two 
+.CW "OP"
+values: the first value is the register indirect offset, and the second value is the final indirect offset. The offsets for double indirect addressing cannot be larger than 16 bits.
+.SH
+The Type Section
+.LP
+The type section contains type descriptors describing the layout of pointers within data types. The format of each descriptor is:
+.P1
+Type_descriptor
+{
+	OP: desc_number;
+	OP: size;
+	OP: number_ptrs;
+	array[number_ptrs] of B: map;
+};
+.P2
+.LP
+The
+.CW desc_number
+is a small integer index used to identify the descriptor to instructions such as 
+.CW "new" .
+.LP
+The 
+.CW "size"
+field is the size in bytes of the memory described by this type.
+.LP
+The
+.CW number_ptrs
+field gives the size in bytes of the 
+.CW "map"
+array.
+.LP
+The 
+.CW "map"
+array is a bit vector where each bit corresponds to a word in memory.
+The most significant bit corresponds to the lowest address.
+For each bit in the map,
+the word at the corresponding offset in the type is a pointer iff the bit is set to 1.
+.SH
+The Data Section
+.LP
+The data section encodes the contents of the
+.CW "MP"
+data for the module. The section contains a sequence of items; each item contains
+a control byte and an offset into the section,
+followed by one or more data items.
+A control byte of zero marks the end of the data section.
+Otherwise, it gives the type of data to be loaded and selects between
+two representations of an item:
+.P1
+Short_item
+{
+	B: code;
+	OP: offset;
+	array[code & 16rF] of type[code>>4]: data;
+};
+.P3
+Long_item
+{
+	B: code;
+	OP: count;
+	OP: offset;
+	array[ndata] of type[code>>4]: data;
+};
+.P2
+A
+.CW Short_item
+is generated for 15 or fewer items, otherwise a
+.CW "Long_item"
+is generated. In a
+.CW "Long_item"
+the count field (bottom 4 bits of code) is set to zero and the count follows as an
+.CW "OP" .
+The top 4 bits of code determine the type of the datum.
+The defined values are:
+.IP
+.TS
+lf(CW)	lw(3i)f(R) .
+0001	8 bit bytes
+0010	32 bit words
+0011	utf encoded string
+0100	real value IEEE754 canonical representation
+0101	Array
+0110	Set array address
+0111	Restore load address
+1000	64 bit big
+.TE
+.LP
+The byte, word, real and big operands are encoded as sequences
+of bytes (of appropriate length) in big-endian form, converted to native
+format before being stored in the data space.
+The `string' code takes a UTF-encoded sequence of
+.CW count
+bytes, which is converted to an array of 21-bit Unicode values stored in an
+implementation-dependent structure on
+the heap; a 4-byte pointer to the string descriptor is stored in the data space.
+The `array' code takes two 4-byte operands: the first is the index of the array's type
+descriptor in the type section; the second is the length of the array to be created.
+The result in memory is a 4-byte pointer to an implementation-dependent
+array descriptor in the heap.
+.LP
+Each item's data is stored at the address formed by adding the
+.CW offset
+in that item to a base address maintained by the loader.
+Initially that address is the base of the data space of the module instance.
+A new base for loading subsequent items can be set or restored by
+the following operations, used to initialize arrays.
+The `set array index' item must appear immediately following an `array'
+item.
+Its operand is a 4-byte big-endian integer that gives an index into that
+array, at which address subsequent data should be loaded; the
+previous load address is stacked internally.
+Subsequent data will be loaded at offsets from the new base address.
+The `restore load address' item has no operands; it pops a load address
+from the internal address stack and makes that the new
+base address.
+.SH
+The Module Name
+.LP
+The module name immediately follows the data section.
+It contains the name of the implementation module, in UTF encoding,
+terminated by a zero byte.
+.SH
+The Link Section
+.LP
+The link section contains an array of external linkage items:
+the list of functions exported by this module.
+Each item describes one exported function in the following form:
+.P1
+Linkage_item
+{
+	OP: pc;
+	OP: desc_number;
+	W: sig;
+	array[] of byte: name;
+};
+.P2
+The
+.CW pc
+is the instruction number of the function's entry point.
+The
+.CW desc_number
+is the index, in the type section, of the type descriptor for the function's stack frame.
+The
+.CW sig
+word is a 32-bit hash of the function's type signature.
+Finally,
+the name of the function is stored as a variable length array of bytes
+in UTF-8 encoding,
+with the end of the array marked by a zero byte.
+The names of member functions of an exported adt are qualified
+by the name of the adt.
+The next linkage item, if any, follows immediately.
+.NH 1
+Symbol Table File Format
+.LP
+The object file format does not include type information for debuggers.
+The Limbo compiler can optionally produce a separate symbol table file.
+Its format is defined in the entry
+.I sbl (6)
+of [1].
+.NH 1
+References
+.IP 1.
+.I "Inferno Programmer's Manual"
+(Third Edition),
+Volume 1 (`the manual'),
+Vita Nuova Holdings Limited, June 2000.
+.IP 2.
+P Winterbottom and R Pike,
+``The Design of the Inferno Virtual Machine'',
+reprinted in this volume.
binary files /dev/null b/doc/dis.pdf differ
--- /dev/null
+++ b/doc/ebookimp.ms
@@ -1,0 +1,389 @@
+.TL
+Navigating Large XML Documents on Small Devices
+.AU
+Roger Peppe
+.AI
+Vita Nuova
+.br
+April 2002
+.AB
+Browsing eBooks on platforms with limited memory presents an
+interesting problem: how can memory usage be bounded despite
+the need to view documents that may be much larger than the
+available memory. A simple interface to an XML parser enables
+this whilst retaining much of the ease of access afforded
+by XML parsers that read all of a document into memory at once.
+.AE
+.SH
+Introduction
+.LP
+The Open Ebook Publication Structure was devised by the Open Ebook Forum
+in order to ``provide a specification for representing the content of electronic
+books''. It is based on many existing standards, notably XML and HTML.
+An Open eBook publication consists of a set of documents bound together
+with an Open eBook package file which enumerates all the documents,
+pictures and other items that make up the book
+.LP
+The underlying document format is essentially HTML compatible,
+which is where the first problem arises: HTML was not designed to
+make it easy to view partial sections of a document. Conventionally
+an entire HTML document is read in at once and rendered onto
+the device. When viewing an eBook on a limited-memory device,
+however, this may not be possible; books tend to be fairly large.
+For such a device, the ideal format would keep the book itself
+in non-volatile storage (e.g. flash or disk) and make it possible
+for reader to seek to an arbitrary position in the book and render
+what it finds there.
+.LP
+This is not possible in an HTML or XML document, as the
+arbitrarily nested nature of the format means that every
+position in the document has some unknown surrounding context,
+which cannot be discovered without reading sequentially through
+the document from the beginning.
+.SH
+SAX and DOM
+.LP
+There are two conventional programming interfaces to an XML
+parser. A SAX parser provides a stream of XML entities, leaving
+it up to the application to maintain the context. It is not possible
+to rewind the stream, except, perhaps, to the beginning.
+Using a SAX parser is
+fairly straightforward, but awkward: the stream-like nature
+of the interface does not map well to the tree-like structure
+that is XML. A DOM parser reads a whole document into an internal
+data structure representation, so a program can treat it exactly
+as a tree. This also enables a program to access parts of the
+document in an arbitrary order.
+The DOM approach is all very well for small documents, but for large
+documents the memory usage can rapidly grow to exceed
+the available memory capacity. For eBook documents, this is unacceptable.
+.SH
+A different approach
+.LP
+The XML parser used in the eBook browser is akin to a SAX parser,
+in that only a little of the XML structure is held in memory at one time.
+The first significant difference is that the XML entities returned are
+taken from one level of the tree - if the program does not wish to
+see the contents of a particular XML tag, it is trivial to skip over.
+The second significant difference is that random access is possible.
+This possibility comes from the observation that if we have visited
+a part of the document we can record the context that we found there
+and restore it later if necessary. In this scheme, if we wish to return later to
+a part of a document that we are currently at, we can create a ``mark'',
+a token that holds the current context; at some later time we can use
+that mark to return to this position.
+.LP
+The eBook browser uses this technique to enable random access
+to the document on a page-by-page basis. Moreover a mark
+can be written to external storage, thus allowing an external
+``index'' into the document so it is not always necessary to
+read the entire document from the start in order to jump to a particular
+page in that document.
+.SH
+The programming interface
+.LP
+The interface is implemented by a module named
+.CW Xml ,
+which provides a
+.CW Parser
+adt which gives access to the contents of an XML document.
+Xml items are represented by an
+.CW Item
+pick adt with one branch of the pick corresponding to each
+type of item that might be encountered.
+.LP
+The interface to the parser looks like this:
+.P1
+open: fn(f: string, warning: chan of (Locator, string)): (ref Parser, string);
+Parser: adt {
+    next:       fn(p: self ref Parser): ref Item;
+    down:   fn(p: self ref Parser);
+    up:     fn(p: self ref Parser);
+    mark:   fn(p: self ref Parser): ref Mark;
+    atmark: fn(p: self ref Parser, m: ref Mark): int;
+    goto:   fn(p: self ref Parser, m: ref Mark);
+    str2mark:   fn(p: self ref Parser, s: string): ref Mark;
+};
+.P2
+To start parsing an XML document, it must first be
+.CW open ed;
+.CW warning
+is a channel on which non-fatal error messages will be sent
+if they are encountered during the parsing of the document.
+It can be nil, in which case warnings are ignored.
+If the document is opened successfully, a new
+.CW Parser
+adt, say
+.I p ,
+is returned.
+Calling
+.CW \fIp\fP.next
+returns the next XML item at the current level of the tree. If there
+are no more items in the current branch at the current level, it
+returns
+.CW nil .
+When a
+.CW Tag
+item is returned,
+.CW \fIp\fP.down
+can be used to descend ``into'' that tag; subsequent calls of
+.CW \fIp\fP.next
+will return XML items contained within the tag,
+and
+.CW \fIp\fP.up
+returns to the previous level.
+.LP
+An
+.CW Item
+is a pick adt:
+.P1
+Item: adt {
+    fileoffset: int;
+    pick {
+    Tag =>
+        name:   string;
+        attrs:      Attributes;
+    Text =>
+        ch:     string;
+        ws1, ws2: int;
+    Process =>
+        target: string;
+        data:       string;
+    Doctype =>
+        name:   string;
+        public: int;
+        params: list of string;
+    Stylesheet =>
+        attrs:      Attributes;
+    Error =>
+        loc:        Locator;
+        msg:        string;
+    }
+};
+.P2
+.CW Item.Tag
+represents a XML tag, empty or not. The XML
+fragments
+.CW "<tag></tag>" '' ``
+and
+.CW "<tag />" '' ``
+look identical from the point of view of this interface.
+A
+.CW Text
+item holds text found in between tags, with adjacent whitespaces merged
+and whitespace at the beginning and end of the text elided.
+.CW Ws1
+and
+.CW ws2
+are non-zero if there was originally whitespace at the beginning
+or end of the text respectively.
+.CW Process
+represents an XML processing request, as found between
+.CW "<?....?>" '' ``
+delimiters.
+.CW Doctype
+and
+.CW Stylesheet
+are items found in an XML document's prolog, the
+former representing a
+.CW "<!DOCTYPE...>" '' ``
+document type declaration, and the latter an XML
+stylesheet processing request.
+.LP
+When most applications are processing documents, they
+will wish to ignore all items other than
+.CW Tag
+and
+.CW Text .
+To this end, it is conventional to define a ``front-end'' function
+to return desired items, discard others, and take an appropriate
+action when an error is encountered. Here's an example:
+.P1
+nextitem(p: ref Parser): ref Item
+{
+    while ((gi := p.next()) != nil) {
+        pick i := gi {
+        Error =>
+            sys->print("error at %s:%d: %s\n",
+                i.loc.systemid, i.loc.line, i.msg);
+            exit;
+        Process =>
+            ;   # ignore
+        Stylesheet  =>
+            ;   # ignore
+        Doctype =>
+            ;   # ignore
+        * =>
+            return gi;
+        }
+    }
+    return nil;
+}
+.P2
+When
+.CW nextitem
+encounters an error, it exits; it might instead handle the
+error another way, say by raising an exception to be caught at the
+outermost level of the parsing code.
+.SH
+A small example
+.LP
+Suppose we have an XML document that contains some data that we would
+like to extract, ignoring the rest of the document. For this example we will
+assume that the data is held within
+.CW <data>
+tags, which contain zero or more
+.CW <item>
+tags, holding the actual data as text within them.
+Tags that we do not recognize we choose to ignore.
+So for example, given the following XML document:
+.P1
+<metadata>
+    <a>hello</a>
+    <b>goodbye</b>
+</metadata>
+<data>
+    <item>one</item>
+    <item>two</item>
+    <item>three</item>
+</data>
+<data>
+    <item>four</item>
+</data>
+.P2
+we wish to extract all the data items, but ignore everything inside
+the
+.CW <metadata>
+tag. First, let us define another little convenience function to get
+the next XML tag, ignoring extraneous items:
+.P1
+nexttag(p: ref Parser): ref Item.Tag
+{
+    while ((gi := nextitem(p)) != nil) {
+        pick i := gi {
+        Tag =>
+            return i;
+        }
+    }
+    return nil;
+}
+.P2
+Assuming that the document has already been opened,
+the following function scans through the document, looking
+for top level
+.CW <data>
+tags, and ignoring others:
+.P1
+document(p: ref Parser)
+{
+    while ((i := nexttag(p)) != nil) {
+        if (i.name == "data") {
+            p.down();
+            data(p);
+            p.up();
+        }
+    }
+}
+.P2
+The function to parse a
+.CW <data>
+tag is almost as straightforward; it scans for
+.CW <item>
+tags and extracts any textual data contained therein:
+.P1
+data(p: ref Parser)
+{
+    while ((i := nexttag(p)) != nil) {
+        if (i.name == "item") {
+            p.down();
+            if ((gni := p.next()) != nil) {
+                pick ni := gni {
+                Text =>
+                    sys->print("item data: %s\n", ni.ch);
+                }
+            }
+            p.up();
+        }
+    }
+}
+.P2
+The above program is all very well and works fine, but
+suppose that the document that we are parsing is very
+large, with data items scattered through its length, and that
+we wish to access those items in an order that is not necessarily
+that in which they appear in the document.
+This is quite straightforward; every time we see a
+data item, we record the current position with a mark.
+Assuming the global declaration:
+.P1
+marks: list of ref Mark;
+.P2
+the
+.CW document
+function might become:
+.P1
+document(p: ref Parser)
+{
+    while ((i := nexttag(p)) != nil) {
+        if (i.name == "data") {
+            p.down();
+            marks = p.mark() :: marks;
+            p.up();
+        }
+    }
+}
+.P2
+At some later time, we can access the data items arbitrarily,
+for instance:
+.P1
+    for (m := marks; m != nil; m = tl m) {
+        p.goto(hd m);
+        data(p);
+    }
+.P2
+If we wish to store the data item marks in some external index
+(in a file, perhaps), the
+.CW Mark
+adt provides a
+.CW str
+function which returns a string representation of the mark.
+.CW Parser 's
+.CW str2mark
+function can later be used to recover the mark. Care must
+be taken that the document it refers to has not been changed,
+otherwise it is likely that the mark will be invalid.
+.SH
+The eBook implementation
+.LP
+The Open eBook reader software uses the primitives described above
+to maintain display-page-based access to arbitrarily large documents
+while trying to bound memory usage.
+Unfortunately it is difficult to unconditionally bound memory usage,
+given that any element in an XML document may be arbitrarily
+large. For instance a perfectly legal document might have 100MB
+of continuous text containing no tags whatsoever. The described
+interface would attempt to put all this text in one single item, rapidly
+running out of memory! Similar types of problems can occur when
+gathering the items necessary to format a particular tag.
+For instance, to format the first row of a table, it is necessary to lay out
+the entire table to determine the column widths.
+.LP
+I chose to make the simplifying assumption that top-level items within
+the document would be small enough to fit into memory.
+From the point of view of the display module, the document
+looks like a simple sequence of items, one after another.
+One item might cover more than one page, in which case a different
+part of it will be displayed on each of those pages.
+.LP
+One difficulty is that the displayed size of an item depends on many
+factors, such as stylesheet parameters, size of installed fonts, etc.
+When a document is read, the page index must have been created
+from the same document with the same parameters. It is difficult in
+general to enumerate all the relevant parameters; they would need
+to be stored inside, or alongside the index; any change would invalidate
+the index. Instead of doing this, as the document is being displayed,
+the eBook display program constantly checks to see if the results
+it is getting from the index match with the results it is getting
+when actually laying out the document. If the results differ, the
+index is remade; the discrepancy will hopefully not be noticed by
+the user!
binary files /dev/null b/doc/ebookimp.pdf differ
--- /dev/null
+++ b/doc/fonts
@@ -1,0 +1,8 @@
+# mkfile rules to get fonts in Lucida Sans.
+# if you don't have Lucida fonts, change this next line to
+# FONTS=''
+FONTS='.fp 1 R LucidaSans
+.fp 2 I LucidaSansI
+.fp 3 B LucidaSansB
+.fp 5 CW LucidaCW
+'
--- /dev/null
+++ b/doc/fonts.bem
@@ -1,0 +1,7 @@
+# FONTS=''
+FONTS='.fp 1 R BemboBookMTStd-Regular
+.fp 2 I BemboBookMTStd-Italic
+.fp 3 B BemboBookMTStd-Bold
+.fp 4 BI BemboBookMTStd-BoldIt
+....fp 5 L LucidaCW
+'
--- /dev/null
+++ b/doc/fonts.pal
@@ -1,0 +1,9 @@
+# mkfile rules to get fonts in Lucida Sans.
+# if you don't have Lucida fonts, change this next line to
+# FONTS=''
+FONTS='.fp 1 R PA
+.fp 2 I PI
+.fp 3 B PB
+.fp 4 PX
+....fp 5 L LucidaCW
+'
binary files /dev/null b/doc/frontmatter.pdf differ
--- /dev/null
+++ b/doc/gridinstall.ms
@@ -1,0 +1,136 @@
+.FP palatino
+.TL
+Installing the Vita Nuova grid software
+.AU
+Vita Nuova
+.br
+5 May 2005
+.NH 1
+Package contents
+.LP
+The installation CD contains software for  both grid client and the server (scheduler),
+in separate directories in the root directory of the CD:
+.B client
+and
+.B server .
+.NH 1
+Client software
+.LP
+The grid client software will be installed on Windows NT4/2000/XP machines,
+in the directory (folder)
+.CW C:\eVNClient .
+.IP 1.
+On a Windows machine with the CD loaded,
+use Windows Explorer (or equivalent) to move to the directory named
+.CW \eclient\einstall
+on the CD.
+.IP 2.
+Double-click
+.CW setup.exe
+in that directory.
+It will display a new window that prompts for a destination directory.
+The directory need not exist but if it does, it should be empty.
+The default should be
+.CW C:\eVNClient .
+You can change the name if required (eg, because
+.CW C:
+lacks space), but
+you will then need to edit several files, as discussed below,
+and make appropriate changes to the instructions below.
+Hit the
+.SM ENTER
+key to start installation.
+The program will prompt for permission to create the directory if it does not already exist.
+It will then populate it with all files required by the client.
+.IP 3.
+Move in Explorer to the directory
+.CW C:\eVNClient\egrid\eslave .
+Check that the file
+.CW schedaddr
+contains the right address for your scheduler machine.
+If you changed the drive letter, you must also change the
+four
+.CW .bat
+files in the directory to replace the
+.CW C:
+drive letter by the one you used.
+.IP 4.
+You can now add the grid client as a Windows service by running the appropriate
+.CW .bat
+file on the client.
+Use
+.RS
+.IP
+\f5install_service.bat\fP
+for Windows 2000 and Windows XP
+.IP \fIOR\fP
+\f5install_service_nt4.bat\fP
+for Windows NT4
+.LP
+Just double-clicking in Explorer on the chosen name should install the service.
+.RE
+.LP
+Once installed as a service the client software will start automatically when
+the client machine next boots.
+You can start it manually using the Windows Services Manager in the usual way.
+There are two
+.CW .bat
+files to remove the service (when desired): \f5remove_service.bat\fP
+for 2000/XP and \f5remove_service_nt4.bat\fP for NT4.
+.LP
+The manual page
+.I scheduler-intro (1)
+in the PDF file
+.CW \escheduler.pdf
+on the CD gives more details on running and configuring the client software.
+The manual page
+.I scheduler-monitor (1)
+in the same PDF file describes the use of the Client Monitor software.
+.LP
+On Windows machines you can remove the directory
+.CW C:\eVNClient\eLinux
+to reduce the space required on Windows clients.
+.NH 1
+Server software
+.LP
+The grid server software will be installed on Linux (Redhat 8 or 9), in the directory
+.CW /grid/inferno ,
+which should either not exist or be empty.
+.LP
+Linux will usually mount the CD at
+.CW /mnt/cdrom .
+.IP 1.
+In a shell (`New Terminal') window, type the following command:
+.P1
+sh /mnt/cdrom/server/install/Linux-grid-386.sh
+.P2
+Assuming it has permission to do so, it will populate
+.CW /grid/inferno
+with the Inferno distribution, including the grid scheduler components.
+.IP 2.
+The file
+.CW /mnt/cdrom/server/install/gridsched.sh
+contains a Bourne shell script that can be copied to an appropriate
+place on your system, or used as the basis for one of your own,
+to simplify starting the scheduler.
+In particular it sets the right bin directory in
+.CW PATH
+to find Inferno's
+.I emu ,
+and starts
+.I emu
+with the right parameters to find the
+.CW /grid/inferno
+directory and start the scheduler in the right environment.
+.LP
+Now check that
+.CW /grid/inferno/grid/master/config
+contains the right network address for your scheduler.
+The manual pages
+.I scheduler-intro (1)
+and
+.I scheduler (1)
+in
+.CW scheduler.pdf
+on the CD give more details on invoking the scheduler in
+different ways.
binary files /dev/null b/doc/gridinstall.pdf differ
--- /dev/null
+++ b/doc/hotchips.ms
@@ -1,0 +1,125 @@
+.TL
+The design of the Inferno virtual machine
+.AU
+.I "Phil Winterbottom"
+.I "Rob Pike"
+.AI
+.I "Bell Labs, Lucent Technologies"
+.FS
+Originally appeared in
+.I "IEEE Compcon 97 Proceedings" ,
+1997.
+.FE
+.SP .22i exactly
+.AB
+Virtual machines are an important component of modern portable environments such as Inferno and Java because they provide an architecture-independent representation of executable code.  Their performance is critical to the success of such environments, but they are difficult to design well because they are subject to conflicting goals.  On the one hand, they offer a way to hide the differences between instruction architectures; on the other, they must be implemented efficiently on a variety of underlying machines.  A comparison of the engineering and evolution of the Inferno and Java virtual machines provides insight into the tradeoffs in their design and implementation.  We argue that the design of virtual machines should be rooted in the nature of modern processors, not language interpreters, with an eye towards on-the-fly compilation rather than interpretation or special-purpose silicon.
+.AE
+.SH
+Dis, the Inferno Virtual Machine
+.LP
+In early 1995, we set out to apply the ideas of the Plan 9 operating system [1] to a wider range of devices and networks.  The resulting system, Inferno [2], is a small operating system and execution environment that supports application portability across a wide variety of processors and operating systems.  Unaware of the contemporary work to establish Java [3] from the technology of the Oak project, we independently concluded that a virtual machine (VM) was a necessary component of such a system [4].  Because of improvements in processor speed and the feasibility of on-the-fly compilers, a VM can execute quickly enough to be economically viable.
+.LP
+The Inferno virtual machine, called Dis, has several unusual aspects to its design: the instruction set, the module system, and the garbage collector.
+.LP
+The Dis instruction set provides a close match to the architecture of existing processors.  Instructions are of the form
+.DS
+.ft I
+OP	src1, src2, dst
+.ft P
+.DE
+The
+.I "src1"
+and
+.I "dst"
+operands specify general addresses or arbitrary-sized constants, while the
+.I "src2"
+operand is restricted to smaller constants and stack offsets to reduce code space.  Each operand specifies an address either in the stack frame of the executing procedure or in the global data of its module.
+.LP
+The types of operands are set by the instructions.  Basic types are
+.CW "word"
+(32-bit signed),
+.CW "big"
+(64-bit signed),
+.CW "byte"
+(8-bit unsigned),
+.CW "real"
+(64-bit IEEE floating point), and pointer (implementation-dependent).  The instruction set follows the example of CISC processors, providing three-operand memory-to-memory operations for arithmetic, data motion, and so on.  It also has instructions to allocate memory, to load modules, and to create, synchronize, and communicate between processes.
+.LP
+A module is the unit of dynamically loaded code and data.  Modules are loaded by a VM instruction that returns a pointer to a method table for the module.  That pointer is managed by the VM's garbage collector, so code and data for the module are garbage collected like any other memory.  Type safety is preserved by checking method types at module load time using an MD5 signature of the type.
+.LP
+Memory management is intimately tied to the instruction set of the VM.  Dis uses a hybrid garbage collection scheme: most garbage is collected by simple reference counting, while a real-time coloring collector gathers cyclic data.  Because reference counting is an exact rather than conservative form of garbage collection, the type of all data items must be known to the VM run-time system.  For this reason, the language-to-VM compiler generates a type descriptor for all compound types.  This descriptor reports the location of all pointers within the type, allowing the VM to track references as items are copied.
+.SH
+Garbage collection
+.LP
+Memory dominates the cost of small systems, so the VM should be designed to keep memory usage as small as possible.  Through reference-counted garbage collection, Dis reclaims memory the moment it becomes unused.  Reference counting also eliminates the need for a large arena as required for efficient mark-and-sweep collection.  Both these results reduce the memory requirements of the VM and its applications.
+.LP
+Compare this to the Java VM, whose instruction set makes it difficult to track references as objects are copied.  This biases against reference counting, so JVM implementations choose lazier techniques such as mark-and-sweep, inducing a larger arena and delayed collection, both of which increase the memory use and therefore the cost of the overall system.
+.SH
+Issues in compiling
+.LP
+It is easy to interpret the individual instructions of a stack-based virtual machine (SM) such as the Java virtual machine (JVM), because most operands are implicit.  However, a high-level language implementation of the interpreter generates more memory traffic than the equivalent set of instructions in a memory transfer machine (MM) such as Dis.  Consider the code to execute
+.P1
+c = a + b;
+.P2
+An SM would execute this by a code burst such as this, which we have annotated with its memory traffic using
+.I L
+for load and
+.I S
+for store:
+.P1
+push  a      # \fILS\fP
+push  b      # \fILS\fP
+add          # \fILLS\fP
+store c      # \fILS\fP
+.P2
+The corresponding MM code burst would be the plain three-operand instruction
+.P1
+add   a,b,c  # \fILLS\fP
+.P2
+When interpreting, the extra memory traffic of the SM is masked by the time saved by not decoding any operand fields.   The operand fields are implicit in the SM instructions, while the MM they are explicit: three operand fields must be decoded in every instruction, even those without operands.
+.LP
+When compiling, the tradeoffs are different.  Clearly, either design can produce the same native instructions from its just-in-time compiler (JIT), but in the SM case most of the work must be done in the JIT, whereas in the MM design the front end has done most of the work and the JIT can be substantially simpler and faster.
+.LP
+A JIT for an SM is forced to do most of the work of register allocation in the JIT itself.  Because the types of stack cells change as the program executes, the JIT must track their types as it compiles.  In an MM, however, the architecture maps well to native instructions.  This produces a continuum of register allocation strategies from none, to simple mapping of known cells to registers, to flow-based register allocation.  Most of the work of any of these strategies can be done in the language-to-VM compiler.  It can generate code for an infinite-register machine, and the JIT can then allocate as many as are available in the native architecture.  Again, this distribution of work keeps the JIT simple.
+.SH
+Processors
+.LP
+The same issues that face the JIT writer also face the designer of special-purpose processors to support a VM.  Register allocation in the JIT is analogous to register relabeling in silicon, and an SM design adds unnecessary complexity to an already difficult problem.  One might argue that a stack-based processor design would mitigate the difficulties, but our experience with the implementation of a stack machine in the AT&T Crisp microprocessor [5] leads us to believe that stack architectures are inherently slower than register-based machines.  Their design lengthens the critical path by replacing simple registers with a complex stack cache mechanism.
+.LP
+In other words, it is a better idea to match the design of the VM to the processor than the other way around.
+.LP
+Dis fits this criterion better, but we do not plan to implement Dis in silicon.  The idea of a VM is to be architecture-independent; offering a special processor to run it negates the original goal by favoring one instruction set.  Ignoring that for the moment, though, there could still be two reasons to consider designing silicon for Dis: performance and cost.
+.LP
+On performance, history shows that language-specific CPUs are not competitive.  The investment in the special design takes energy away from the systems issues that ultimately dominate performance.   Performance gains realized through language-specific support tend to be offset by parallel improvements in general-purpose processors during the life cycle of the CPU.
+.LP
+Dis compiles quickly into native code that runs only 30-50% slower than native C.  At the current rate of processor improvement, that is only a few months of processor design time.  It is wiser to focus on improving execution on commodity, general purpose processors than on inventing a new architecture.
+.LP
+The issue of cost is more subtle.  Dis is close enough to familiar architectures that a special chip with high integration of systems facilities could be cost-effective on small platforms.  The real reason for that, though, is that the memory management design of the virtual machine makes it easy to implement Dis in small memory.  By contrast, whatever cost gains an integrated Java processor might realize will likely be lost in the extra memory required by its conservative garbage collection scheme [6].
+.SH
+References
+.nr PS -1
+.nr VS -1
+.IP 1.
+R. Pike, D. Presotto, S. Dorward, B. Flandrena, K. Thompson, H. Trickey, and P. Winterbottom. ``Plan 9 from Bell Labs'',
+.I "J. Computing Systems"
+8:3, Summer 1995, pp. 221-254.
+.IP 2.
+Dorward, S., et al., ``Inferno'',
+.I "IEEE Compcon 97 Proceedings" ,
+1997.
+.IP 3.
+Arnold, K. and Gosling, J.,
+.I "The Java Programming Language" ,
+Addison-Wesley, 1996.
+.IP 4.
+Nori, K. V., Ammann, U., Nabeli, H. H., and Jacobi, Ch.,  ``Pascal P Implementation notes'', in Barron, D. W. (ed.),
+.I "Pascal\-The Language and its Implementation" ,
+Wiley, 1981, pp. 125-170.
+.IP 5.
+Ditzel, D. R. and McLellan, R., ``Register Allocation for Free: The C Machine Stack Cache'',
+.I "Proc. of Symp. on Arch. Supp. for Prog. Lang. and Op. Sys." ,
+March, 1982, pp. 48-56.
+.IP 6.
+Case, B., ``Implementing the Java Virtual Machine'',
+.I "Microprocessor Report" ,
+March 25, 1996, pp. 12-17.
binary files /dev/null b/doc/hotchips.pdf differ
--- /dev/null
+++ b/doc/install.ms
@@ -1,0 +1,1423 @@
+.de EX
+.nr x \\$1v
+\\!h0c n \\nx 0
+..
+.de FG		\" start figure caption: .FG filename.ps verticalsize
+.KF
+.BP \\$1 \\$2
+.sp .5v
+.EX \\$2v
+.ps -1
+.vs -1
+..
+.de fg		\" end figure caption (yes, it is clumsy)
+.ps
+.vs
+.br
+\l'1i'
+.KE
+..
+\" step numbers
+.nr ,s 0 1
+.af ,s a
+.am NH
+.nr ,s 0 1
+..
+.de Sn		\" .Sn "step"
+•\ Step \\n(H1\\n+(,s: \\$1
+..
+.de Ss
+.P1
+.B
+.Sn "\\$1"
+.P2
+..
+.TL
+Installing the Inferno Software
+.AU
+Vita Nuova
+.br
+support@vitanuova.com
+.br
+12 June 2003
+.SP 4
+.LP
+Inferno can run as either a native operating system, in the usual way, or as a
+.I hosted
+virtual operating system,
+running as an application on another operating system.
+This paper explains how to install Inferno from the distribution media
+to a hosted environment and how to configure the system for
+basic networking.
+.LP
+Inferno can run as a hosted virtual operating system on top of
+Plan 9, Unix or Windows.
+In this paper, the term
+.I Unix
+is used to cover all supported variants, currently FreeBSD, Linux, HP/UX, Irix and Solaris,
+and the term
+.I Windows
+covers Microsoft Windows (98, Me, Nt, 2000, and XP).
+(Windows 98 might first require installation of the Unicode layer update from Microsoft.)
+.NH
+Preparation
+.LP
+You should ensure at least 150 Mbytes of free space on the filesystem.
+The installation program will copy files from the distribution CD to a
+directory on the filesystem called the
+.I inferno_root
+directory.
+You can choose the location of this directory.
+If you are installing to a multiuser filesystem outside your control a subdirectory of your home
+directory might be most sensible. If you plan to share the Inferno
+system with other users then common choices for
+.I inferno_root
+are
+.CW /usr/inferno
+on Unix and Plan 9 systems, and
+.CW c:\einferno
+on Windows systems.
+Where these appear in examples in this paper you should substitute
+your own
+.I inferno_root
+directory.
+.Ss "Choose the \fIinferno_root\fP directory."
+Ensure that the user who will run the installation program has
+appropriate filesystem permissions to create the
+.I inferno_root
+directory and
+files and subdirectories beneath it.
+.NH
+Copying Files
+.LP
+On all platforms the files will be owned by the user doing the installation,
+except for installation onto a FAT file system (eg, on Windows), where the files
+appear to be owned by
+.CW Everyone
+because FAT does not record ownership.
+.Ss "Insert the distribution CD into the CD drive."
+On Unix and Plan 9,
+mount the CD to a suitable location on the filesystem, call this location
+.I cd_path .
+On Windows, note the drive letter of the CD, call this drive letter
+.I cd_drive .
+The files will be copied by an Inferno hosted installation program which runs
+directly from the CD.
+The directory
+.CW /install
+on the CD contains an installation program for each supported platform \- a shell
+script for Unix and Plan 9 and an executable for Windows.
+The Plan 9 install script is called
+.CW Plan9.rc
+and determines the CPU type from the environment variable
+.CW cputype .
+The Unix install scripts all have names of the form
+.CW \fIhost_os\fP-\fIhost_arch\fP.sh
+where
+.I host_os
+will be one of:
+.CW FreeBSD ,
+.CW Linux ,
+or
+.CW Solaris
+and
+.I host_arch
+will be one of:
+.CW 386 ,
+.CW mips ,
+.CW power
+or
+.CW sparc .
+Most platforms offer just the one obvious combination.
+The Windows installation program is called
+.CW setup.exe ;
+it is used on all varieties of Windows.
+The next step describes how to begin the installation by running the program
+that corresponds to your host system.
+.Ss "Run the installation script."
+The installation program will copy files from the CD to the filesystem.
+The Windows installation program will also create registry entries and add
+an Inferno item to the Windows
+.I start
+menu.
+On Plan 9, run
+.P1
+rc \fIcd_path\fP/install/Plan9.rc \fIinferno_root\fP
+.P2
+Where
+.I inferno_root
+is the path to the chosen Inferno root directory. The CPU architecture
+will be inferred from the environment variable
+.CW cputype .
+On Unix, run
+.P1
+sh \fIcd_path\fP/install/\fIhost-os\fP-\fIhost_arch\fP.sh  \fIinferno_root\fP
+.P2
+Where
+.I host_os
+is the Unix variant name
+.CW FreeBSD , (
+.CW Irix ,
+.CW Linux
+or
+.CW Solaris ).
+.I host_arch
+is the CPU type (eg,
+.CW 386 ), 
+and
+.I inferno_root
+is the path to the chosen Inferno directory.
+On Windows, run
+.P1
+\fIcd_drive\f(CW:\einstall\esetup.exe
+.P2
+The Windows installation program will ask you to choose the location of the installation
+directory on the hard disk.
+.LP
+On all platforms, a copy of Inferno
+on the CD will install from various installation packages on the CD to the
+.I inferno_root
+subtree on the filesystem.
+On any platform it installs support for all.
+.LP
+Inferno is now installed, but it needs to be configured
+for your site.
+The process acts as a quick tour of parts of the system.
+The main tasks are to add local parameters to the network data base,
+and to set up the authentication system.
+If you are going to run Inferno standalone, for instance to experiment with Limbo
+and the file serving interface,
+most of what follows can be deferred indefinitely.
+It is still worthwhile skimming through it, because the first few sections tell how
+to start up Inferno with correct parameters (eg, root directory and graphics resolution).
+(A configuration program that runs under the window system would be more convenient,
+and fairly easy to do, but that has not yet been done.)
+.NH
+Running Inferno
+.LP
+Inferno host executables are all kept in a single directory corresponding
+to the combination of host operating system and CPU architecture \- the Inferno
+.CW bin
+directory.
+.P1
+\fIinferno_root\fP/\fIhost_os\fP/\fIhost_arch\fP/bin
+.P2
+(On Windows the path might need
+.CW \e
+not
+.CW /
+of course.)
+That directory can be added to the search path of the host system's command interpreter,
+and that process will be described first, although as discussed later one can use a script
+instead and that is sometimes more convenient.
+(Of course, the script will still need to refer to that directory.)
+.LP
+.I "Plan 9:\ \ "
+Plan 9 users should add a line to their
+.CW lib/profile
+file that binds this directory after their
+.CW /bin
+directory.
+.P1
+bind -a /usr/inferno/Plan9/$cputype/bin /bin
+.P2
+The bind is done after the existing
+.I bin
+directory to avoid hiding the existing Plan 9 compilers.
+If, at a later stage, you build either the hosted or native Inferno kernels for ARM or StrongARM
+you should ensure that the Inferno compilers are used rather than
+the Plan 9 compilers, since they differ in the implementation of
+floating-point instructions (the Plan 9 ARM suite uses a byte order that is more plausible
+than the order ARM dictates but therefore wrong).
+That difference is likely to be resolved at some point but it has not yet been done.
+.LP
+.I "Windows:\ \"
+The
+.I host_os
+is always
+.CW Nt
+(even for Windows 98, 2000 or XP)
+and
+.I host_arch
+is always
+.CW 386
+and the installation program will create an entry on the
+.I "start menu"
+to invoke Inferno.
+For Unix systems or Windows systems in which Inferno will be started
+from a command shell, the environment variable
+.CW PATH
+should be set to include the Inferno
+.CW bin
+directory.
+For Windows 95 and Windows 98 this should be done in the
+.CW \eautoexec.bat
+file by adding a line like
+.P1
+PATH=c:\einferno\eNt\e386\ebin;%PATH%
+.P2
+You will need to reboot Windows to have the system reread the
+.CW \eautoexec.bat
+file.
+For Windows NT and Windows 2000 modify the
+.CW Path
+environment variable through
+.I "Control Panel -> System -> Environment" .
+.LP
+If you are using an MKS or Cygwin Unix-like shell environment,
+you might instead set:
+.P1
+PATH="c:/inferno/Nt/386/bin;$PATH"
+.P2
+and export it if necessary.
+.LP
+.I "Unix:\ \"
+For Unix  systems, for
+.CW sh
+derivatives, the environment variable
+.CW PATH
+should be set to include the Inferno
+.CW bin
+directory.
+This might be done in your
+.CW .profile
+file by adding a line like
+.P1
+PATH="/usr/inferno/Linux/386/bin:$PATH"
+.P2
+Don't forget to ensure that
+.CW PATH
+is exported.
+You may need to log out and back in again for the changes to take effect.
+.KS
+.Ss "Start Inferno."
+Hosted inferno is run by invoking an executable called
+.I emu .
+.KE
+On Windows, select the Inferno option from the
+.I "start menu" .
+This will invoke
+.I emu
+with appropriate arguments to find its files in
+.I inferno_root .
+If you need to change any of the options passed to
+.I emu
+when invoked from the
+.I "start menu"
+you need to do this by clicking the right mouse button
+on the Windows task bar and choosing
+.I "Properties -> Start Menu Programs -> Advanced"
+to modify the shortcut used for Inferno.
+For Unix and Plan 9, you will need to tell
+.I emu
+where to find the Inferno file tree by passing it the
+.CW -r\fIrootpath\f(CW
+command line option. For example
+.P1
+emu -r/usr/john/inferno
+.P2
+Without the
+.CW -r
+option it will look for the file tree in
+.CW /usr/inferno
+on Plan 9 and Unix and, when invoked from the command line on WIndows,
+the default is
+.CW \einferno
+on the current drive.
+(The Windows start menu by contrast has already been set to use the right directory by the installation software.)
+.LP
+When using graphics,
+.I emu
+will use a window with a resolution of 640 x 480 pixels by default. To use a larger resolution
+you will need to pass
+.I emu
+an option
+.CW -g\fIXsize\f(CWx\fIYsize\f(CW
+on the command line. So, for example, to invoke
+.I emu
+as above but with a resolution of 1024 x 768 pixels the full command line
+would be
+.P1
+emu -r/usr/john/inferno -g1024x768
+.P2
+When invoked in this way
+.I emu
+displays a command window running the Inferno shell
+.CW /dis/sh.dis .
+To avoid typing the command line options each time you invoke
+.I emu
+you can store them in the environment variable
+.CW EMU
+which is interrogated when
+.I emu
+is started and might as well be set along side the
+.CW PATH
+environment variable if the same configuration options are to be used on
+each invocation.
+.P1
+set EMU="-rd:\eDocuments and Settings\ejohn\einferno -g1024x768"
+.P2
+for Windows.
+.P1
+EMU=(-r/usr/john/inferno -g1024x768)
+.P2
+for Plan 9, and
+.P1
+EMU="-r/usr/john/inferno -g1024x768"
+.P2
+for Unix.
+An alternative to using the
+.CW EMU
+environment variable is to place the correct invocation in a
+script file (or batch file, for Windows) and invoke that instead
+of running
+.I emu
+directly.
+It is important to note that for Windows the
+.CW -r
+option also serves to indicate both the drive and directory on to which the software
+has been installed. Without a drive letter the system will assume the
+current drive and will fail if the user changes to an alternative drive.
+Once the environment variables or scripts are set up, as described above, invoking plain
+.P1
+emu
+.P2
+or the appropriate script file,
+should result in it starting up Inferno's command interpreter
+.I sh (1),
+which prompts with a semicolon:
+.P1
+; 
+.P2
+You can add a further option
+.CW -c1
+to start up
+.I emu
+in a
+mode in which the system compiles a module's
+Dis operations to native machine instructions when a module
+is loaded.
+(See the
+.I emu (1)
+manual page.) 
+In
+.I compile
+mode programs that do significant computation will run much faster.
+Whether in compiled or interpreted mode you should now have a functional
+hosted Inferno system.
+When Inferno starts the initial
+.CW /dis/sh.dis
+it reads commands from the file
+.CW /lib/sh/profile
+before becoming interactive. See the manual pages for the shell
+.I sh (1)
+to learn more about tailoring the initial environment.
+.LP
+The semicolon is the default shell prompt. From this command window
+you should be able to see the installed Inferno files and directories
+.P1
+lc /
+.P2
+The command
+.I lc
+presents the contents of its directory argument in columnar fashion to standard
+output in the command window.
+.P1
+; lc /
+FreeBSD/     Unixware/    icons/       libkern/     man/         prof/
+Hp/          acme/        include/     libkeyring/  mkconfig     prog/
+Inferno/     appl/        keydb/       libmath/     mkfile       services/
+Irix/        asm/         legal/       libmemdraw/  mkfiles/     tmp/
+LICENCE      chan/        lib/         libmemlayer/ mnt/         tools/
+Linux/       dev/         lib9/        libtk/       module/      usr/
+MacOSX/      dis/         libbio/      licencedb/   n/           utils/
+NOTICE       doc/         libcrypt/    limbo/       net/         wrap/
+Nt/          emu/         libdraw/     locale/      nvfs/
+Plan9/       env/         libfreetype/ mail/        o/
+Solaris/     fonts/       libinterp/   makemk.sh    os/
+;
+.P2
+Only the files and directories in and below the
+.I inferno_root
+directory on the host filesystem are immediately visible to an Inferno process;
+these files are made visible in the root of the Inferno file namespace.
+If you wish to import or export files
+from and to the host filesystem you will need to use tools on your
+host to move them in or out of the Inferno visible portion of your host
+filesystem (see the manual pages
+.I os (1)
+and
+.I cmd (3)
+for an interface to host commands).
+(We plan to make such access direct, but the details are still being worked out.)
+From this point onwards in this paper all file paths not qualified with
+.I inferno_root
+are assumed to be in the Inferno namespace.
+Files created in the host filesystem will be created with the user id of
+the user that started
+.I emu
+and on Unix systems with that user's group id.
+.NH
+Setting the site's time zone
+.LP
+Time zone settings are defined by
+files in the directory
+.CW /locale .
+The setting affects only how the time is displayed; the internal representation does not vary.
+For instance, the file
+.CW /locale/GMT
+defines Greenwich Mean Time,
+.CW /locale/GB-Eire
+defines time zones for Great Britain and the Irish Republic
+(GMT and British Summer Time), and
+.CW /locale/US_Eastern
+defines United States
+Eastern Standard Time and Eastern Daylight Time.
+The time zone settings used by applications are read
+(by
+.I daytime (2))
+from the file
+.CW /locale/timezone ,
+which is initially a copy of
+.CW /locale/GB-Eire .
+If displaying time as the time in London is adequate, you need change nothing.
+To set a different time zone for the whole site,
+copy the appropriate time zone file into
+.CW /locale/timezone :
+.P1
+cp /locale/US_Eastern /locale/timezone
+.P2
+To set a different time zone for a user or window,
+.I bind (1)
+the file containing the time zone setting over
+.CW /locale/timezone ,
+either in the user's profile or in a name space description file:
+.P1
+bind /locale/US_Eastern /locale/timezone
+.P2
+.NH
+Running the
+Window Manager
+.I wm
+.LP
+Graphical Inferno programs normally run under the window manager
+.I wm (1).
+Inferno has a simple editor,
+.I wm/edit ,
+that can be used to edit the inferno configuration files.
+The `power environment' for editing and program development is
+.I acme (1),
+but rather that throwing you in at the deep end, we shall stick to
+the simpler one for now.
+If you already know Acme from
+Plan 9, however, or perhaps Wily from Unix, feel free to use Inferno's
+.I acme
+instead of
+.I edit .
+.Ss "Start the window manager."
+Invoke
+.I wm
+by typing
+.P1
+wm/wm
+.P2
+You should see a new window open with a blue-grey background and a small
+.I "Vita Nuova"
+logo in the bottom left hand corner. Click on the logo with mouse button 1
+to reveal a small menu.
+Selecting the 
+.I Edit
+entry will start
+.I wm/edit .
+In common with most
+.I wm
+programs the editor has three small buttons in a line at its top right hand corner.
+Clicking on the X button, the rightmost button,
+will close the program down. The leftmost of the three buttons will allow the window
+to be resized \- after clicking it drag the window from a point near to either one of its
+edges or one of its corners. The middle button will minimise the window, creating
+an entry for it in the application bar along the bottom of the main
+.I wm
+window. You can restore a minimised window by clicking on its entry in the application bar.
+The initial
+.I wm
+configuration is determined by the contents of the shell
+script
+.CW /lib/wmsetup
+(see
+.I toolbar (1)
+and
+.I sh (1)).
+.Ss "Open a shell window."
+Choose the
+.I shell
+option from the menu to open up a shell window. The configuration of Inferno
+will be done from this shell window.
+.NH
+Manual Pages
+.LP
+Manual pages for all of the system commands are available from a shell
+window. Use the
+.I man
+or
+.I wm/man
+commands. For example,
+.P1
+man wm
+.P2
+will give information about
+.I wm .
+And
+.P1
+man man
+.P2
+will give information about using
+.I man .
+.I Wm/man
+makes use of the Tk text widget to produce slightly more
+attractive output than the plain command
+.I man .
+Here, and in other Inferno documentation you will see references to manual page
+entries of the form \fIcommand\f(CW(\fIsection\f(CW)\fR.
+You can display the manual page for the command by running
+.P1
+man \fIcommand\fP
+.P2
+or
+.P1
+man \fIsection\fP \fIcommand\fP
+.P2
+if the manual page appears in more than one section.
+.NH
+Initial Namespace
+.LP
+The initial Inferno namespace is built
+by placing the root device '#/' (see
+.I root (3))
+at the root of the namespace and binding
+.nr ,i 0 1
+.af ,i i
+.IP  \n+(,i)
+the host filesystem device '#U' (see
+.I fs (3))
+containing the
+.I inferno_root
+subtree of the host filesystem at the root of the Inferno filesystem,
+.IP  \n+(,i)
+the console device '#c' (see
+.I cons (3))
+in
+.CW /dev ,
+.IP  \n+(,i)
+the prog device '#p' (see
+.I prog (3))
+onto
+.CW /prog ,
+.IP  \n+(,i)
+the IP device '#I' (see
+.I ip (3))
+in
+.CW /net ,
+and
+.IP  \n+(,i)
+the environment device '#e' (see
+.I env (3))
+at
+.CW /dev/env .
+.rr ,i
+.LP
+You can see the sequence of commands required to construct the current namespace
+by running
+.P1
+ns
+.P2
+.NH
+Inferno's network
+.LP
+If you are just going to use Inferno for local Limbo programming, and not use its
+networking interface, you can skip to the section ``Adding new users'' at the end of this document.
+You can always come back to this step later.
+.LP
+To use IP networking, the IP device
+.I ip (3)) (
+must have been bound into
+.CW /net .
+Typing
+.P1
+ls -l /net
+.P2
+(see
+.I ls (1))
+should result in something like
+.P1
+--rw-rw-r-- I 0 network john 0 May 31 07:11 /net/arp
+--rw-rw-r-- I 0 network john 0 May 31 07:11 /net/ndb
+d-r-xr-xr-x I 0 network john 0 May 31 07:11 /net/tcp
+d-r-xr-xr-x I 0 network john 0 May 31 07:11 /net/udp
+.P2
+There might be many more names on some systems.
+.LP
+A system running Inferno, whether native or hosted, can by agreement attach to any or all resources that
+are in the name space of another Inferno system (or even its own).
+That requires:
+.IP •
+the importing system must know where to find them
+.IP •
+the exporting system must agree to export them
+.IP •
+the two systems must authenticate the access (not all resources will be permitted to all systems or users)
+.IP •
+the conversation can be encrypted to keep it safe from prying eyes and interference
+.LP
+On an Inferno network, there is usually one secure machine that acts as authentication server.
+All other systems variously play the rôles of server and client as required: any system can import some resources (or none)
+and export others (or none), simultaneously, and differently in different name spaces.
+In following sections, we shall write as though there were three distinct machines:
+authentication server (signer); server (exporting resources); and client (importing resources).
+With Inferno, you can achieve a similar effect on a single machine by starting up distinct
+instances of
+.I emu
+instead.
+That is the easiest way to become familiar with the process (and also avoids having to install
+the system on several machines to start).
+It is still worthwhile setting up a secured
+authentication server later, especially if you are using Windows on a FAT file system
+where the host system's file protections are limited.
+.LP
+We shall now configure Inferno to allow each of the functions listed above:
+.IP •
+change the network database to tell where to find local network resources
+.IP •
+set up the authentication system, specifically the authentication server or `signer'
+.IP •
+start network services (two distinct sets: one for the authentication services and the other for
+all other network services)
+.NH
+Network database files
+.LP
+In both hosted and native modes, Inferno uses a collection of text files
+of a particular form to store all details of network and service configuration.
+When running hosted, Inferno typically gets most of its data from the host operating system,
+and the database contains mainly Inferno-specific data.
+.LP
+The file
+.CW /lib/ndb/local
+is the root of the collection of network database files.
+The format is defined by
+.I ndb (6),
+but essentially it is a collection of groups of attribute/value pairs of the form
+\fIattribute\fP\f(CW=\fP\fIvalue\fP.
+Attribute names and most values are case-sensitive.
+.LP
+Related attribute/value pairs are grouped into database `entries'.
+An entry can span one or more
+lines: the first line starts with a non-blank character,
+and any subsequent lines in that entry start
+with white space (blank or tab).
+.NH 2
+Site parameters
+.LP
+The version of
+.CW /lib/ndb/local
+at time of writing looks like this:
+.P1
+database=
+	file=/lib/ndb/local
+	file=/lib/ndb/dns
+	file=/lib/ndb/inferno
+	file=/lib/ndb/common
+
+infernosite=
+	#dnsdomain=your.domain.com
+	#dns=1.2.3.4	# resolver
+	SIGNER=your_Inferno_signer_here
+	FILESERVER=your_Inferno_fileserver_here
+	smtp=your_smtpserver_here
+	pop3=your_pop3server_here
+	registry=your_registry_server
+.P2
+The individual files forming the data base are listed in order in the
+.CW database
+entry.
+They can be ignored for the moment.
+The entry labelled
+.CW infernosite=
+defines a mapping from symbolic host names of the form
+.CW $\fIservice\f(CW
+to a host name, domain name, or a numeric Internet address.
+For instance, an application that needs an authentication service
+will refer to
+.CW $SIGNER
+and an Inferno naming service will translate that at run-time to the appropriate network name for
+that environment.
+Consequently,
+the entries above need to be customised for a given site.
+(The items that are commented out are not needed when the host's own DNS resolver is used instead
+of Inferno's own
+.I dns (8).)
+For example, our
+.CW infernosite
+entry in the
+.CW local
+file might look something like this
+.P1
+infernosite=
+	dnsdomain=vitanuova.com
+	dns=200.1.1.11	# resolver
+	SIGNER=doppio
+	FILESERVER=doppio
+	smtp=doppio
+	pop3=doppio
+	registry=doppio
+.P2
+where
+.CW doppio
+is the host name of a machine that is offering the given services to Inferno,
+and
+.CW 200.1.1.11
+is the Internet address of a local DNS resolver.
+.Ss "Enter defaults for your site"
+.LP
+The only important names initially are:
+.IP \f(CWSIGNER\fP 20
+the host or domain name, or address of the machine that will act as signer
+.IP \f(CWregistry\fP
+the name or address of a machine that provides the local dynamic service
+.I registry (4)
+.IP \f(CWFILESERVER\fP
+the primary file server (actually needed only by clients with no storage of their own)
+.LP
+All others are used by specific applications such as
+.I acme (1)
+mail or
+.I ftpfs (4).
+.LP
+If you are using a single machine for signer and server/client, put its name in those three entries.
+.NH 2
+Connection server
+.I cs (8)
+and name translation
+.LP
+The connection server
+.I cs (8)
+uses the network database
+and other
+data (such as that provided by the host system and
+the Internet DNS servers) to translate symbolic network names and services into instructions
+for connecting to a given service.
+In hosted mode,
+network and service names are passed through to the host for conversion to numeric IP
+addresses and port numbers. If the host is unable to convert a service name
+the connection server will attempt to convert the name using mappings
+of service and protocol names to Internet port numbers
+in the file
+.CW /lib/ndb/inferno :
+.P1
+tcp=infgamelogin port=6660	# inferno games login service
+tcp=styx port=6666	# main file service
+tcp=mpeg port=6667	# mpeg stream
+tcp=rstyx port=6668	# remote invocation
+tcp=infdb port=6669	# database server
+tcp=infweb port=6670	# inferno web server
+tcp=infsigner port=6671	# inferno signing services
+tcp=infcsigner port=6672	# inferno countersigner
+tcp=inflogin port=6673	# inferno credential service
+tcp=infsds port=6674	# software download
+tcp=registry port=6675	# registry(4)
+udp=virgil port=2202	# naming service
+.P2
+For the moment, leave that file as it is.
+You will only need to modify this file if in future
+you add new statically-configured services to Inferno.
+(Services that come and go dynamically might use
+.I registry (4)
+instead, a registry manager that allows a service to be found
+using a description of it.)
+.NH
+Configuring a Signer
+.LP
+Before an Inferno machine can authenticate establish a secure connection to an Inferno
+service on another machine, each system needs to obtain a certificate from a common signer.†
+We talk here as though there is only one `signer' per site but in fact there can be application- or
+group-specific ones.
+For instance, a version of the Inferno games server automatically starts its own signing service to
+keep the identities and keys used for game service separate from those of the primary
+system, allowing users to set up their own gaming groups without fuss.
+.FS
+.FA
+†The authentication system will shortly expand to a rôle-based one allowing a chain of certificates to be used,
+from several signers, with delegation etc.
+.FE
+To use authenticated connections for the primary
+file services we need to set up a signer to generate
+certificates for users (see
+.I createsignerkey (8)
+and
+.I logind (8)).
+.LP
+Choose an Inferno machine to become the signer.
+If this is the first or only
+Inferno machine on your network then make this machine the signer.
+(It is more realistic if you start up a separate copy of
+.I emu
+and leave it in `console' mode without starting the window system.)
+You can always move the function elsewhere later.
+.Ss "Empty the secret file of secrets."
+The authentication server verifies a user's identity by checking that the user knows a shared secret.
+(In fact the secret is not used directly, but instead a scrambled value that was derived from it.)
+The file
+.CW /keydb/keys
+holds those secrets; it is encrypted using a secret password or phrase known only to the
+manager of the authentication server.
+Having just installed Inferno, the file
+should exist and be readable only by you (or the user as which the authentication service will run).
+On the signer machine, type
+.P1
+ls -l /keydb/keys
+.P2
+You should see something like:
+.P1
+--rw------- M 7772 yourname inf 0 Jun 12 03:08 /keydb/keys
+.P2
+You should see something like the above.
+If the file does not exist or is not empty or has the wrong mode, use:
+.P1
+cp /dev/null /keydb/keys; chmod 600 /keydb/keys
+.P2
+to set it right.
+.Ss "Generate a signer key."
+Next on the signer machine, run
+.P1
+auth/createsignerkey \fIname\fP
+.P2
+In place of
+.I name
+enter the network name of the signer. A fully-qualified domain name of a
+host or individual is fine.
+This value will appear as the signer name in each
+certificate generated by the signer.
+.I Createsignerkey
+creates public and private keys that are used by the signer when generating
+certificates.
+They are stored in
+.CW /keydb/signerkey ;
+check that it has permissions that limit access to the user that will run the
+authentication services:
+.P1
+; ls -l /keydb/signerkey
+--rw------- M 32685 secrets inf 1010 Jul 07  2000 /keydb/signerkey
+.P2
+Use
+.I chmod (1)
+to set the mode to read/write only for the owner if necessary:
+.P1
+chmod 600 /keydb/signerkey
+.P2
+.Ss "Start the authentication network services"
+Still at the signer console, type
+.P1
+svc/auth
+.P2
+That script (see
+.I svc (8))
+will check that the
+.CW /keydb/keys
+and
+.CW /keydb/signerkey
+files exist, and then
+start the program
+.I keyfs (4),
+which manages the
+.CW keys
+file.
+It will prompt for the password (pass phrase) you wish to use to protect the
+.CW keys
+file, now and on subsequent runs:
+.P1
+; svc/auth
+Key: 
+Confirm key:
+.P2
+It prompts twice to confirm it.
+If successfully confirmed, it will then
+start the
+network services used by Inferno to authenticate local and remote users and hosts.
+(If confirmation fails, retry by running
+.CW svc/auth
+again.)
+.LP
+You can check that they are running by typing:
+.P1
+ps
+.P2
+which should show something like the following:
+.P1
+       1        1    john    release    74K Sh[$Sys]
+       3        2    john        alt    15K Cs
+      10        9    john       recv    25K Keyfs
+      11        9    john    release    44K Styx[$Sys]
+      12        9    john       recv    25K Keyfs
+      14        1    john        alt     8K Listen
+      16        1    john    release     8K Listen[$Sys]
+      18        1    john        alt     9K Listen
+      20        1    john    release     9K Listen[$Sys]
+      22        1    john        alt     9K Listen
+      24        1    john    release     9K Listen[$Sys]
+      26        1    john        alt     8K Listen
+      28        1    john    release     8K Listen[$Sys]
+      29        1    john      ready    73K Ps[$Sys]
+.P2
+There should be
+.CW Keyfs
+and
+.CW Listen
+processes.
+.Ss "Enter user names and secrets."
+For each user to be authenticated by the signer run
+.P1
+auth/changelogin \fIusername\fP
+.P2
+You will be prompted to supply a secret (ie, password or pass phrase) and expiration date.
+The expiration date will be used
+as the maximum expiration date of authentication certificates granted to that user.
+.I Changelogin
+(see
+.I changelogin (8))
+accesses the name space generated by
+.I keyfs (4),
+which has just been started above by
+.CW svc/auth .
+A user can later change the stored secret using the
+.I passwd (1)
+command.
+For the signer to generate a certificate there must be at least one entry in the
+password file.
+If you are not sure at this stage of the names of the users that you want to
+authenticate then create an entry for the user
+.CW inferno
+and yourself.
+.NH
+Establishing a Secure Connection
+.LP
+To establish a secure connection between two Inferno machines, each needs to present a public key with
+a certificate signed by a common signer.
+We shall make two public/private key sets, one for the server and one for a client
+(they differ only in where they are stored).
+We shall do the server first, because the usual network services require
+the server possess some keys before they can start.
+We shall then start those services, and finally sort out the client.
+.Ss "Start the connection service."
+The server still needs to make contact with the signer, so we need to start the basic connection service
+.I cs (8).
+If you are using the same instance of
+.I emu
+in which you invoked
+.CW svc/auth
+above, you should skip this step.
+To check, you should see a new file in the
+.CW /net
+directory called
+.CW cs .
+Run the command
+.P1
+ls /net
+.P2
+You should see at least the following names in the output:
+.P1
+/net/cs
+/net/ndb
+/net/tcp
+/net/udp
+.P2
+Otherwise, type
+.P1
+ndb/cs
+.P2
+That starts
+.I cs (8).
+Try the
+.CW "ls /net"
+again to check that the
+.CW cs
+file has appeared.
+.LP
+.Ss "Generate a server key set."
+On the server machine (or in the `server' window),
+use
+.I getauthinfo (8)
+to obtain a certificate and save it in a file named
+.CW default
+by running
+.P1
+getauthinfo default
+.P2
+.I Getauthinfo
+will prompt for the address of your signer (you can often
+just use its host name or even
+.CW localhost )
+and for a remote username and password
+combination.
+.I Getauthinfo
+will connect to the
+.I inflogin
+service on the signer and authenticate you against its user and password database,
+.CW /keydb/keys ,
+using the username and password that you entered above.
+Answer
+.CW yes
+to the question that asks if you want to save the certificate in a file.
+.I Getauthinfo
+will save a certificate in the file
+.CW /usr/\fIuser\f(CW/keyring/default
+where
+.I user
+is the name in
+.CW /dev/user .
+.NH
+Network Services
+.LP
+As mentioned above, in a full Inferno network
+the authentication services will usually be run on a secured machine of their own (the signer),
+and the ordinary network services such as file service are not run on a signer.
+If you are, however, using one machine for all functions, you can get the right
+effect by starting another instance of
+.I emu ,
+to act as an Inferno host that is not a signer.
+This one will run the services of a primary file server
+and the site
+.I registry (4).
+.LP
+Commands described in
+.I svc (8)
+start listeners for various local network services.
+(The commands are actually shell scripts.)
+As we saw above,
+.CW svc/auth
+starts the services on a signer.
+.LP
+Here we shall start the usual set of services.
+.KS
+.Ss "Start the network listener services."
+Type
+.P1
+svc/net
+.P2
+.KE
+Various network services will (should!) now be running. To confirm this type
+.P1
+ps
+.P2
+which should show something like the following:
+.P1
+; ps
+       1        1    inferno    release    74K Sh[$Sys]
+       7        6    inferno        alt    15K Cs
+      13        1    inferno       recv    15K Registry
+      14        1    inferno    release    44K Styx[$Sys]
+      15        1    inferno       recv    15K Registry
+      17        1    inferno        alt     8K Listen
+      19        1    inferno    release     8K Listen[$Sys]
+      22        1    inferno        alt     8K Listen
+      24        1    inferno    release     8K Listen[$Sys]
+      25        1    inferno      ready    74K Ps[$Sys]
+.P2
+There should be a few
+.CW Listen
+processes and perhaps a
+.CW Registry .
+.LP
+You can also try
+.P1
+netstat
+.P2
+.I Netstat
+prints information about network connections. You should see
+several lines of output, each one describing an announced TCP or UDP service.
+Depending upon the contents of the network configuration files we included on the CD,
+you might see output something like this:
+.P1
+tcp/1      Announced    inferno    200.1.1.89!6668      ::!0
+tcp/2      Announced    inferno    200.1.1.89!6666      ::!0
+tcp/3      Announced    inferno    200.1.1.89!6675      ::!0
+.P2
+Each line corresponds to a network connection:
+the connection name, the name of the user running the server,
+the address of the local end of the connection,
+the address of the remote end of the connection,
+and the connection status.
+The connection name is actually the protocol and conversation directory
+in
+.CW /net .
+The connection addresses are all of the form \fIhost\f(CW!\fIport\fR
+for these IP based services, and the remote addresses are not filled in
+because they all represent listening services that are in the
+.CW Announced
+state.
+In this example the third line shows a TCP service listening on port 6675.
+Examining
+.CW /lib/ndb/inferno
+with
+.CW grep
+(see
+.I grep (1))
+shows that the listener on port 6675 is the Inferno registry service
+.P1
+grep 6675 /lib/ndb/inferno
+.P2
+gives
+.P1
+tcp=registry port=6675	# default registry
+.P2
+.LP
+Now the server is ready but we need a client.
+.LP
+Either use a third machine or (more likely at first) simply start another
+.I emu
+instance in a new window.
+Start its connection server, again by typing
+.P1
+ndb/cs
+.P2
+The connection server is fundamental to the Inferno network.
+Once networking is set up, when subsequently starting up
+a client you should start
+.I cs
+before starting the window system.
+Note that if you are running the Inferno instance as a server, or combined
+server and client,
+the
+.CW svc/net
+that starts the network services
+automatically starts
+.I cs ,
+and you need not do so explicitly.
+.LP
+.Ss "Generate a client certificate."
+Obtain a certificate for the client in the same way as on the server.
+We shall obtain a certificate for use with a specific server
+by storing
+it in a file whose name exactly matches the network address of the server
+.P1
+getauthinfo tcp!\fIhostname\fP
+.P2
+Use the current machine's
+.I hostname .
+.I Getauthinfo
+stores the certificate in the file
+.CW /usr/\fIuser\fP/keyring/\fIkeyname\fP
+where
+.I user
+is the name in
+.CW /dev/user
+and
+.I keyname
+is the argument given to
+.I getauthinfo .
+Again, 
+answer
+.CW yes
+to the question that asks if you want to save the certificate in a file.
+.LP
+Now that both client and server have a certificate obtained from the same signer
+it is possible to establish a secure connection between them.
+Note that getting keys and certificates with
+.I getauthinfo
+is normally done just once (or at most once per server when the
+.CW default
+key is not used).
+In short, all the work done up to now need not be repeated.
+After this, provided the keys were saved to a keyring file,
+as many authenticated connections can be made as desired
+until the certificate expires (which by default is whenever the password entry
+was set to expire).
+Also note that the certificates for different machines can have
+different signers, and one can even use different certificates for the same machine
+when the remote user name is to differ
+(the
+.CW -f
+option of
+.I getauthinfo
+can then be useful to force an appropriate keyring name).
+.Ss "Make an authenticated connection."
+The script
+.CW svc/net
+on the server started fundamental name services and also a Styx file service.
+That can also be started separately using
+.CW svc/styx .
+In either case the namespace that is served
+is the one in which the command was invoked.
+Now you can test the service.
+.LP
+Confirm that
+.CW /n/remote
+is an empty directory by typing
+.P1
+lc /n/remote
+.P2
+You can now mount the server's name space
+onto the client's directory
+.CW /n/remote
+by typing
+.P1
+mount  \fIserveraddr\fP /n/remote
+.P2
+Where
+.I serveraddr
+is the IP address of the server or a name that the host can resolve to the
+IP address of the server.
+Now
+.P1
+lc /n/remote
+.P2
+should reveal the files and directories in the namespace being served by the server.
+Those files are now also visible in the namespace of your shell.
+You will notice that these changes only affect the shell in which you ran the
+.I mount
+command \- other windows are unaffected.
+You can create, remove or modify files and directories in and under
+.CW /n/remote
+much as you can any other file or directory in your namespace.
+In fact, in general, a process does not need to know whether a file
+actually resides locally or remotely.
+You can unmount the mounted directory with
+.I unmount .
+Type
+.P1
+unmount /n/remote
+.P2
+You can confirm that it has gone by running
+.P1
+ls /n/remote
+.P2
+All connections made by Inferno are authenticated. The default connection
+made by
+.I mount
+is authenticated but uses neither encryption nor secure digests.
+You can pass an argument to
+.I mount
+to specify
+a more secure connection:
+its
+.CW -C
+option gives it a hashing and an encryption algorithm to be applied to
+the connection.
+.KS
+.Ss "Make a secure authenticated connection."
+For example,
+.P1
+mount  -C sha1/rc4_256 \fIserveraddr\fP /n/remote
+.P2
+makes an authenticated connection to the machine given by
+.I serveraddr ,
+then engages SHA1 hashing for message digesting and 256-bit RC4 for encryption.
+.KE
+It mounts the namespace served by
+.I serveraddr 's
+Styx service on the local Inferno directory
+.CW /n/remote .
+.NH
+Adding new users
+.LP
+Every inferno process has an associated
+.I "user name" .
+At boot time the user name is set equal to your login name on the host
+operating system.
+The user name is used by
+.I wm/logon
+to select the home directory, and
+by other programs like
+.I mount
+when it searches for certificates.
+(It can also control permission for file access on the local system in native Inferno
+and some hosted Inferno configurations.)
+When you attach to a server on another
+system the user name in the authenticating certificate can be used by
+the remote file service to set the user name appropriately there.†
+.FS
+.FA
+†The details are system-dependent and currently subject to change.
+.FE
+.LP
+To create a new user, copy the directory
+.CW /usr/inferno
+into
+\f(CW/usr/\fP\fIusername\fP.
+If the user is to have access to services on the network,
+make an authentication server entry using
+.I changelogin (8).
+The user can change the stored secret using
+.I passwd (1),
+if desired.
+Having logged in for the first time, the user should generate
+a default public/private key set using
+.I getauthinfo (8).
+(The authentication services must be running somewhere.)
+.LP
+The
+.I wm
+window manager program
+.I wm/logon
+allows a user to login to the local Inferno system as an Inferno
+user (different from the host user name).
+Its use is shown next.
+.Ss "Re-start Inferno."
+You should now close down any instances of
+.I emu
+that you are currently running.
+The quickest way to do this is to
+type
+.I control-c
+in the emu window in which you ran
+.I wm/wm .
+Start a new
+.I emu ,
+as before, by either running
+.P1
+emu
+.P2
+or by choosing the appropriate entry from your start menu on
+Windows machines. This time, start network services
+.P1
+svc/net
+.P2
+and then run
+.P1
+wm/wm wm/logon
+.P2
+and log in as user
+.I inferno .
+When you log in,
+.I wm/logon
+will change directory to
+.CW /usr/inferno
+and then write the name
+.CW inferno
+to
+.CW /dev/user .
+If the file
+.CW /usr/inferno/namespace
+exists it will be used to construct a new namespace for the user
+based on the commands that it contains (see
+.I newns (2)).
+.NH
+What next
+.LP
+You should now have a fully functional Inferno system.
+You will need to have a three button mouse to use
+.I acme ,
+.I wm ,
+or
+.I plumbing .
+.LP
+To learn more you could start with the manual pages for:
+.I intro (1),
+.I emu (1),
+.I wm (1),
+.I wm-misc (1),
+.I sh (1),
+.I acme (1),
+and
+.I limbo (1)
+and also the papers in sections 1, 2 and 3
+of Volume 2 of
+.I "The Inferno Programmer's Manual" .
binary files /dev/null b/doc/install.pdf differ
--- /dev/null
+++ b/doc/lego.ms
@@ -1,0 +1,642 @@
+.TL
+Styx-on-a-Brick
+.AU
+Chris Locke
+.br
+chris@vitanuova.com
+.AI
+Vita Nuova
+.br
+June 2000
+.SH
+Background
+.LP
+The aim of the Vita-Nuova ``styx-on-a-brick'' project was
+to demonstrate the simplicity of the Styx protocol and the ease
+with which a Styx `stub' can be implemented on tiny devices.
+We also aimed to demonstrate the effectiveness of a protocol based approach
+to resource management and sharing, whether the resource be a physical device
+or a software service.
+.LP
+Adopting a protocol-centric view of resource and service management, as opposed to
+a language-centric approach (as emphasised for instance by Jini™ with Java)
+greatly eased the software burden on our tiny target device \-
+implementing a simple protocol in firmware required much less work than trying to
+implement a virtual machine.  We are confident that if we had adopted a language-centric
+approach, we would not have completed the project within our aggressive space and implementation time constraints.†
+.FS
+.FA
+†Indeed, we later discovered that in the application of Jini to load code into an RCX robot no part
+of Jini was actually on the brick.
+.FE
+.LP
+The project took 2 weeks from start to finish.
+In this time the firmware was developed and all client software
+was written: firmware download, IR-link protocol support,
+clockface application and worldclock application.
+Two people worked on the project, one full-time, the other (Nigel Roles) part-time.
+.LP
+The demo was then taken on a Press Conference tour of the US
+and later appeared at the Usenix2000 Plan 9/Inferno BOF at the request
+of Dennis Ritchie.
+.LP
+I should stress that the project was a demonstration of the ease of
+supporting Styx on small devices \- it was not a demo of robotics!
+(Indeed, the design of the IR-link protocol, Styx name space and the
+services provided by the firmware would be considerably different for
+serious robotics.)
+.LP
+The project used a standard Lego™ Mindstorms™ robotics kit \-
+the ``Robotics Invention System''.  This consists of the RCX brick,
+2 motors, 2 button sensors, a light sensor and a whole load of
+lego pieces \- including wheels, gears and axles; which all adds up
+to a whole load of fun!
+.LP
+The RCX brick is an Hitachi H8 microcontroller with 32K of RAM and
+a 16K ROM BIOS.  The RCX provides 3 motor outputs and 3 sensor inputs.
+Communication with the RCX is via IR.  An IR tower is supplied with the
+``Robotics Invention System'' that connects to a PC via a serial port.
+.SH
+Acknowledgements
+.LP
+Before going any further I must acknowledge the work of Kekoa Proudfoot at
+Stanford and Russ Nelson at Crynwr Software.
+Without their valiant efforts we would not have been able to pursue this project.
+Our work relied on the documents and librcx suite provided by Kekoa:
+.P1
+http://graphics.stanford.edu/~kekoa/rcx/
+.P2
+and on information from Russ Nelson's web site
+.P1
+http://www.crynwr.com/lego-robotics/
+.P2
+.SH
+Files
+.LP
+The files in the
+.CW legostyx.tar
+file are shown in Table 1.
+.KF
+.TS
+center;
+lf(CW) lfR .
+llp.h	Link level protocol constants
+styx.c	The firmware implementation
+styx.srec	The firmware image (S-record format)
+styx_abp.srec	The firmware with the alternating bit part of the link protocol enabled
+send.b	Test app \- sends RCX op codes to the brick
+firmdl.b	Firmware download app
+rcxsend.m	Util module header
+rcxsend.b	Util module \- supports RCX ROM message format on serial link
+timers.m	Timer module header
+timers.b	Util module \- general purpose timers
+legolink.b	Implements the link protocol via a limbo file2chan()
+clockface.b	The controller app for our Clockface robot
+.TE
+.fi
+.ce 10
+.I "Table 1.\ "\c
+Files in the Styx-on-a-Brick package
+.ce 0
+.KE
+.SH
+Project details
+.NH 1
+Firmware Download
+.LP
+The RCX brick comes supplied with Lego firmware to be downloaded into the RAM via
+the IR link.  The ROM implements a monitor which provides for the firmware download,
+as well as other 'op-codes'.
+.LP
+We wrote our own firmware in C using the GNU H8 compiler suite on a FreeBSD machine.
+The code used Kekoa's
+.CW librcx
+library for interfacing to the RCX ROM routines.
+(We should have liked to have done an H8 code generator for our own compiler suite,
+but time did not permit this!)
+The
+.CW gnuh8
+list is accessible via:
+.P1
+http://www.pcserv.demon.co.uk/
+.P2
+First up we had to write a Limbo application to communicate with the ROM, via
+the IR tower in order that we could get our firmware downloaded onto the RCX.
+This is the firmdl application.  Source files: 
+.CW firmdl.b , 
+.CW rcxsend.b
+and 
+.CW timers.b
+.NH 1
+Styx Comms Link
+.LP
+Having got a means of installing our firmware we needed a means of delivering
+Styx messages to and from the Brick.
+.LP
+Styx makes certain demands of its transport media:
+.TS
+l l .
+Reliable	messages must not get 'lost'
+Ordered	messages must not get transposed
+.TE
+The RCX ROM provides a couple of functions for IR comms \- a routine to check
+for message reception and a routine for message delivery.
+The message reception routine receives the data of a RCX "Transfer Data"
+message (RCX op-code 0x45)
+.LP
+We chose to use this facility as a means of delivering Styx messages to our Firmware
+on the Brick.  But it did not provide the Transport properties that Styx requires.
+To meet the Styx requirements we implemented a simple 'alternating bit' protocol whose
+payload was the Styx messages themselves.  These Link protocol messages become the
+payload of the RCX "Transfer Data" messages.
+.LP
+The IR link is very slow, the baud rate of the IR tower serial link is 2400
+and the ROM message format requires that every byte of a message be doubled up with
+its complement. (e.g. the byte 0x7e is transmitted as 0x7e, 0x81)
+This is because of the simple way that the RCX ROM and hardware handle elimination
+of the ambient IR signal level \- all message have the same number of 1s and 0s so
+the ambient IR level can be negated by subtracting the average level.
+All RCX messages are also prefixed by a header and suffixed with a checksum:
+.P1
+0x55 0xff 0x00 \fID1 ~D1 D2 ~D2 ... Dn ~Dn C ~C\fP
+.P2
+where 
+.I D1
+\&...
+.I Dn
+are the bytes in the message body and \fIC = D1+D2+ ... Dn\fP.
+.LP
+Therefore, the effective data rate is considerably less than 1200 baud.
+.LP
+We noted that many Styx messages, especially 
+.CW Twstat
+and 
+.CW Rstat ,
+contained a high
+proportion of 0 byte values.†
+.FS
+.FA
+The protocol has since been revised to reduce that.
+.FE
+Consequently, we decided to incorporate a 0-run-length
+compression scheme in our simple link protocol.
+.LP
+Within the payload of the link messages:
+.TS
+l l .
+0x88 0x00	represents 0x88
+0x88 n	represents n + 2 0's
+others	represent themselves
+.TE
+.LP
+An additional burden is that communication with the Brick via the IR tower has to be strictly
+synchronous.  The IR tower echoes back all data transmitted to it on the serial link
+as well as any data received on the IR link.  Therefore the brick must not send IR data
+while the PC is sending serial data to the tower.  In order to achieve this a 'ping-pong'
+communication scheme must be employed.  The PC is the master, the brick is the slave.
+The master sends a request and waits for the reply from the slave.
+Only the master is allowed to start an exchange.
+.LP
+The problem with the master/slave style of communication is that a Styx Server
+implements blocking requests, e.g. reads and writes, by simply not responding to the
+request until the operation is completed.  This does not fit with the link protocol
+requirement that the server (slave) always respond and the requirement that the brick
+cannot instigate a data exchange.
+The firmware could simply reply with an empty Link protocol message but it then has no
+way of giving timely notification of the completion of a pending Styx request as it is not
+allowed to start a link-protocol message exchange.
+.LP
+To get around the pending Styx reply problem, the link protocol header incorporates a flag
+that the slave (brick) can set to indicate that it is holding outstanding requests and that the
+master (PC) should continue to poll the slave in order to receive their replies in a timely
+fashion.
+.LP
+The link protocol message format is as follows.
+Request from Master (PC) to Slave (RCX):
+.LP
+.TS
+l l .
+0x45/4d	RCX Transfer Data op-code  (including RCX alternating bit)
+0	LSB of "Data" block number
+0	MSB of "Data" block number
+*	LSB of "Data" payload length (lost to ROM firmware)
+*	MSB of "Data" payload length (lost to ROM firmware) (n+2)
+*	LSB of Link protocol payload length
+*	MSB of Link protocol payload length (n+1)
+*	Link protocol header
+*[n-1]	Link protocol payload (0 or 1 Styx messages)
+*	"Transfer Data" cksum (Last byte of Link protocol payload)
+.TE
+.LP
+Note that the 0x45 ROM op-code ("Transfer Data") message incorporates a checksum byte at the
+end, but the ROM doesn't bother to check it so we moved the last byte of the Link protocol
+payload (or the link header if the payload is empty) into the checksum position of
+the ROM message.
+.LP
+Reply from Slave to Master:
+.LP
+.TS
+l l .
+?	Junk from ROM
+*	LSB of Link protocol payload length
+*	MSB of Link protocol payload length (n+1)
+*	Link protocol header
+*[n]	Link protocol payload
+.TE
+.LP
+The Link protocol header has the following flags:
+.LP
+.TS
+l l .
+bit 0	Alternating bit
+bit 1	Poll immediate (requested by slave)
+bit 2	Poll periodic (requested by slave)
+bit 3	compressed (payload is 0-run-length compressed)
+bits 4-7	reserved (should be 0)
+.TE
+.LP
+The master flips the 
+.I Alternating
+.I bit
+for every message that it successfully delivers.
+If a slave reply is lost or corrupted the master will re-send the message using the same
+alternating bit value.  The slave should not act on a repeated message but should
+re-send it's last response.  The value of the alternating bit in the slave response
+is the same as in the request from the master.
+.LP
+The 
+.I Poll
+.I immediate
+bit indicates that the slave has more data to send to the master.
+The master should immediately send another Link-protocol message, even if it has no
+data to send, so as the slave can reply with its pending data.
+.LP
+The 
+.I Poll
+.I periodic
+bit indicates that the slave has pending (blocked) requests that
+it will reply to sometime in the future.  The master should periodically poll the
+slave, even if the master has no data to send.  The polling period should be small
+enough that reply latencies are acceptable.
+.NH 1
+The name space
+.LP
+We now have a means of getting Styx messages to and from the brick.
+But what does the name space provided by the firmware on the brick look like?
+.LP
+We wanted a generic name space; one that reflected the functions of the brick, not
+the model attached to it, so that the same firmware could be used with many
+different robots.
+.LP
+The brick has 3 motor outputs and 3 sensor inputs.
+The motors can be run forwards or reverse with 8 different power settings.
+They can be stalled, also with 8 power levels, and they can be left 'floating'
+[A stalled motor presents resistance to turning proportional to the stall power level]
+.LP
+There are 2 types of sensor \- buttons and light-sensors.
+[You can also get a 'rotation sensor', but we had not got one in our kit!]
+.LP
+We decided on a name space comprised of 2 directories, 
+.CW motor
+and 
+.CW sensor .
+We didn't need to use subdirectories for our name space but it was easy, so we did!
+.LP
+The motor directory contains 4 files \- 
+.CW 0 , 
+.CW 1 , 
+.CW 2
+and 
+.CW 012 .
+The files 
+.CW 0 , 
+.CW 1
+and 
+.CW 2
+represent the individual motor outputs and
+accept command messages of the form
+.I 'XP'
+where 
+.I X
+is a direction and
+.I P
+is the power level.
+.LP
+.I X
+can be one of
+.TS
+l l .
+f	forward
+r	reverse
+s	stall
+F	float
+.TE
+.LP
+.I P
+is a digit in the range
+.CW '0..7'
+.LP
+The file 
+.CW 012
+takes messages of the form
+.I 'XPXPXP'
+enabling the state of all the motors to be modified with a single message.
+The first 
+.I XP
+pair affects motor 0, the middle pair affects motor 1 and the
+last pair affects motor 2.
+.I XP
+can be
+.CW '--'
+indicating that the state should remain the same as before.
+.LP
+.LP
+The sensor directory contains three files 
+.CW 0 , 
+.CW 1
+and 
+.CW 2 ,
+corresponding to the three sensor inputs on the brick.
+.LP
+Before a sensor file can be read it must be configured by writing a configuration
+message to the file.  These message take the form
+.I 'Tv*'
+where
+.I T
+is the sensor type and 
+.I v*
+is a threshold value.
+The idea of the threshold value is that reads of the sensor file wil block until
+the threshold value has been achieved.
+.LP
+Reads of a sensor file return its current value.
+When a sensor file is configured any pending reads of the sensor are
+failed with the error message
+.CW 'reset' .
+.LP
+The available sensor types are:
+.LP
+.TS
+l l .
+b	button
+l	light sensor
+.TE
+.LP
+The threshold value for a button sensor is a click count.
+So the control message
+.CW 'b0'
+configures a sensor to be a button and subsequent reads
+of the file will yield the current click count.
+.br
+The message
+.CW 'b20'
+will cause subsequent reads to block until the click count reaches
+20 or more.
+.LP
+The threshold value for a light sensor is a raw sensor value qualified by
+.CW '<'
+or
+.CW '>' .
+.LP
+The control message
+.CW 'l>600'
+configures the input to be a light sensor and subsequent
+reads will block until the sensor value exceeds 600.
+If the
+.CW '<'
+qualifier is used, reads block until the value drops below the threshold.
+.SH
+Using the Styx firmware
+.NH 1
+Download the firmware
+.LP
+Use the 
+.CW firmdl
+command to download the firmware to the brick
+.P1
+% firmdl 0 styx.srec
+%
+.P2
+.LP
+The first argument is the number of the inferno serial port (
+.CW /dev/eia0
+in this example).
+The second argument is the file containing the firmware image in s-record format.
+.LP
+The firmdl app prints the response code from the ROM.
+On successful download the ROM reports:
+.P1
+Just a bit off the block!
+.P2
+.LP
+Once the firmware is downloaded it is immediately run.
+The RCX display should be showing the 'running man' symbol.
+If at any time the Styx firmware encounters an error, the 'running man'
+is changed to a 'standing man' and the source code line number of the error
+is displayed on the LCD.
+The firmware doesn't stay resident: it monitors the on/off button and
+restarts the ROM monitor when it is pressed.
+.NH 1
+Start the link protocol
+.LP
+.P1
+% legolink 0
+%
+.P2
+.LP
+The legolink argument is the serial port over which to run the link protocol.
+This will be the same as the first argument to the firmdl command.
+.LP
+Once started the legolink command creates the file 
+.CW /net/legolink
+in the Inferno
+name space.  Any reads/writes of this file are the payload data of the link protocol.
+.NH 1
+Mount the brick name space
+.LP
+.P1
+% mount -o -A /net/legolink /n/remote
+.P2
+.LP
+The 
+.CW -A
+flag to mount prevents the command from trying to
+do authentication
+on the link before running the Styx protocol over it.
+The
+.CW -o
+option uses an older version of Styx.
+The second argument to mount is the the file over which the Styx protocol will be run.
+Raw Styx messages are written to and read from this file.
+The third argument is the directory on which to mount the name space presented by the
+Styx server on the other end of the link \- the firmware on the Brick.
+.NH 1
+Explore the name space
+.LP
+.P1
+% cd /n/remote
+% ls
+motor
+sensor
+% ls motor
+motor/0
+motor/1
+motor/2
+motor/012
+% ls sensor
+sensor/0
+sensor/1
+sensor/2
+%
+.P2
+.LP
+Attach a motor to the first output and a button sensor to the first input
+and then try the following...
+.LP
+Start motor...
+.P1
+% cd motor
+% echo -n f7 > 0
+%
+.P2
+.LP
+Reverse the motor...
+.P1
+% echo -n r7 > 0
+%
+.P2
+.LP
+Stop the motor (float)...
+.P1
+% echo -n F0 > 0
+%
+.P2
+.LP	
+Notice the need for the 
+.CW -n
+flag to echo.  The firmware is a bit touchy about
+the format of the motor control messages \- they have to be 2 bytes long.
+.LP
+Run the motor for (a little more than) 5 seconds...
+.P1
+% echo -n r7 > 0; sleep 5; echo -n F0 > 0
+%
+.P2
+.LP
+It takes time on the slow link to open the file for the control message to
+stop the motor.  It should be possible to reduce the delay by keeping the file open:
+.P1
+% {echo -n r7; sleep 5; echo -n F0} > 0
+%
+.P2
+but the firmware only accepts command messages written to file offset 0.
+.br
+[Fixing this is left as an exercise for the reader!]
+.LP
+Ok, lets play with a sensor...
+.P1
+% cd /n/remote/sensor
+% echo b0 > 0
+% cat 0
+0%
+.P2
+.LP
+Note that the sensor file isn't as fussy about its message format as the motor file.
+.LP
+Click the button a few times and then try reading the sensor file again
+.P1
+% cat 0
+4%
+.P2
+.LP
+Let's try a blocking read on the sensor
+.P1
+% echo b5 > 0
+% cat 0
+\fR[click the button 5 times]\fP
+5%
+.P2
+.LP
+Ok, we're done playing \- unmount the brick name space
+.P1
+% cd
+% ls /n/remote
+/n/remote/motor
+/n/remote/sensor
+% unmount /n/remote
+% ls /n/remote
+%
+.P2
+.SH
+The Clockface robot
+.LP
+So we have a means of controlling the brick via Styx.
+We now needed to design a robot suitable for demonstrating the software.
+.LP
+The robot needed to be static; the IR link needs to maintain line-of-sight contact
+between the IR tower and the brick.
+The operation of the robot needed to be clearly visible to a group of people in a
+conference room.
+We also wanted a robot that we could layer services on top of each other to demonstrate
+the versatility of Inferno name spaces.
+.LP
+We decided on a clock robot.  The robot is static; it doesn't move around the room!
+The clockface would be visible and its operation obvious
+to a group of people in a reasonably large room.
+.LP
+The clockface robot also allowed us to layer services:
+.LP
+Initially we just mount the Brick name space.
+This name space represents the services of the brick \- nothing is known of the
+robot model that is attached to the brick.
+.LP
+We then start the clockface service.  This knows how to use the name space of
+the brick to control the motors and sensors of the clockface model.
+The clockface service provides a 
+.CW clockface
+file which accepts
+time values (e.g.
+.CW '14:35' ),
+the service then runs motors and reads sensors
+to set the hands of the robot to the specified time.
+.LP
+On top of the clockface service we can run a world-clock service.
+This periodically reads the system clock and writes time messages to the
+.CW clockface
+file resented by the clockface service.
+The world-clock service also provides a configuration file so that the user
+can set the time zone of the clock display.  Writing a time zone abbreviation into
+the control file causes the world-clock service to write new time messages into
+the 
+.CW clockface
+file to reflect the new time zone setting.
+.LP
+By using Inferno's ability to export a name space, any of the clock  services
+could be running anywhere in the network.
+The Lego brick could be attached to machine A.
+Machine B could be running the legolink application using 
+.CW /dev/eia0
+imported from machine A.
+Machine C could mount the 
+.CW /net/legolink
+file imported from machine B's
+name space.
+Machine D could then run the clockface service over the brick's name space
+imported from machine C, etc. etc.
+.LP
+The source of the clockface service is 
+.CW clockface.b .
+.br
+The source of the world-clock service is 
+.CW worldclock.b .
+.SH
+Final Notes
+.LP
+The firmware could do with some more work on it, such as the overly strict
+length restriction on motor control messages, or the fact that control messages
+must be written at offset 0.
+.LP
+Please feel free to fix problems and make modifications.  I am more than happy
+to discuss the software and answer any questions you may have.
+.LP
+Have Fun!
--- /dev/null
+++ b/doc/lego.pdf
@@ -1,0 +1,953 @@
+%PDF-1.2
+%�쏢
+6 0 obj
+<</Length 7 0 R/Filter /FlateDecode>>
+stream
+x��Z�r���k��d#�ʢ�)8�X��F���J&W�!�I�D�x��&�L?��� ��x1%��}���{_'�i4����r{����6��۳������+���;���3�&w�3�J4��|2��&w۳g���oO�~*��Y><��Ӽ�Lr��b��\D�i6�[�={�idkV��4�;�g�T� ̳�t��F�ai�}/���վ��jk����zM�75������h��f��-��C��m_Xy+��l�Μ��4�\ı]p]��F����A�Tq�����F<?w2�-�R�'je��A�qrd�������Z7�×/-��ޘ��ܬX���F�)��<Kf��P��f��@��ت�횢��d18����]%K�=Z�b���2qa]=��,q�JUY�$�T8+k��ю��(Z�(''d���Dt�a#K�lAoZ����h�Hۺ����Y����ysR��	�i�@b+�NX��l���ܻ	+$�G�qA���R�S����]��xJQ�*_k��x�D__��Eri���G,�Z鈒{Q��R��C9?nT߹�Ix��v����d���G�����#Z�7�pƁ�ۢ.���V���A�Fk7E#���~�ŇЊ7 �8ڲ#Ǜ`%�AD����9I��<��,*87��Z��\5nj�{�j��fh�V4f����dn1т����R�t��!ac߫�UO���F{&���`�L�����F�m6�A �]�)�N���<m�$�E�v
+H�c�r��Y��^��_��d�MًA⛟Q��D�ݦh%H�2���{)�-u�5��8r���⾕����CQI(P�:,7G���m�/>?���F\7���GW�LA��I�Q��e����R��F��1�EՇ1��͓+������@.T:���$[cx�󗡙8|	�!2f�]��]jm���(Fn�,EV�ْ�rҶ_{�@��)	�=$6s��0�<��cHܸ��t�#����ih@�+?�}$�˦������Y;�I9�,�6��D���\���Մ5��tS崠��?���)B4)���;P�X�ϙSa�[�I9��p���\��{k�A����{$%+���i�Y��Cb�p1Ki��\�D����y�3�m�;�;��Pi�b3�5I�I�� 1q�B/b�*!����e2�ɋd���t8�~2�(�r��'ǎid�,�����[5�C�d57���Z�G��B��P[�k�g�h�g�J�@� ��	:s�������SraU���e%!�<P7�����@EY��t(�G���:Q��
+�Ӆ}�u���K'����S%��G����u�oHXײ�m+�8e3��
	El�x����KQ���`p�Y����?�(��*@ݝPT(��l+�%�U�+�
+r����&���aw���v����J'?��v�瑂[�iV�]Gf��0��)D�o7X>	Vu�@_���y
v�B棈P;����Ga��D,��zP�,fq<Z�Z�-ฎ����s�aUM�S\�y���a��]t�=������� (��FݫN��O�ȃ�u�\
+�*@2��;���:�T�)���J2��j\��Ϥ�؊ �|zD���'hf]b��0Xn32�^��%�C����|0h,�� ���!?ӧ6Ž��2.K���ف���#Q�(U��x���E<�ҟ��g/mq�[�h8��Z2�?/�f9���ZA`��{��e���d�l;�l���i��7Q���.�8C��f�	l�����;entS�M�
+��G%��Nl�ϧPhp�����?�>�OZ�v���޾������@����9���Yٴ/J��|�w�B�1��[z1=��\oB6�ރ�y�b� Ro�Q��XnCaa��U�����N�h��'BB�e�/�r\$y�
A!*���Z3
dA����}��+�������V
���c}h��ԟ�n`
+2���u8k`�h�:_ـ+kN	B
/yxB�n�(�)A�0����:����h���+�	ߡ��T���x�%j:�HّA&��+B��a�e/� Y�/�ZH��c�j	�ԫJ�Z��&L������o:<���� ������؟��S����x�6�,�%Zf�J���f��Mx��#���1���<�k�v����
o��O�a����)x�|w)�R�^yg�]����-B,F������$�`ZA�<���GX.�	���dU�a�)p���`:�z�<l�����+endobj
+7 0 obj
+3204
+endobj
+31 0 obj
+<</Length 32 0 R/Filter /FlateDecode>>
+stream
+x��ZY��~����/�aqĹ���F��FV4�����INv.�A�����L���MnlD�i��>�����j~^�w���Ϭ��|�y�Nc�#+�67o���b���o�Tw�%+'X�A�ؔ7��o��n�/9���ĥr��-6���E�8G5�J|'�{��~ȫ��Co�D0T��(�1��`�i����i��5gu��i�w��+e\��4�럟�����?scLJ�}ޖ紝��5
�eS�RT}��ue���ّ]+�ʩ�a�"R����K�y��`��{�m����y�h&ڧt�|%��y4����I`$-z�VRm�a�$��m�Os=�i��j(�I�~Xѡ�	��8~�gD�n�34����A:���^W��PD�5m��A�Ĥ�?�7�H����u��6���'�O��PL^�沾��*ڶy�h:�T{�h�]����k>�t֮>WE�N:
|rF҉�Ɉp\�=M�.���k�`���z7�	���Hw�5����Qׯ��QlV:��Q���[I>{�m��_����lj��P��UE�4��N��t��<��S�|%�	�ͽ�P+}^��{A��q`��{
xZD�Q��D%Z��8�mSw�\����K�P!����	�´O��#��:�)�EeL�G�V�v
+y/tЁ�y!���V��$瀬���}���@�+����#��ҋU�G����b����!�[
+��s2^ɹ��h���w<j� ��X7SrH���Ͽ\���~D�.���3��=j�2�Q�;kL�z�
+��� "JP��1����oy���༐n���2p9y�U<��+#�}�M�oe�{Ȕ����}�M?�8�+Ie��2��R��R:�	+Fr�59
�����ۡ�@Ñ�aC�j��I(FU�2�l#�2�T�Fλo�J(����݄ns��cb���b�ȁ[r��'���O�LR�p��}�T������{ɔ�c��c�7?�}{>��&�����DYWNV;��۹\KX��&���N�ѡ�GG=#��Y;0��|�ɹET�+DPm(�%<�i�<�r,��L��1�P���sˆ�+Ǝ\<]�� B�#�h{����i��n~&F�{���Ⱥ&qT�G�%�EZ聲#-2+ܜ���Ox���D&$�VB�'����G��(򓬘 ���8�T�n����A[����ۺ�h�&m�W(�D,'�.]U��]P��H�>���2���Bo�ݰL����M5Pg���#�i�������Ҋ�#����K]"��WW�܈�3@�`W�,WC�+��B���VZ�����u1!Y"\3�P���dI��q(CR?%��5Qdj��I����KN�kD&�����u�f����i?7�Ϗ�vϝ]��^Iv�������4
lb�9��ɸ<]Y�b��l��3W���{I�
+4�:�+endobj
+32 0 obj
+3178
+endobj
+40 0 obj
+<</Length 41 0 R/Filter /FlateDecode>>
+stream
+x��ZI��6���P�b;6e�"�K*����=ɴ�0U�9P�☋�E���o���q�R>������+ӗ�]Y|R�"Z�\�����w��C�C�{ѩ�64��+��
�ph��������A�3TJ>I�?4űk�v��J�Q�I��n@<�2��]7ű�F�� P�h�������}>��Z4ty���0�����=3
+W*+f���\9ʦ㋮Ԁ	cZ�*�O���+����D�i��h�iﲹS
+�I��e#����\�]�{
N��5�Z�0�#�--��q��X��� bG}"���fV<���<�wj����h��X�/$}�f�kM�(أE}���WǎY*&��m���mlu�y?��5���Q&��W�b	'櫾��B�I�h&��O�z0��4ǴN|�V�/s�}����RO�=%P��s��X��Z�C�][�k�A�'.���\>{L�l:aUI?؃��(r���wXe�D�}3E�Kq̛;-�LQ}
+����O]����@�2S�
�ݐ��`o�fT����@;̯�7v]���7|X'D,�V J�qx�b����Z�N*��I���+�8����p�m'D�${�S��X߭-V�D+�X3���*�z�KN�5P^	�I���w��"dB�ZTxȘVʃA�1�*kMFNBVQ^O3��<p���1���U�KlJ��;fh���;�2�����09�a"gá?�(9���31��z&&���A;�6�Y�FS���
+�6˻v�{�M�M*B�� Ux
n���qz+�Y�A��!��A)E۝Zct<H��"�*���Xb7�.q[JZ$�Ëo5�S�;@
���"�
�i����'C�`����)�>�Y��k�A��l����+�S�~�H�NF3��+Eì/:0�,���n�HL.PBN•�������\���QR"xw�,��\>������0k,s�,���]�_��C;џnSE��
�e/TM+�f+�A>�i��n_\���ۗ?*�EQ�z�؝���ɛX��8���y3�� UB���N�ۓW�{��	!ɨ)ÎX-�^y%��Ș	cy�]9hxa��o����[� j���M�?p��S��C4c������K�~Л���.���7��;���?Tm����h� �K
�T���B��]��a�0�D{����)�����1��/�W!�m�e�,����4\���X���h�>A��O����Wh+�um}����x�oV?����?�����n��sD�&_������Q�C��QY��K<�1����n���S?�\9�x�S��ч�V�+S���FA�� ��\ڣ��[K8��^�YJ��fAi+���p�Z������i�c7��Rי��Pڊ���<�4/�}���<xo7P����x����F���f�n��F*�N3�r���i�$pa�F�pVq�bc��'�PR4>.����bg��U���F����vÀ��A��m��/���v�w����|r�,Q:�����\.��ۥ�	�:�k��i�'�c��o#�����p/���h,�G�8}D��E�N3;R��zJ���y���ɋg�U"n�Y
�Ǝ!"����Kf���������Q�t��nLJ�QJ��0���F?�]0�����u-�%�Wb��[��kN7�����ѕ�|Y�+Q�u�N�+�}Y�i��S �~��@�%��v�$��#V��G�E��nl<��$\X��a��vpk\�^
+�j\UMw#��Tn�������F��t�f~/	�a8��\ɊDo��^�q:b#��!`	��j	/���$΢�ز��-��+9�0V:Z%�g܋��A㆓�w����=��
"���‹�+j0�Eb�G�}e�í_訉c�ҦN������Ʊap�`�c0.�r�]�X�U��j?���&���c�WWv�y�)��%�7=f��C�TA�jF���c03bZ
+��;���a��‹����9�����A��=�{�;V���B�V%�d�Ҹ�g����ic9��žy�IZ��f/�����
+��w��y����n��p��-�����ӽ�f���l���F�D��Z��Q�‡���nh�����y��|��Oo�����
�qqʦ�������_Wӿ�O�·endstream
+endobj
+41 0 obj
+3002
+endobj
+46 0 obj
+<</Length 47 0 R/Filter /FlateDecode>>
+stream
+x��ZK������@>�5F2��b�䰱��vI���H-3����fw��Mi�N0��p�Q]��W���+o민�~�经wW������ꛇ�����U�z8ޙ��*H�m��G���|�f��V�����^��o��꡸{�p*��jz��۝�?��][��?է>]ʮj�*�9�eh��j�S�m_�F�φ�����6���)3C'q��ƏiP_gO�[�˝2����1�R��<���m
+_~s���CY��v�O䑈]�q,���&,�cΒ�Q�+PHBK]�#imh�o��3��r������I/�Q��l|�+U���eӎ�'�f�@oWx�Z�P�W�G;�%�̾���yy�Cm`��45~�	�<��j�X�� rd��1�d�
+���K�#k+�;LFEL>�6�1t����9�k��"����B�,��,iQ��@�,.�A3�"� /��0oϗ����	B;	;NM��SiH۩J���'�~"�<��2�T����g��!+�{<����8�ZQ�z�򫦤HNLk�r�ѐx�~<�o'����Co8Bp
+9�rL/�,'t0�i�99g�=�
�[f��=�Z�N��l��s�I޴���d)�@4�@����6CV5�"�-�gǪ6ZdrR�6	O������dLK��yF0����/����I�I��g�r�*haV��|b����'u%�^M�B�H=���T�7�Hq�C�Q޴�r�8OQ-)E�1]�_L0;�ah��\�
+��ݨ;��:�~��^�����a�����,�~>+��Z��؁��_;:6�P4Mq�w�	����jҲ���	�X�jHW�G�����>��6q����?�]���NՁ�'M�5P����5�������O����������
�>���J�6��汜���D��v��0�I#�Ѹ<O-_EEE��.�%\?d0#]�D'M�y��Y�D:��wӏu���Z�dl����F�}(gJwd��>X0u�����VGd�O�TZA~�Ճ��f��MH�����nǂƵ�Fܹ�ƪOV�z�"༷P,r�KV/K9&����[��J�F�<�҅N�*�������ob��}�����z읦��+�N���k`Ѩh{�ھI��1�J׿�jG'ND�<"�
�O���E<v����<g���%ϾѦ�\���C��߀xz���t�a���&�ϐyi,:]�BQj!#c�{mF�a�3�v]=+��>��md5ש���U��c���t���& ��U�lʃ5��ٚ�hK���
$q��hBs{�b܀j
+}ѿ��Xϣ�|�Nk�c�8vP9smG�t��Uw�����r�ш�2��!�9]-�g�Ya��B�+��D(��򼲉������6n��s����Ith3f���Ρ��z?�P���+�[��Y��<}i�1S�-�e�ɑ9n��0��z4	8�1�Q�_����W�ژM�U
+ۂ �>ӂh9����}pf:��sz�/���l$r�]����j�䐤��̨���
+۪�o�/Sb�����L��*U>@\a4#��H'l}Њo�c�R9�e"���Ԩ�q���0�ϗ����5W�3���?��x���N��8�XtȷL/�nJ��Kf.�����S��s��Ǭ�� ZJ�mz�Ae���܀l�[<�YO}��⽐�<L~���h�'%���¤/�=j�@��fo��t�LƩ�N���PY�گpt����E�t��wqJ�3w�`R�$Jw��"�p�J�y����5^�zȊg�o���-����"���]�u2�/��;���gG._ɧ�{��J��>���n�ɜN��j<����
�~<���5h�E��wD��P���Pҗ��2��kɃ���c�ƛ 	�͎낟t�C�X���Βgp� ��t�d��?R^Ռ��J����W���y�|��v�v�����1۽^�p|�����݆��g+l-��$��1���#�r��1$>��d!H�.^��4���k{�uѠ����`�8]���	��˿u��γa/�Lq�N�ʮ���
+�+�/��G"3w��/�*�ol|�~r�v��Mtcו���T>≶�t?����
+E"
+�T���e�W#�U`(G��~�G��d�P쾄�Ԃp)��V�3=�����L�"[K��^��%e]{1;p���w�{���<�h�z�j�����S/��Z���jW<��:�ߗmv��qkd?n�k��ԭ�@D����W��}0{,�C��Yn�^��+���!'��iN�)��!��ûW�����>Fb�
�Sp	�+s5�W&��]��e�-�Pv��a�ϻ�����]endstream
+endobj
+47 0 obj
+3155
+endobj
+54 0 obj
+<</Length 55 0 R/Filter /FlateDecode>>
+stream
+x��XM��6���@=�j�"%����&M�	�n|�a/�D晴DG����/?���+��o����"2�
+�걿N��h_
�8"�o��E���1�D��B�r(8�	��3��z��mpA���QD�`@;f�-�X���b�_�J�2ڝ��b�����|x�O�̲��5ӛQ��|��֞����F��3�	
k,s�n�_��t���j������/�^�1 ���0���,�6־+h6�bk�(L�����߿�#��jR:�B�+޷��	�JI�
��y�NI�U)�J�]c����}oD[
€�b����R���ݮݟ���Y&g{1�ҕ�uF��\��g�7�����͙)&(�T(�G�B���7������	cE�I�}A�2"�����Pw�D!�P!��<���I���
+�g�^��n�����������d�C���k;8����j��+��sU<C�+�R�}HrR�_L}p�DҲ�������~��\�5�����2A�wo�Xѵ�a=�DK��[���f��?A���o�&�V!I���X%�ر�vIF���T6s��.Ӯ��Ӣ���%��z��bo���l����E��i�ƒi�|�M�ܷ6������H�E��r��TWV��~y�*�d�W�
Lth�����ˣ�������d>��c����&�hϫ���n-���!�}P��e�:��}W��h&9�$\�  �|�c�Tب�����&�۲���0���R��~�6�f�P��@}'U��hl��|�0�L�R��b"�Ό6��L��%OJ��@v�g�CU��2J�y���t���͞���䷒�i5 D���������fD�2siB=��ڷ��ڊG��|깕lB������#������AIZWԭmg��]O\%���'FZ��>�`p���PՂt�͎uhr�Xym�y8�B/��|�'��m�r27]�K=�3��O��{7��cO&�)zb)�U?���Nb�G`�<ㆦ+p���I��O�g�w���k��I�����`zrc�8�NW�&�U��|zǠM	
+CHs�e��]⯨�%]>��dž��1C�'��w_+endobj
+55 0 obj
+1942
+endobj
+61 0 obj
+<</Length 62 0 R/Filter /FlateDecode>>
+stream
+x��YM��6��u��rzX��O�`	6+ʭ_s?�A&��_!ڕ���b�q/�������M�W>t}4t�#<�{(/27nFk/1�D���1yMr+�
���a�#��{�yG
v)�z�Bt�Gá������3hd��,�Y�=���9���ATq��n0�Y����\DhHG��Υ./>��Mx������;˘Y1�o䄴���v�ݶ�,�p�9���D�$����uT�`�\PD��s�� ���`��������������j[���!�P��� �6"��f� �}ec�	��"���;�f�����]�����x�+K�I����U�k'�3goH��P�1j�l����42����βx�(�Y:}4�6���|�J�0 1�
+�)�En���7Ҫão��bw�q�S�<�9��lX�Q&�Q���K�:�s��  (��w���>�T�K[}r��A�+���_�0,kn��e��Wj��Ko�5�1���3��s�
>s%��)@
�4$˷a���"�W�W�z޾��(	�1!�,�䇅y��މ6ڿ���U��.���̬w��
������JLD���^d ���j��_1�\�#��ҝr�Lf��&$p���s�w5�e8�� �Tܯͻ�2������e��U����s�È�l�N� �������x=�ͺ��:/�l��Ή?i�+��K��/iZ	���1䕁��g��rj7�W�%�Uj[�eV�gӥ|+>�t����e'Od�LDgq���F�Z��g���n[^;���u|����4!�G~9%"�3��>��l�3����*�6�(��6r~�4P��y b�� ��o3H�X>��+g��i�
+P�gǚ+g04�9�K�:�m'��ڵ���ᝀw�-3!����2ށH�f0į�����"jK+w�W6
+�վ�+e�uQ��Z��8��q���+l+:N��WV�\�A��p���l��P���l��w<����5DJ�S�*;�r\��N�{����!���#�dk�=���Nvj�[�V"��EH �ۢ��箃q�G��(�<pfj�	�3�x���퓉���ydJs[X*���GS������)u+y~��D�<��Sej�	��6�E�U�S�f1D�̵��N|�z� $Ղ��p�F*�t��\��7�$���k���W~u�Қ���t�0F��ϭ�\�L��,@QN$�,����1�\�:Iݦ�3��fM�JLB+>����$;�z�m);����9X2R������RL��j��	z�~s2�4�y��JXWS�F�0W��QbV����߱%咂���+=R����צ�0������X��NM�	[�Y�CQ=N-,(*�ߛ��U��Ь�+���e���]��	�K��;���E\�g3\�&Վ�ƭ��7��H���D�δ�g�&0S�Ԅ���������V��endstream
+endobj
+62 0 obj
+2278
+endobj
+68 0 obj
+<</Length 69 0 R/Filter /FlateDecode>>
+stream
+x��XɎ�6��+�S&@[�͒uLO2+ؔ�e���KU��=)h� ���a���l��A�����%�h-��|�����n<˾9�̽��0�\��K����X�)�ȓ�ky��e�\�����.g/9�5^u�h!����A:��	�(�t	q<������Tu+�O4�b�g�2e����x>~�C�š_e�ɲ�(�U�`|�0�N	�w������������VjR�a�sf�,���Q�4Luz	�f��l�S/���.a܁J�����y�KUKúuF�+0��iڧڈi!�bZY�v�x���_w������.���8�F'Q��A�嵹�]��V̹�Է��cjM�V��gOl����^]�}f^sek��A�W�|�������^T��+��C�7Bp��\4'%w5�Ȱk����>�6��P�a�r1+�Ǯ}'���������r��v��${�1�k,]�b2���4�+������0+endobj
+69 0 obj
+1455
+endobj
+5 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/ExtGState 27 0 R
+/Font 28 0 R
+>>
+/Contents 6 0 R
+>>
+endobj
+30 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 37 0 R
+>>
+/Contents 31 0 R
+>>
+endobj
+39 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 43 0 R
+>>
+/Contents 40 0 R
+>>
+endobj
+45 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 51 0 R
+>>
+/Contents 46 0 R
+>>
+endobj
+53 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 58 0 R
+>>
+/Contents 54 0 R
+>>
+endobj
+60 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 65 0 R
+>>
+/Contents 61 0 R
+>>
+endobj
+67 0 obj
+<</Type/Page/MediaBox [0 0 612 792]
+/Rotate 0/Parent 3 0 R
+/Resources<</ProcSet[/PDF /Text]
+/Font 72 0 R
+>>
+/Contents 68 0 R
+>>
+endobj
+3 0 obj
+<< /Type /Pages /Kids [
+5 0 R
+30 0 R
+39 0 R
+45 0 R
+53 0 R
+60 0 R
+67 0 R
+] /Count 7
+>>
+endobj
+1 0 obj
+<</Type /Catalog /Pages 3 0 R
+>>
+endobj
+4 0 obj
+<</Type/ExtGState/Name/R4/TR/Identity>>
+endobj
+27 0 obj
+<</R4
+4 0 R>>
+endobj
+28 0 obj
+<</R22
+22 0 R/R26
+26 0 R/R24
+24 0 R/R10
+10 0 R/R13
+13 0 R/R16
+16 0 R/R19
+19 0 R>>
+endobj
+37 0 obj
+<</R22
+22 0 R/R36
+36 0 R/R29
+29 0 R/R33
+33 0 R/R34
+34 0 R/R35
+35 0 R>>
+endobj
+43 0 obj
+<</R42
+42 0 R/R38
+38 0 R>>
+endobj
+51 0 obj
+<</R22
+22 0 R/R44
+44 0 R/R48
+48 0 R/R49
+49 0 R/R50
+50 0 R>>
+endobj
+58 0 obj
+<</R22
+22 0 R/R52
+52 0 R/R56
+56 0 R/R57
+57 0 R>>
+endobj
+65 0 obj
+<</R22
+22 0 R/R59
+59 0 R/R63
+63 0 R/R64
+64 0 R>>
+endobj
+72 0 obj
+<</R66
+66 0 R/R70
+70 0 R/R71
+71 0 R>>
+endobj
+21 0 obj
+<</Type/FontDescriptor/FontName/KORKOY+LucidaSansUnicode20/FontBBox[-302 -205 1349 976]/Flags 4
+/Ascent 976
+/CapHeight 976
+/Descent -205
+/ItalicAngle 0
+/StemV 202
+/MissingWidth 316
+/CharSet(/2013/2020)
+/FontFile3 20 0 R>>
+endobj
+20 0 obj
+<</Subtype/Type1C/Filter/FlateDecode/Length 73 0 R>>stream
+x�cd`ab`dd��������)M�LIN�+��L�OI52+endstream
+endobj
+73 0 obj
+303
+endobj
+18 0 obj
+<</Type/FontDescriptor/FontName/KERJOY+LucidaSansUnicode21/FontBBox[-30 -325 1384 883]/Flags 4
+/Ascent 883
+/CapHeight 883
+/Descent -325
+/ItalicAngle 0
+/StemV 207
+/MissingWidth 316
+/CharSet(/2122)
+/FontFile3 17 0 R>>
+endobj
+17 0 obj
+<</Subtype/Type1C/Filter/FlateDecode/Length 74 0 R>>stream
+x�cd`ab`dd��v
�����)M�LIN�+��L�OI52I���f�!��C�9��M֌_쬲�
+����O��$�ݞ+P���8�Ȉ���Q����������������]�}�^��b׾�^��{�OS���{?��.���5��ߗ���^z��?6�ߓX��L�Ob�������=l~O`=��W9�g����ӿWNg��q��I��^��~��5�Ke>���<<�'���q���b`+endstream
+endobj
+74 0 obj
+295
+endobj
+15 0 obj
+<</Type/FontDescriptor/FontName/GPQJOY+Palatino-Roman/FontBBox[-166 -283 1021 943]/Flags 34
+/Ascent 943
+/CapHeight 709
+/Descent -283
+/ItalicAngle 0
+/StemV 116
+/MissingWidth 250
+/XHeight 469
+/CharSet(/space/exclam/quotedbl/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/question/A/B/C/D/F/G/H/I/J/K/L/M/N/O/P/R/S/T/U/V/W/X/Y/bracketleft/bracketright/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/guilsinglright)
+/FontFile3 14 0 R>>
+endobj
+14 0 obj
+<</Subtype/Type1C/Filter/FlateDecode/Length 75 0 R>>stream
+x��yyXW��PLfZ�ZґQ�u�֥�Z�uEpAW��$@�a�$'		k��MEeq�[ݭUk���պ����뙼����3H[��}���]�a��<�s?�}Ǝ�agg7z���5�>Ӽ�����2���~2�e2�lǍ}�g��C��2�k�`�^qcd��ɧmٯp^�,�{~�]�]��
[�N�6}�<2!:48D)�=�|��d�E�B�
�I&���pyd�T��!�(�J�!RIPh�T������c�d�*o�*�L�.���
���He
+�TI�<Z��I�\���3$K?�"R�I���|�tI�4:"T���%�
+Ip��L)
�(��PY@xL �<~$�)%��r��[�T^r�R����V�>ݣ2�Oɯ���y�(��O�{��/T��(��J~�$0T��SEF�n!F*�c���hi�_t`�T18/o�?�'y��~���	�c僽~_?T������`�����%��A���A�Kd[�-K��x,��z��
+��vU�lX�ݸ:f�&��0�5q�~���G�o������xo���f�5��)��L}���ms�I�MOo_“XA�'f�m���x��I�F�'\�Y���b1��H�&&�7�mb
+�M�!�S���Z��
b�N�%�[�u�2b1��!<��Ļ�"�%{b�2�L�"�c�WGBDPīċ��������p"�XH8#;�!F/���0"��M�3/l}��~�0�a���p����DvP�ԧ/�x��KA/}1\1�ሾ�I#�����/?�xT�+�]�Ģ�W�_-�'�m�����'��\bw�ywL��v����ǪǞ��8�qY���z�AW�1+^(� yI�"���z¸	�&������}&���k�������V��f�<tE�p�
nz
���\��[�P�����_ݫ6f��쀌������$FI^2��zP�@��������Y��
++̠���F�W�4�o���+��4���J��	O��W4x����<CȞK�?�|�g���w���ف�칉�
z�݅��!E�`��)]�+h%x�B���1�nV��]�Z�K���2����̯݇G�~s�?.�B��!p����a��aQe�@G�
���,Z���}���T�v͓H�ՠWa�rory��E�#�Q=�ZMǞ�M,|����@��5�����!+�Ei�d�p6�ḁ撺���0�+0��銝@	���w��Z����߂� 3
+v%��\���O��ibQ���a`�&]��o�
���ݿ�á݉��ݯRt��R�U ��#���VGx��Xh[H��&u{α-��p
+7�R@�&�`aN���A�z��t�a�u�/a+���
J�E������#�����D4l���7�Wtb+��C�v��͎s��V��J���x7�Ƿe5jNSp��*8h�Z�+��b
+�Ko�4�[��w��}�:0��z7H�o�~t����*K��Z��-�6+���4�*�"+�2K�i��s8�p�£������4T/a�:����6?:� ՠa $1&z�#ۣ�	�(?�5\C^���g�,�2������9p����)W�	IK㩆���Z�b.�~�W��Z�ѽ|��pͅ���tGAS^;� q�g�l�9����(�9�6��%�+����Y��a0:��*B��E�����d2�j7�Bu�z
+Z��+��Nf�d�fr��Z�A�����C���n �2���q���8�l��(�3V� �y8X���ks��(ro8�tÉ4pUGdKܗՋ�����'-5�VqTݞ�����EZA/u���C���GC������в�"8�o��Vl���:�7Vܐz<�JrOze,�R�>�xԲ-G�����7�`ɷM�O
+k���?��[����_��.>�>�=�����(Cl�Y�a(P-8P�����ԟOo�;s�zDee+_%O�qق�$8`�,��Z�(�#T���]<��V���bIxhCK��B{Nj�~�Q�����ɧԶb�����;��i�%"**BV���P���(��Eu�!���=xg��\

�絛O,h�iބ�?o"'_KpS��=�7���VZGZ��>�X�-0{ɚ���ם��yY&�%`E�
vhb�w��>�:��mt��ާj�׋C��,hX)r(��nQ�Ο�j_Wfr�K[bQ�Af��8خrЧ�`=Y���~E���"��~��Mr%c��Z�H%�1�8]����ٶ���
+�A_�c#���1S6`i����ᖧv��LT$��ޝG���R)���� /J�L)�j�(�O��?�JSxEtu���S���{������� �&��SX�^ցR,f�J$P�:���V�s{�G�j�;{+�ߒ�)2�
+d|�$�!@Vւ9�&�#͒h���L_gCq;�Ɠɵk�+_��p;��J�q�lD��Y���鼝�o1���h�*7�:{~+X��I�Q� 	��6�� �Ҟe�l��R� &�����K�_�˳W�z��Er�܇�w����>�s+0]����i���W�r�a�%�$��������l�!��,-U}��^�~�fMI`���
۱\����y���`�w��૴��]�����]֎�Jq]�%�a��a�M����t3�^�6R��#/<�p�Ҙ3,,��oY\R��V�+nk��q���E�VC3�~D��R'ӱ9�I:<���ZkI�,HW�d'������yZ�cAqq�U�w��Yv1���SڜD_	�����uY��M�O�%�7��.�+aVCm��^���I�����[��"I��JLJB-���{�?Rؿe,�ښ��MiL�:�$���X��g�/�+lI�|!��/�>Dru�%�Qq�1�JS��N1��pZ���Y��t�&F�����+����n<a~Esu�(�0� � �-1��Y�f�:��/��hC�.� ��u��ǽ��{0��s*�V�y@�����k/����s�}�D���.h��3�)�;������w}Z�w�K>��n���?����f��2�\�
+���+�  �HHr]�|A�\�Q�GR�[(;\�~i߰���O&�:md�ʲlf�����������J��9��q\� ������	QQ.�6
+<��sEYEcӾ�n@�;�J��y�?w���j�ÿ�ql̶�٢3��RC��h044�7��Ta.�ַ>%�t|����Q�P��p�R�V������ŜUd��a��u�;��1W�ɜ��X[�,�66�/䑣:����l��&uqZa0�[6+"�� R+	�M�:9=#5=6;PRan� �4e�׃:����wUSha�k�-�[�X��BrE���~sK�f���T�n������&̺����B����OL���J�v�-�kwC
��Qw�"�1ѭoϵ8;�������9�'�j�~����|�������������Mg\o��уGT~G����G�K�=׮�o[�!:p��6	��v�0��r�Q�ʄ���9��Ba��/8��­:=�=[c�����w�!��V�1��6[��bb������Ya����6;���_�?���}g͉��w���
+�P���~Bzu�d�p�漟���V�|t:-Dv�e䶋�$��m2����*Š}�Nj��u�x_���c�?�g0�`z���HyDD�������Y�.��  e_~^�d�3��[q?qe������
+`�m%^b�m)�a�tu�;�Yl6-5ݮ���I���+�x�[�����+tdFB������k�O+Ic�+?�e���[�*���,��밉:x)U��Yf[I���rЋU�:|��'�����	FC!�����rB?�7e�P��3����ap�݇�_[�t1ɳ1�/s�h�ҧu:�֤�P�H�%-�[�q�B+Z�����nk*6!�[rE4r�����*0E����
+4��{�^`&WA��'�.,�#���Xq��.]W���&N"H��bH�F�w�>]�W�łb��˔*8-���{�_!w�NF��1�+���'s��0ĘR���І9�J�Lu񉩋�5��ׁ6Ciaa���+endstream
+endobj
+75 0 obj
+8093
+endobj
+12 0 obj
+<</Type/FontDescriptor/FontName/MYPKOY+Palatino-Italic/FontBBox[-170 -305 1010 941]/Flags 98
+/Ascent 941
+/CapHeight 706
+/Descent -305
+/ItalicAngle -10
+/StemV 105
+/MissingWidth 250
+/XHeight 482
+/CharSet(/space/quoteright/asterisk/plus/period/zero/one/two/equal/at/A/C/D/J/L/N/P/T/V/X/a/b/c/d/e/g/h/i/k/l/m/n/o/p/r/s/t/u/v/tilde)
+/FontFile3 11 0 R>>
+endobj
+11 0 obj
+<</Subtype/Type1C/Filter/FlateDecode/Length 76 0 R>>stream
+x��W	XSWھ�	ץXI3��6����ժ�vƺQ�ED+�X�e�v��v�3�vl���tz.s���	�3�>g�'�s��{�=����{�0l�$,,,lֶ}�[v���"JQŒ76)RD´��kTt��$��p�����[�x�Z��3/�L5ΞI�͠��bᡍa�a�s���}޼��$R�L����/Z�b?U�+?F f�����@$�+Ċ�8�����3�"ݎ�}��o��ݰ}�@,��������T���4�X.x��!��EO���$�t�B(�����)|�T�&D	
+����|�T �����/��3e)b� ������4Q~z�<z�!+�R�����U�D���ɄRY��Y�􌊬EȮ\�����f�$-?��?�)B���(BvR�t�\*JQ#�h+�L8q�|�P��/���2Af�,]$�O��ʿ������T���V2��?�r�(c
+8%U��.��������1��u�8-A��}�T+˔g)����9�E){sS,\�����V�|���^�v`1�
+,{{{ۉ��^�aq�Fl7�	ۃm��bK�xl+6ۆ�Ŗa۱u�l&�q1�cZl66
���a����&c�0^�褟M�7y����0�M��q�7��)���uj���i�3�w>���3�"�3�g<xV�l��_��=S6�~����U�jd�@g$u�:8�L0>��v�1��E�"��Hb��*9ak���@M�b��,Z���X�ZS�ɜ� ;��d0�ʨ`V�f��8�f��U�q�p�!�Ph0%�-��`?������PMzH��T;���v�:���k�0+�Px0���R����Ly���8u��H�̌��j+PD�|���#��������uz@�J�>�#�x�a����
�F]�*e�`w,W�%Ư��K9e��J��덕ez~�Zn$5Ow�zq4|����k�^o�ܟ+A.�J$Q�Zl��JS0���ҍ���ѨZ���X� {�Y�#��~,t�����T�z(��{�fXā�h�W�*�h�ʸEvF$�룖���A3�_�d��s��y�U@Gⳇw=8w�ep�{��!���_�[���/u\6O4;y/O��ӊ+�f;-+�`���J~���9����?g��g�ԗT
�����>��}W�6�����HO��z*��������{t����G��7vūW�^��\û���eމ��M��mp��|f(kt{�Nd�����Q���'�ke�>2����+�{�p%�x���\^@T�
�F�ʦ����w,T-"���zw���"~M+ڭi�T+�"$���@Y+�A��$�b¸����ȡ��QakI�C�-���9�H���Y�������?�v�͏����x�.�xf�d���S���5x�������R�Pq
+����T�B{f���}w{���?���>/��Ԣ�����A�yc��8�mN(��%���
=`�=�����gs��T�pv+`+��U����^�!�0x��3�{Ws��p�-ge�������&M@�*������i���m�[�@����ɋ�t�3��]�q��~Y��: qF&��B}�f�l�(��]�2&
�F�7P��r5��`���Q
��:Ce������c�Y�z����>i3���5X:�_����!�!��5�����ǟg���1;�N�����l��1[������
v��2�r)9������v�����]S�&��}��!'3�>�-ZhC�F$X-�1n���v�&�t؏"p�
!p��1�Mp���/��`Թ;���,�0���%�W�-�:�3�5�4z���e����}{��_�H��Ve(�J+G]�vj�&��z&�G�C�v��u����$�����h^�ݗP\H�ә���*���,8}��~M���{�S�<�	�>$�B=�~�I���j�5�t�v��fQ_��4(�����(G)���	����*���C�J��zo���j���I�%@e��le���'�%����x�_X�������;:|�C1��X
+mjP�����%�Ɓ������K�V��B�H5
�
�����t���.;�+���Z�}g���U�W����OxM�kG@#��iB�������C5�ݶ:��0I�$E�=�.���2���mCV�ѝA|��I�Q&I}���A*��
}�k��!A�G�3�Lz*(��uz�6@g�iU!N����f�J'P�x�,��	���W$�m�n=����a�"�,��7^��,�M�O��M���wA�SV��"�����		����7<n���H>�pw��$+�f���xE]�[���j�w04J��t�����Hn-�_�+�Z�C/4H,y � I�!����Gw¡�'��d��Ky�>A|��D�H���SuǸ�n^�/�}��Z��[+u�Z���Y,�7W����˝�[�כ������I�7F?�m��მ6d,ݲ���'f�;���sX.u+�q�}�R4�u	ܱߴnqJ=V�1Ih͊F@Be��;�����\C�E�J�-q�����:ua����3��b�{Q�՟S�lweE3�����is�I��s�4����f��G�*���J�3���&��&k�W�tD��\�Z�RZ�0�fe���G���>��
�b=_+��F�8&j�HU��	¤ �o��ӸS�}�|?}J�k�t�T��ӣ0�t��
+endstream
+endobj
+76 0 obj
+5031
+endobj
+9 0 obj
+<</Type/FontDescriptor/FontName/YCYKOY+Palatino-Bold/FontBBox[-152 -301 1000 935]/Flags 34
+/Ascent 935
+/CapHeight 695
+/Descent -301
+/ItalicAngle 0
+/StemV 156
+/MissingWidth 250
+/XHeight 471
+/CharSet(/hyphen/period/one/two/three/four/five/six/seven/A/B/C/D/E/F/L/M/N/P/S/T/U/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/r/s/t/u/w/x/y/guilsinglright)
+/FontFile3 8 0 R>>
+endobj
+8 0 obj
+<</Subtype/Type1C/Filter/FlateDecode/Length 77 0 R>>stream
+x��X	XSWھ�ɍV�rM�W,D�K;�Z�:j�(���"� �%$���5!������	�,A@Q�J]jk�[�Z[k���t�Ӟ����..Ŷ���?O�'��{��{��{���M��999����߶s�#�y����JE?������7���3�ō�|�終DZ��g��s']�>��<�a��9�Ә������������Te��c�4�gW�^-�ʔ��l����I���K�T�T%J�4�${�R�&N*��R�����[vl�,ݼc�d�4I����F)�ђ+Þ�`���&l��^Ğ���va��"l3�,�ۃ��-���-�^l+��c۰�X+�
#�g���X���ӹ)�S�:�M
�Z#xA��p���+ʙ�`��t�#[fL��<s�L��Q��.wf������َG�Ε!�'sb��s:Ğb�c.�չ-t���K.���]��9��ނ���s�����L��%�p�+&Єf�4����K�1ר_̙�U0	0�RC)UPo(���ZV͈P�v����Y���]�7C7�iv���l>�8%���8#+�;8a?�q+F}��a{Y��������T}���1
+�/�����kX�ҝ���َ�e}2��T���ˎ�y�.�:Ί�}p�MÊd���Ɖ�X8�.w¿0+�n.��䈄g�?�^��qɅY*�0喘�����V�i|򢽼��G�ٜ�����h@��m)'��tM�3"�&�K.T���vq�PT�a&�!ٿ6�]As�i)��<]�W��<
x�&��p������-d��i��N~@]{����F����]��6s��ܸ�6 Z�A�=Ɋ~E�x}��4
\��L��֠���?��B5lK�������lJ� d2)ŨVP����\o�4���	1�e�J+-�u�&$5��̚R�;\���a+T�(Pd̥�b9�����<�;�~�������J
+��u9�#��@�N��t90�*-eV�3&A/ι�����7+Ͻ%�o�;!/�k�L�;V�*᫼�&����r�Հ���6�Z��L/S	�@�苝�GF�jd�	���q�-m+m�[�x,�zE&ɹ&�ǀ�D��?���Z�+�g$�2�(!���P���z��
+$�*��gs%|a���)�$]���0R�/�c�V����I"�o�:��1�
}����`���.zC/�;(��)/�3���0[��̦�*.C���K��Rda:A]��C"��gN�$��Z���*J��%l��6���~y�)�Tt�u�w�]j����֡w�
+�����?+HX%4�Y{jz��I�� J��'đ2YddO\�����_��7s|�\�:H�
p����Ę��YhS!H���ARF���Ƿ�W�+LrTL{�pG���/�*Q�=ė���ԔQ
�)�!FM�[�Ԝr�s	����� �8�<Yt��+�����������uPZ��T�
+42���"����-�ܭ�
���*���{���pm�n�Ln��P���}����8��7f��u��Zn
~���/��:���ˮ5����pV]�v �S�<&\�@�=�����R�Vn���u^�{c��A�9��<�2A������ z�D\ж��͞qŒ
�z[I��Pĵ������1N^٘��i�nH݋1\t��i�j���bh�+ӓe�m|d���L
�l s��,a��}�'��XV�f������8�
+V�G��#�
3\RX�b���q�7qsvs�wN�K*L�e6�Qk���5("�����Ya�֕W��[�u	���	��;�'=b�[��햑*��5�
+TP�f�27YH�E�rS���
+�~L"�S�p�F����璝m�����s{W�q���N\��L̬�$�$��gu�'"L@jB�׿�͌H,Hލ�G�p���nңͭ���\�8�G���G�\�ࣦ�'?s(=;�N����eƐ̭���p�s����?~�g߅�w�N���p�w����#�����s��^}��=P,����!�-���K'v,�Iطg�������_����28��-��/��I����a�As��+ ٭LE�׉N-Wͧ��3Ƞ�
+�u�����\��+�5d�'����K�ml�m�M84�z�c��uѿfL�̘g�f���.��W�ⱩM
+endstream
+endobj
+77 0 obj
+5531
+endobj
+22 0 obj
+<</Subtype/Type1/BaseFont/KORKOY+LucidaSansUnicode20/Type/Font/Name/R22/FontDescriptor 21 0 R/FirstChar 0/LastChar 170/Widths[
+500 1000 500 1000 333 250 167 633 316 125 56 0 0 0 0 0
+325 325 633 500 1000 1000 578 500 316 316 316 316 373 373 373 373
+633 633 561 356 333 667 1000 325 0 0 0 0 0 0 0 0
+1012 1355 325 542 759 325 542 759 353 331 331 723 518 422 500 316
+590 465 916 325 0 602 316 316 316 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+422 422 422 422 422 422 422 422 422 422 422 422 422 226 226 383
+422 422 422 422 422 422 422 422 422 422 422 422 422 226 226 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+696 706 687 633 633 934 817 1319 1014 1046 1060]
+>>
+endobj
+42 0 obj
+<</Subtype/Type1/BaseFont/MYPKOY+Palatino-Italic/Type/Font/Name/R42/FontDescriptor 12 0 R/FirstChar 32/LastChar 255/Widths[
+250 333 500 500 500 889 778 278 333 333 389 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 500
+747 722 611 667 778 611 556 722 778 333 333 667 556 944 778 778
+611 778 667 556 611 778 722 944 722 667 667 333 606 333 606 500
+278 444 463 407 500 389 278 500 500 278 278 444 278 778 556 444
+500 463 389 389 333 556 500 722 500 500 444 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+278 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 333 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 556 500 250 333 300 333 500 750 750 750 500
+722 722 722 722 722 722 941 667 611 611 611 611 333 333 333 333
+778 778 778 778 778 778 778 606 778 778 778 778 778 667 611 500
+444 444 444 444 444 444 638 407 389 389 389 389 278 278 278 278
+444 556 444 444 444 444 444 606 444 556 556 556 556 500 500 500]
+>>
+endobj
+25 0 obj
+<</Type/FontDescriptor/FontName/Times-Roman>>
+endobj
+59 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R59/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+>>
+endobj
+63 0 obj
+<</Subtype/Type1/BaseFont/Courier/Type/Font/Name/R63>>
+endobj
+36 0 obj
+<</Subtype/Type1/BaseFont/Times-Roman/Type/Font/Name/R36/FirstChar 32/LastChar 251/Widths[
+250 333 408 500 500 833 778 333 333 333 500 564 250 333 250 278
+500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444
+921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722
+556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500
+333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500
+500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+250 333 500 500 167 500 500 500 500 180 444 500 333 333 556 556
+250 650 500 500 250 250 453 350 333 444 444 500 1000 1000 250 444
+250 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+1000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+250 889 250 276 250 250 250 250 611 722 889 310 250 250 250 250
+250 667 250 250 250 278 250 250 278 500 722 500]
+>>
+endobj
+26 0 obj
+<</Subtype/Type1/BaseFont/Times-Roman/Type/Font/Name/R26/FirstChar 32/LastChar 251/Widths[
+250 333 408 500 500 833 778 333 333 333 500 564 250 333 250 278
+500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444
+921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722
+556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500
+333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500
+500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+250 333 500 500 167 500 500 500 500 180 444 500 333 333 556 556
+250 650 500 500 250 250 453 350 333 444 444 500 1000 1000 250 444
+250 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+1000 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+250 889 250 276 250 250 250 250 611 722 889 310 250 250 250 250
+250 667 250 250 250 278 250 250 278 500 722 500]
+>>
+endobj
+23 0 obj
+<</Type/FontDescriptor/FontName/Courier>>
+endobj
+24 0 obj
+<</Subtype/Type1/BaseFont/Courier/Type/Font/Name/R24/Encoding 78 0 R>>
+endobj
+78 0 obj
+<</Type/Encoding/Differences[
+173/hyphen]>>
+endobj
+64 0 obj
+<</Subtype/Type1/BaseFont/YCYKOY+Palatino-Bold/Type/Font/Name/R64/FontDescriptor 9 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 402 500 500 889 833 278 333 333 444 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833 833
+611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606 500
+278 500 611 444 611 500 389 556 611 333 333 611 333 889 611 556
+611 611 389 444 333 611 556 833 500 556 500 310 606 310 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+333 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 278 500 500 500 500 606 500 333 747 438 500 606 333 747 333
+400 606 300 300 333 611 641 250 333 300 488 500 750 750 750 444
+778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389 389
+833 833 833 833 833 833 833 606 833 778 778 778 778 667 611 611
+500 500 500 500 500 500 778 444 500 500 500 500 333 333 333 333
+556 611 556 556 556 556 556 606 556 611 611 611 611 556 611 556]
+>>
+endobj
+44 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R44/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+>>
+endobj
+48 0 obj
+<</Subtype/Type1/BaseFont/MYPKOY+Palatino-Italic/Type/Font/Name/R48/FontDescriptor 12 0 R/FirstChar 32/LastChar 255/Widths[
+250 333 500 500 500 889 778 278 333 333 389 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 500
+747 722 611 667 778 611 556 722 778 333 333 667 556 944 778 778
+611 778 667 556 611 778 722 944 722 667 667 333 606 333 606 500
+278 444 463 407 500 389 278 500 500 278 278 444 278 778 556 444
+500 463 389 389 333 556 500 722 500 500 444 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+278 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 333 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 556 500 250 333 300 333 500 750 750 750 500
+722 722 722 722 722 722 941 667 611 611 611 611 333 333 333 333
+778 778 778 778 778 778 778 606 778 778 778 778 778 667 611 500
+444 444 444 444 444 444 638 407 389 389 389 389 278 278 278 278
+444 556 444 444 444 444 444 606 444 556 556 556 556 500 500 500]
+>>
+endobj
+49 0 obj
+<</Subtype/Type1/BaseFont/YCYKOY+Palatino-Bold/Type/Font/Name/R49/FontDescriptor 9 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 402 500 500 889 833 278 333 333 444 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833 833
+611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606 500
+278 500 611 444 611 500 389 556 611 333 333 611 333 889 611 556
+611 611 389 444 333 611 556 833 500 556 500 310 606 310 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+333 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 278 500 500 500 500 606 500 333 747 438 500 606 333 747 333
+400 606 300 300 333 611 641 250 333 300 488 500 750 750 750 444
+778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389 389
+833 833 833 833 833 833 833 606 833 778 778 778 778 667 611 611
+500 500 500 500 500 500 778 444 500 500 500 500 333 333 333 333
+556 611 556 556 556 556 556 606 556 611 611 611 611 556 611 556]
+>>
+endobj
+50 0 obj
+<</Subtype/Type1/BaseFont/Courier/Type/Font/Name/R50/Encoding 79 0 R>>
+endobj
+79 0 obj
+<</Type/Encoding/Differences[
+173/hyphen]>>
+endobj
+29 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R29/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+>>
+endobj
+10 0 obj
+<</Subtype/Type1/BaseFont/YCYKOY+Palatino-Bold/Type/Font/Name/R10/FontDescriptor 9 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 402 500 500 889 833 278 333 333 444 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833 833
+611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606 500
+278 500 611 444 611 500 389 556 611 333 333 611 333 889 611 556
+611 611 389 444 333 611 556 833 500 556 500 310 606 310 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+333 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 278 500 500 500 500 606 500 333 747 438 500 606 333 747 333
+400 606 300 300 333 611 641 250 333 300 488 500 750 750 750 444
+778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389 389
+833 833 833 833 833 833 833 606 833 778 778 778 778 667 611 611
+500 500 500 500 500 500 778 444 500 500 500 500 333 333 333 333
+556 611 556 556 556 556 556 606 556 611 611 611 611 556 611 556]
+/Encoding 80 0 R>>
+endobj
+80 0 obj
+<</Type/Encoding/Differences[
+173/hyphen]>>
+endobj
+66 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R66/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+>>
+endobj
+33 0 obj
+<</Subtype/Type1/BaseFont/Courier/Type/Font/Name/R33>>
+endobj
+70 0 obj
+<</Subtype/Type1/BaseFont/Courier/Type/Font/Name/R70>>
+endobj
+34 0 obj
+<</Subtype/Type1/BaseFont/MYPKOY+Palatino-Italic/Type/Font/Name/R34/FontDescriptor 12 0 R/FirstChar 32/LastChar 255/Widths[
+250 333 500 500 500 889 778 278 333 333 389 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 500
+747 722 611 667 778 611 556 722 778 333 333 667 556 944 778 778
+611 778 667 556 611 778 722 944 722 667 667 333 606 333 606 500
+278 444 463 407 500 389 278 500 500 278 278 444 278 778 556 444
+500 463 389 389 333 556 500 722 500 500 444 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+278 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 333 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 556 500 250 333 300 333 500 750 750 750 500
+722 722 722 722 722 722 941 667 611 611 611 611 333 333 333 333
+778 778 778 778 778 778 778 606 778 778 778 778 778 667 611 500
+444 444 444 444 444 444 638 407 389 389 389 389 278 278 278 278
+444 556 444 444 444 444 444 606 444 556 556 556 556 500 500 500]
+/Encoding 81 0 R>>
+endobj
+81 0 obj
+<</Type/Encoding/Differences[
+148/tilde]>>
+endobj
+71 0 obj
+<</Subtype/Type1/BaseFont/YCYKOY+Palatino-Bold/Type/Font/Name/R71/FontDescriptor 9 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 402 500 500 889 833 278 333 333 444 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833 833
+611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606 500
+278 500 611 444 611 500 389 556 611 333 333 611 333 889 611 556
+611 611 389 444 333 611 556 833 500 556 500 310 606 310 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+333 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 278 500 500 500 500 606 500 333 747 438 500 606 333 747 333
+400 606 300 300 333 611 641 250 333 300 488 500 750 750 750 444
+778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389 389
+833 833 833 833 833 833 833 606 833 778 778 778 778 667 611 611
+500 500 500 500 500 500 778 444 500 500 500 500 333 333 333 333
+556 611 556 556 556 556 556 606 556 611 611 611 611 556 611 556]
+>>
+endobj
+35 0 obj
+<</Subtype/Type1/BaseFont/YCYKOY+Palatino-Bold/Type/Font/Name/R35/FontDescriptor 9 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 402 500 500 889 833 278 333 333 444 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833 833
+611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606 500
+278 500 611 444 611 500 389 556 611 333 333 611 333 889 611 556
+611 611 389 444 333 611 556 833 500 556 500 310 606 310 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+333 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 278 500 500 500 500 606 500 333 747 438 500 606 333 747 333
+400 606 300 300 333 611 641 250 333 300 488 500 750 750 750 444
+778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389 389
+833 833 833 833 833 833 833 606 833 778 778 778 778 667 611 611
+500 500 500 500 500 500 778 444 500 500 500 500 333 333 333 333
+556 611 556 556 556 556 556 606 556 611 611 611 611 556 611 556]
+>>
+endobj
+13 0 obj
+<</Subtype/Type1/BaseFont/MYPKOY+Palatino-Italic/Type/Font/Name/R13/FontDescriptor 12 0 R/FirstChar 32/LastChar 255/Widths[
+250 333 500 500 500 889 778 278 333 333 389 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 500
+747 722 611 667 778 611 556 722 778 333 333 667 556 944 778 778
+611 778 667 556 611 778 722 944 722 667 667 333 606 333 606 500
+278 444 463 407 500 389 278 500 500 278 278 444 278 778 556 444
+500 463 389 389 333 556 500 722 500 500 444 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+278 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 333 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 556 500 250 333 300 333 500 750 750 750 500
+722 722 722 722 722 722 941 667 611 611 611 611 333 333 333 333
+778 778 778 778 778 778 778 606 778 778 778 778 778 667 611 500
+444 444 444 444 444 444 638 407 389 389 389 389 278 278 278 278
+444 556 444 444 444 444 444 606 444 556 556 556 556 500 500 500]
+>>
+endobj
+52 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R52/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+>>
+endobj
+56 0 obj
+<</Subtype/Type1/BaseFont/Courier/Type/Font/Name/R56>>
+endobj
+57 0 obj
+<</Subtype/Type1/BaseFont/YCYKOY+Palatino-Bold/Type/Font/Name/R57/FontDescriptor 9 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 402 500 500 889 833 278 333 333 444 606 250 606 250 296
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 667 722 833 611 556 833 833 389 389 778 611 1000 833 833
+611 833 722 611 667 778 778 1000 667 667 667 333 606 333 606 500
+278 500 611 444 611 500 389 556 611 333 333 611 333 889 611 556
+611 611 389 444 333 611 556 833 500 556 500 310 606 310 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+333 333 333 333 333 333 333 333 333 250 333 333 250 333 333 333
+250 278 500 500 500 500 606 500 333 747 438 500 606 333 747 333
+400 606 300 300 333 611 641 250 333 300 488 500 750 750 750 444
+778 778 778 778 778 778 1000 722 611 611 611 611 389 389 389 389
+833 833 833 833 833 833 833 606 833 778 778 778 778 667 611 611
+500 500 500 500 500 500 778 444 500 500 500 500 333 333 333 333
+556 611 556 556 556 556 556 606 556 611 611 611 611 556 611 556]
+>>
+endobj
+16 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R16/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+/Encoding 82 0 R>>
+endobj
+82 0 obj
+<</Type/Encoding/Differences[
+173/hyphen]>>
+endobj
+38 0 obj
+<</Subtype/Type1/BaseFont/GPQJOY+Palatino-Roman/Type/Font/Name/R38/FontDescriptor 15 0 R/FirstChar 32/LastChar 255/Widths[
+250 278 371 500 500 840 778 278 333 333 389 606 250 606 250 606
+500 500 500 500 500 500 500 500 500 500 250 250 606 606 606 444
+747 778 611 709 774 611 556 763 832 337 333 726 611 946 831 786
+604 786 668 525 613 778 722 1000 667 667 667 333 606 333 606 500
+278 500 553 444 611 479 333 556 582 291 234 556 291 883 582 546
+601 560 395 424 326 603 565 834 516 556 500 333 606 333 606 250
+250 250 250 250 250 250 250 250 250 250 250 250 250 250 250 250
+287 333 333 333 333 333 333 250 333 250 333 333 250 380 313 333
+250 278 500 500 500 500 606 500 333 747 333 500 606 333 747 333
+400 606 300 300 333 603 628 250 333 300 333 500 750 750 750 444
+778 778 778 778 778 778 944 709 611 611 611 611 337 337 337 337
+774 831 786 786 786 786 786 606 833 778 778 778 778 667 604 556
+500 500 500 500 500 500 758 444 479 479 479 479 287 287 287 287
+546 582 546 546 546 546 546 606 556 603 603 603 603 556 601 556]
+>>
+endobj
+19 0 obj
+<</Subtype/Type1/BaseFont/KERJOY+LucidaSansUnicode21/Type/Font/Name/R19/FontDescriptor 18 0 R/FirstChar 0/LastChar 234/Widths[
+750 750 738 922 648 750 750 630 602 780 773 1121 643 880 704 704
+675 704 787 590 979 819 967 855 725 705 904 938 909 782 633 633
+807 1481 807 654 645 512 876 876 582 401 653 690 799 678 853 488
+572 828 664 1043 574 676 666 463 607 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+316 316 316 316 316 316 316 316 316 316 316 316 316 316 316 316
+940 530 940 530 1205 530 745 745 745 745 940 940 795 795 940 530
+940 530 940 940 940 530 940 530 530 940 940 940 940 1217 1205 660
+687 687 687 687 687 940 983 983 940 940 940 940 940 940 434 434
+940 940 434 434 940 771 940 940 771 940 771 940 940 940 1205 940
+940 771 940 771 1205 772 813 813 813 813 940 940 1205 1205 530 530
+940 530 940 530 940 940 940 772 940 772 772]
+>>
+endobj
+2 0 obj
+<</Producer(AFPL Ghostscript 7.04)>>endobj
+xref
+0 83
+0000000000 65535 f 
+0000020002 00000 n 
+0000064668 00000 n 
+0000019901 00000 n 
+0000020050 00000 n 
+0000018877 00000 n 
+0000000015 00000 n 
+0000003289 00000 n 
+0000036528 00000 n 
+0000036159 00000 n 
+0000052731 00000 n 
+0000031021 00000 n 
+0000030657 00000 n 
+0000058224 00000 n 
+0000022457 00000 n 
+0000021903 00000 n 
+0000061415 00000 n 
+0000021502 00000 n 
+0000021270 00000 n 
+0000063571 00000 n 
+0000020861 00000 n 
+0000020623 00000 n 
+0000042165 00000 n 
+0000047179 00000 n 
+0000047237 00000 n 
+0000044018 00000 n 
+0000046185 00000 n 
+0000020105 00000 n 
+0000020135 00000 n 
+0000051691 00000 n 
+0000019037 00000 n 
+0000003309 00000 n 
+0000006559 00000 n 
+0000054887 00000 n 
+0000055029 00000 n 
+0000057184 00000 n 
+0000045191 00000 n 
+0000020233 00000 n 
+0000062531 00000 n 
+0000019181 00000 n 
+0000006580 00000 n 
+0000009654 00000 n 
+0000042978 00000 n 
+0000020320 00000 n 
+0000048424 00000 n 
+0000019325 00000 n 
+0000009675 00000 n 
+0000012902 00000 n 
+0000049464 00000 n 
+0000050504 00000 n 
+0000051544 00000 n 
+0000020363 00000 n 
+0000059264 00000 n 
+0000019469 00000 n 
+0000012923 00000 n 
+0000014937 00000 n 
+0000060304 00000 n 
+0000060375 00000 n 
+0000020439 00000 n 
+0000044080 00000 n 
+0000019613 00000 n 
+0000014958 00000 n 
+0000017308 00000 n 
+0000045120 00000 n 
+0000047384 00000 n 
+0000020504 00000 n 
+0000053847 00000 n 
+0000019757 00000 n 
+0000017329 00000 n 
+0000018856 00000 n 
+0000054958 00000 n 
+0000056144 00000 n 
+0000020569 00000 n 
+0000021250 00000 n 
+0000021883 00000 n 
+0000030636 00000 n 
+0000036138 00000 n 
+0000042144 00000 n 
+0000047324 00000 n 
+0000051631 00000 n 
+0000053787 00000 n 
+0000056085 00000 n 
+0000062471 00000 n 
+trailer
+<< /Size 83 /Root 1 0 R /Info 2 0 R
+>>
+startxref
+64719
+%%EOF
--- /dev/null
+++ b/doc/limbo/addendum.ms
@@ -1,0 +1,495 @@
+.TL
+Addendum to
+.I "The Limbo Programming Language"
+.AU
+Vita Nuova
+.br
+30 March 2005
+.NH 1
+Introduction
+.LP
+This addendum provides a brief summary of several language changes to
+Limbo since
+.I "The Limbo Programming Language"
+was last revised:
+.RS
+.IP •
+buffered channels
+.IP •
+unrestricted \f5alt\f1
+.IP •
+function references
+.IP •
+exceptions
+.IP •
+exponentiation
+.IP •
+fixed-point types
+.RE
+.NH 1
+Buffered channels
+.LP
+A buffered channel can now be declared:
+.P1
+c := chan[1] of int;
+.P2
+Here the buffer size is 1. A send on this channel will succeed immediately
+if there is a receiver waiting or if the buffer is empty. A receive on this
+channel will succeed immediately if there is a data item in the buffer. This allows us to
+write a very simple locking mechanism:
+.P1
+acquire(c: chan of int)
+{
+	c <-= 0;
+}
+
+release(c: chan of int)
+{
+	<-c;
+}
+
+new(): chan of int
+{
+	return chan[1] of int;
+}
+.P2
+The declaration
+.P1
+c := chan[0] of int;
+.P2
+is equivalent to 
+.P1
+	c := chan of int;
+.P2
+An attempt to create a channel with a negative buffer size will raise
+an exception. An attempt to create a channel with a very large buffer
+may result in an immediate memory exception if there is not enough
+room for the buffer.
+.NH 1
+Unrestricted
+.B alt
+.LP
+The implementation has changed to remove the restriction that only one process can be
+waiting in an
+.CW alt
+to send or receive on a particular channel.
+The busy exception never occurs now. Thus you can do
+.P1
+i()
+{
+	c := chan of int;
+	c1 := chan of int;
+	spawn p(c, c1);
+	<-c;
+	spawn p(c, c1);
+	<-c;
+	for(i := 0; i < 20; i++)
+		c1 <-= i;
+}
+
+p(c: chan of int, c1: chan of int)
+{
+	c <-= 0;
+	for(;;)
+		alt{
+			i := <-c1 =>
+				;
+		}
+}
+.P2
+The two spawned processes can both wait on
+.CW c1
+without fuss.
+Processes are queued on a strict FIFO basis so, in
+the example above, the two processes receive on
+.CW c1
+alternately.
+.NH 1
+Function references
+.LP
+Function references may be declared as follows:
+.P1
+fp: ref fn(s1: string, s2: string): int;
+.P2
+Given the function
+.P1
+cmp(s1: string, s2: string): int
+{
+	if(s1 < s2)
+		return -1;
+	if(s1 > s2)
+		return 1;
+	return 0;
+}
+.P2
+a reference to it can be created by assignment:
+.P1
+fp = cmp;
+.P2
+where the name can be qualified by an explicit module reference as usual:
+.P1
+fp = mod->cmp;
+.P2
+or it can be returned from a function:
+.P1
+Cmp: type ref fn(s1: string, s2: string): int;
+
+rcmp(s1: string, s2: string): int
+{
+	return -cmp(s1, s2);
+}
+
+choose(i: int): Cmp
+{
+	if(i)
+		return rcmp;
+	return cmp;
+}
+.P2
+(the declaration of the synonym
+.CW Cmp
+was done only for clarity).
+They may be declared and passed as parameters:
+.P1
+sort(a: array of string, f: ref fn(s1, s2: string): int): array of string
+{
+	# ...
+}
+	# ...
+b := sort(a, cmp);
+c := sort(a, rcmp);
+.P2
+The function is called via the reference by
+.P1
+	r := fp("fred", "bloggs");
+.P2
+Otherwise function references behave just like any other reference type.
+.NH 1
+Exceptions
+.LP
+Both string exceptions and user defined exceptions are now provided.
+The
+.CW Sys
+module interface to exceptions
+has been removed and replaced by new language constructs in limbo.
+.NH 2
+String exceptions
+.LP
+Simple string exceptions can be raised as follows
+.P1
+raise \fIs\fP;
+.P2
+where
+.I s
+is any value of type string (it need not be constant).
+.LP
+Exception handlers may be attached to a block (or sequence of statements) :-
+.P1
+{
+	foo();
+	bar();
+} exception e {
+"a" or "b" =>
+	sys->print("caught %s\en", e);
+	raise;
+"ab*" =>
+	sys->print("caught %s\en", e);
+	exit;
+"abcd*" =>
+	sys->print("caught %s\en", e);
+	raise e;
+"a*" =>
+	sys->print("caught %s\en", e);
+	raise "c";
+"*" =>
+	sys->print("caught %s\en", e);
+}
+LL:
+.P2
+.LP
+Any exception occurring within the block (and in nested function calls within the block) can
+potentially be caught by the exception handler. An exception is caught by a guard exactly
+maching the exception string or by a guard
+\f5\&"\fP\fIs\fP\f5*"\fP
+where
+.I s
+is a prefix of the exception string.
+The most specific match is used. Thus a raise of "a" will be caught by the first
+guard and not by the fourth guard. A raise of "abcde" is caught by the third and not the second
+or fourth. If a match is found, the sequence of statements following the guard are executed.
+If not, the system searches for a handler at a higher level.
+.LP
+As shown above, the exception is available through the exception identifier (e in this case) if given following the exception keyword.
+.LP
+The exception is reraised using
+.P1
+raise;
+.P2
+or
+.P1
+raise e;
+.P2
+.LP
+Both the block and the exception code will fall through to the statement labelled
+LL unless, of course, they do an explicit exit, return or raise first.
+.NH 2
+User-defined exceptions
+.LP
+You can declare your own exceptions:
+.P1
+implement Fibonacci;
+
+include "sys.m";
+include "draw.m";
+
+Fibonacci: module
+{
+	init: fn(nil: ref Draw->Context, argv: list of string);
+};
+.P3
+
+init(nil: ref Draw->Context, nil: list of string)
+{
+	sys := load Sys Sys->PATH;
+	for(i := 0; ; i++){
+		f := fibonacci(i);
+		if(f < 0)
+			break;
+		sys->print("F(%d) = %d\en", i, f);
+	}
+}
+.P3
+
+FIB: exception(int, int);
+.P3
+
+fibonacci(n: int): int
+{
+	{
+		fib(1, n, 1, 1);
+	}exception e{
+	FIB =>
+		(x, nil) := e;
+		return x;
+	"*" =>
+		sys->print("unexpected string exception %s raised\en", e);
+	* =>
+		sys->print("unexpected exception raised\en");
+	}
+	return 0;
+}
+.P3
+
+fib(n: int, m: int, x: int, y: int) raises (FIB)
+{
+	if(n >= m)
+		raise FIB(x, y);
+
+	{
+		fib(n+1, m, x, y);
+	}exception e{
+	FIB =>
+		(x, y) = e;
+		x = x+y;
+		y = x-y;
+		raise FIB(x, y);
+	}
+}
+.P2
+.LP
+.CW FIB
+is a declared exception that returns two integers. The values are supplied when raising the exception:
+.P1
+raise FIB(3, 4);
+.P2
+When caught the values can be recovered by treating the declared exception identifier
+as if it were a tuple of 2 integers:
+.P1
+(x, y) = e;
+.P2
+In general each exception alternative treats the exception identifier appropriately : as a string
+when the exception qualifier is a string, as the relevant tuple when the exception is declared.
+.LP
+If you do
+.P1
+"abcde" or FIB =>
+	(x, y) = e;
+	sys->print("%s\en", e);
+.P2
+you will get a compiler error as
+.CW e 's
+type is indeterminate within this alternative.
+.LP
+Reraising is the same as in the case of string exceptions.
+.LP
+Note also the difference between the string guard
+\&\f5"*"\fP and the guard
+.CW *
+in
+the function fibonacci.
+The former will match any string exception, the latter any exception. If a
+string exception does occur it matches the former as it is the most specific.
+If an unexpected user defined
+exception occurs it matches the latter.
+.LP
+The main difference between declared exceptions and string exceptions is
+that the former must be caught by the immediate caller of a function that
+raises them, otherwise they turn into a string exception whose name is derived
+from that of the exception declaration.
+.NH 2
+The
+.CW raises
+clause
+.LP
+The definition of the function fib in the above example also lists the user defined exceptions it can raise via the use of a
+.CW raises
+clause. In this case there is just the one exception (\f5FIB\f1). These
+clauses (if given) must be compatible between any declaration and definition of the function.
+.LP
+The compiler reports instances of functions which either raise some exception which
+is not mentioned in their raises clause or does not raise some exception which is
+mentioned in their raises clause. Currently the report is a warning.
+.NH 1
+Exponentiation
+.LP
+The exponentiation operator (written as
+.CW ** )
+is now part of the Limbo language.
+Its precedence is above that of multiplication, division and modulus but below
+that of the unary operators. It is right associative. Thus
+.P1
+3**4*2 = (3**4)*2 = 81*2 = 162
+-3**4 = (-3)**4 = 81
+2**3**2 = 2**(3**2) = 2**9 = 512
+.P2
+The type of the left operand must be
+.CW int ,
+.CW big
+or
+.CW real .
+The type of the right operand must be
+.CW int .
+The type of the result is the type of the left operand.
+.NH 1
+Fixed point types
+.LP
+A declaration of the form
+.P1
+x: fixed(0.2, 12345.0);
+.P2
+declares
+.CW x
+to be a variable of a fixed point type. The scale of the type is
+1/5 and the maximum absolute value of the type is 12345.0.
+.LP
+Similarly
+.P1
+x: fixed(0.125, 4096.0)
+.P2
+specifies a scale of 0.125 and a maximum absolute value of 4096.
+This requires only 17 bits so the underlying type will be
+.CW int
+and the compiler
+is free to allocate the remaining 15 bits to greater range or greater
+accuracy. In fact the compiler always chooses the latter.
+.LP
+The maximum absolute value is optional :-
+.P1
+x: fixed(0.125);
+.P2
+is equivalent to
+.P1
+x: fixed(0.125, 2147483647.0 * 0.125);
+.P2
+and ensures the underlying type is exactly an int ie the compiler has
+no scope to add any extra bits for more accuracy.
+.LP
+A binary fixed point type with 8 bits before the binary point and 24 after
+might therefore be declared as
+.P1
+x: fixed(2.0**-24);
+.P2
+.LP
+The scale must be static: its value known at compile time and
+it must be positive and real; similarly for the maximum absolute
+value when specified.
+.LP
+Currently the only underlying base type supported is
+.CW int .
+.LP
+A shorthand for fixed point types is available through the use of
+.CW type
+declarations:
+.P1
+fpt: type fixed(2.0**-16);
+.P2
+We can then do
+.P1
+x, y, z: fpt;
+zero: con fpt(0);
+
+x = fpt(3.21);
+y = fpt(4.678);
+z = fpt(16r1234.5678);
+z = -x;
+z = x+y;
+z = x-y;
+z = x*y;
+z = x/y;
+sys->print("z=%f", real z);
+.P2
+There is no implicit numerical casting in Limbo so we have to use explicit
+casts to initialize fixed point variables. Note the use of a base to
+initialize
+.CW z
+using a new literal representation.
+.LP
+Given
+.P1
+fpt1: type fixed(0.12345);
+x: fpt1;
+fpt2: type fixed(0.1234);
+y: fpt2;
+fpt3: type fixed(0.123);
+z: fpt3;
+.P2
+then
+.P1
+z = x*y;
+.P2
+is illegal. We must add casts and do
+.P1
+z = fpt3(x)*fpt3(y);
+.P2
+ie type equivalence between fixed point types requires equivalence of scale
+(and of maximum absolute value when specified).
+.LP
+Fixed point types may be used where any other numerical type (byte, int, big, real) can be used. So you can compare them, have a list of them, have a channel of them, cast them to or from string and so on.
+.LP
+You cannot use complement(~), not(!), and(&), or(|), xor(^) or modulus(%) on them as fixed point types are basically a form of real type.
+.NH 2
+Accuracy
+.LP
+A fixed point value is a multiple of its scale. Given fixed point values X, Y and
+Z of scale s, t and u respectively, we can write
+.P1
+X = sx
+Y = ty
+Z = uz
+.P2
+where x, y and z are integers.
+.LP
+For the multiplication Z = X*Y the accuracy achieved is given by
+.P1
+| z - (st/u)xy | < 1
+.P2
+and for the division Z = X/Y
+.P1
+| z - (s/(tu))x/y | < 1
+.P2
+That is, the result is always within the result scale of the correct real value.
+.LP
+This also applies when casting a fixed point type to another, casting an
+integer to a fixed point type and casting a fixed point type to an integer. These
+are all examples of the multiplication law with t = y = 1 since an
+integer may be thought of as a fixed point type with a scale of 1.
binary files /dev/null b/doc/limbo/addendum.pdf differ
--- /dev/null
+++ b/doc/limbo/limbo.ms
@@ -1,0 +1,5046 @@
+...FP lucidasans
+...FP palatino
+.FP palatino
+." .fp 6 RR R
+.nr PI 2n
+.de P1
+.DS L
+.ft CW
+.ps -1
+.vs -1u
+.ta .75i 1.5i 2.25i 3i 3.75i 4.5i 5.25i 6i 6.75i 7.5i
+..
+.de P2
+.ft R
+.ps +1
+.vs +1u
+.DE
+..
+.de s1
+.DS
+.br
+.ft I
+..
+.de s2
+.br
+.DE
+.ft R
+..
+...ds CF "Copyright 2000 Lucent Technologies Inc. Modifications Vita Nuova Limited.
+.TL
+The Limbo Programming Language
+.AU
+Dennis M. Ritchie
+.br
+(Revised 2005 by Vita Nuova)
+.SP .5i exactly
+.PP
+Limbo is a programming language intended for applications
+running distributed systems on small computers.
+It supports modular programming,
+strong type checking at compile- and run-time,
+interprocess communication over typed channels,
+automatic garbage collection,
+and simple abstract data types.
+It is designed for safe execution even on
+small machines without hardware memory protection.
+.PP
+In its implementation for the Inferno operating system,
+object programs generated by the Limbo compiler run
+using an interpreter for a fixed virtual machine.
+Inferno and its accompanying virtual machine run either stand-alone
+on bare hardware
+or as an application under conventional operating systems like
+Unix, Windows 2000, Linux, FreeBSD, MacOSX, and Plan 9.
+For most architectures, including
+Intel x86, ARM, PowerPC, MIPS and Sparc, Limbo object programs
+are transformed on-the-fly into instructions for the underlying hardware.
+.NH 1
+Overview and introduction
+.PP
+A Limbo application consists of one or more
+.I modules ,
+each of which supplies an interface declaration and
+an implementation part.
+A module that uses another module
+includes its declaration part.
+During
+execution, a module dynamically attaches another module by
+stating the other module's type identifier and a place from which to load
+the object code for its implementation.
+.PP
+A module declaration specifies the functions and data it will make visible,
+its data types, and constants.
+Its implementation part defines the functions and data visible at its interface and
+any functions associated with its data types;
+it may also contain definitions for functions used only internally and
+for data local to the module.
+.PP
+Here is a simple module to illustrate the flavour of the language.
+.P1
+1	implement Command;
+
+2	include "sys.m";
+3	include "draw.m";
+
+4	sys:	Sys;
+
+5	Command: module
+	{
+6	    init: fn (ctxt: ref Draw->Context, argv: list of string);
+7	};
+.P2
+.P1
+8	# The canonical "Hello world" program, enhanced
+9	init(ctxt: ref Draw->Context, argv: list of string)
+10	{
+11		sys = load Sys Sys->PATH;
+12		sys->print("hello world\en");
+13		for (; argv!=nil; argv = tl argv)
+14			sys->print("%s ", hd argv);
+15		sys->print("\en");
+16	}
+.P2
+A quick glance at the program reveals that
+the syntax of Limbo is influenced by C in its expressions,
+statements, and some conventions (for example, look at lines 13-14),
+and also by Pascal and its successors (the declarations on lines 4, 6, 9).
+When executed in the Inferno environment, the program writes
+.CW hello
+.CW world
+somewhere, then echoes its arguments.
+.PP
+Let's look at the program line-by-line.
+It begins (line 1) by saying that this is the implementation of module
+.CW Command .
+Line 2 includes a file (found in a way analogous to C's
+.CW #include
+mechanism) named
+.CW sys.m .
+This file defines the interface to module
+.CW Sys ;
+.ds CF
+it says, in part,
+.P1
+Sys: module {
+	PATH: con "$Sys";
+	. . .
+	print: fn (s: string, *): int;
+	. . .
+};
+.P2
+This declares
+.CW Sys
+to be the type name for a module containing among other things a
+function named
+.CW print ;
+the first argument of
+.CW print
+is a string.
+The
+.CW *
+in the argument list specifies that further arguments, of
+unspecified type, may be given.
+.PP
+Line 3 includes
+.CW draw.m ;
+only one piece of information, mentioned below,
+is used from it.
+Line 4 declares the variable
+.CW sys
+to be of type
+.CW Sys ;
+its name will be visible throughout the remainder of the file
+describing this module.
+It will be used later to refer to an instance of the
+.CW Sys
+module.
+This declaration initializes it to
+.CW nil ;
+it still needs to be set to a useful value.
+.PP
+Lines 5-7 constitute the declaration of
+.CW Command ,
+the module being implemented.
+It contains only a function named
+.CW init ,
+with two arguments, a
+.CW ref
+.CW Draw->Context
+and a list of strings,
+and it doesn't
+return any value.
+The
+.CW ref
+.CW Draw->Context
+argument would be used if the program did any
+graphics; it is a data type defined in
+.CW draw.m
+and refers to the display.
+Since the program just writes text, it won't be used.
+The
+.CW init
+function isn't special to the Limbo language,
+but it is conventional in the environment,
+like
+.CW main
+in C.
+.PP
+In a module designed to be useful
+to other modules in an application, it would be wise to
+take the module declaration for
+.CW Command
+out, put it in a separate file called
+.CW command.m
+and use
+.CW "include
+.CW command.m
+to allow this module and others to refer to it.
+It is called, for example, by the program loader in the Inferno
+system to start the execution of applications.
+.PP
+Line 8 is a comment; everything from the
+.CW #
+to the end of line is ignored.
+.PP
+Line 9 begins the definition for the
+.CW init
+function that was promised in the module's declaration
+(line 6).
+The argument that is a list of strings is named
+.CW argv .
+.PP
+Line 11 connects the program
+being written to the
+.CW Sys
+module.
+The first token after
+.CW load
+is the target module's name as defined by its interface
+(here found in the
+.CW include
+on line 2)
+The next token is the place
+where the code for the module can be found; it is a string
+that usually names a file.
+Conventionally, in the Inferno system,
+each module contains a constant declaration for the name
+.CW PATH
+as a string that names the file where
+the object module can be found.
+Loading the file is performed dynamically during
+execution except for a few modules built
+into the execution environment.
+(These include
+.CW Sys ;
+this accounts for the peculiar file name
+.CW "$Sys"
+as
+the value of
+.CW PATH .)
+.PP
+The value of
+.CW load
+is a reference to the
+named module; line 11 assigns it
+to the variable
+.CW sys
+for later use.
+The
+.CW load
+operator dynamically loads the code for the named
+module if it is not already present and instantiates
+a new instance of it.
+.PP
+Line 12 starts the work by printing a familiar message,
+using the facilities provided by module
+.CW Sys
+through its handle
+.CW sys ;
+the notation
+.CW sys->print(...)
+means to call the
+.CW print
+function of the module referred to by
+.CW sys .
+The interface of
+.CW Sys
+resembles a binding to some of
+the mechanisms of Unix and the ISO/ANSI C library.
+.PP
+The loop at lines 13-14 takes the
+.CW "list
+.CW of
+.CW string
+argument to
+.CW init
+and iterates over it using the
+.CW hd
+(head) and
+.CW tl
+(tail) operators.
+When executed, this module combines the
+traditional `Hello world' and
+.CW echo .
+.NH 1
+Lexical conventions
+.PP
+There are several kinds of tokens:
+keywords, identifiers, constants, strings, expression operators,
+and other separators.
+White space (blanks, tabs, new-lines) is ignored except that
+it serves to separate tokens; sometimes it is required
+to separate tokens.
+If the input has been parsed into tokens up to a particular
+character, the next token is taken to include the longest
+string of characters that could constitute a token.
+.PP
+The native character set of Limbo is Unicode,
+which is identical with the first 16-bit plane of the ISO 10646 standard.
+Any Unicode character may be used in comments, or in strings
+and character constants.
+The implementation assumes that source files use the UTF-8 representation,
+in which 16-bit Unicode characters are represented as sequences
+of one, two, or three bytes.
+.NH 2
+Comments
+.PP
+Comments begin with the
+.CW #
+character and extend to the end of the line.
+Comments are ignored.
+.NH 2
+Identifiers
+.PP
+An identifier is a sequence of letters and digits
+of which the first is a letter.
+Letters are the Unicode characters
+.CW a
+through
+.CW z
+and
+.CW A
+through
+.CW Z ,
+together with the underscore character, and
+all Unicode characters with encoded values greater than 160
+(A0 hexadecimal, the beginning of the range corresponding to Latin-1).
+.PP
+Only the first 256 characters in an identifier
+are significant.
+.NH 2
+Keywords
+.PP
+The following identifiers are reserved for use as keywords,
+and may not be used otherwise:
+.P1
+.ta 1i 2i 3i 4i 5i
+	adt	alt	array	big
+	break	byte	case	chan
+	con	continue	cyclic	do
+	else	exit	fn	for
+	hd	if	implement	import
+	include	int	len	list
+	load	module	nil	of
+	or	pick	real	ref
+	return	self	spawn	string
+	tagof	tl	to	type
+	while
+.P2
+The word
+.CW union
+is not currently used by the language.
+.NH 2
+Constants
+.PP
+There are several kinds of constants for denoting values of the
+basic types.
+.PP
+.NH 3
+Integer constants
+.PP
+Integer constants have type
+.CW int
+or
+.CW big .
+They can be represented in several ways.
+.PP
+Decimal integer constants consist of a sequence of decimal
+digits.
+A constant with an explicit radix
+consists of a decimal radix followed by
+.CW R
+or
+.CW r
+followed by the digits of the number.
+The radix is between 2 and 36 inclusive;
+digits above 10 in the number
+are expressed using letters
+.CW A
+to
+.CW Z
+or
+.CW a
+to
+.CW z .
+For example,
+.CW 16r20
+has value 32.
+.PP
+The type of a decimal or explicit-radix number is
+.CW big
+if its value exceeds
+.CW 2\u31\d\(mi1 ,
+otherwise it is
+.CW int .
+.PP
+Character constants consist of a single Unicode
+character enclosed within single-quote characters
+.CW ' .
+Inside the quotes the following escape sequences represent
+special characters:
+.DS
+\f(CW\e\e\fR		backslash
+\f(CW\e'\fR		single quote
+\f(CW\e"\fR		double quote
+\f(CW\ea\fR		bell (BEL)
+\f(CW\eb\fR		backspace (BS)
+\f(CW\et\fR		horizontal tabulation (HT)
+\f(CW\en\fR		line feed (LF)
+\f(CW\ev\fR		vertical tabulation (VT)
+\f(CW\ef\fR		form feed (FF)
+\f(CW\er\fR		carriage return (CR)
+\f(CW\eu\fIdddd	\fRUnicode character named by 4 hexadecimal digits
+\f(CW\e0\fR		NUL
+.DE
+Character constants have type
+.CW int .
+.NH 3
+Real constants
+.PP
+Real constants consist of a sequence of decimal digits
+containing one period
+.CW .
+and optionally followed by
+.CW e
+or
+.CW E
+and then by a possibly signed integer.
+If there is an explicit exponent, the period is
+not required.
+Real constants have type
+.CW real .
+.NH 3
+Strings
+.PP
+String constants are sequences of Unicode characters contained in double
+quotes.
+They cannot extend across source lines.
+The same escape sequences listed above for character
+constants are usable within string constants.
+.PP
+Raw (uninterpreted) string constants are sequences of Unicode characters
+contained in backquotes.
+They can extend across source lines and thus include newlines.
+They contain no character escapes.
+The only character that cannot appear inside an uninterpreted string is a backquote, because that delimits the string.
+.PP
+Both forms of string constant have type
+.CW string .
+.NH 3
+The nil constant
+.PP
+The constant
+.CW nil
+denotes a reference to nothing.
+It may be used where an object of a reference
+type is expected;
+otherwise uninitialized values of reference type
+start off with this value, it can be assigned to
+reference objects, and reference types can be
+tested for equality with it.
+(The keyword has other uses as well.)
+.NH 2
+Operators and other separators
+.PP
+The operators are
+.P1
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i 6.0i 6.5i
+	+	-	*	/	%	&	|	^
+	==	<	>	<=	>=	!=	<<	>>
+	&&	||	<-	::
+	=	+=	-=	*=	/=	%=	&=	|=	^=	<<=	>>=
+	:=
+	~	++	--	!	**
+.P2
+The other separators are
+.P1
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i
+	:	;	(	)	{	}	[	]
+	,	.	->	=>
+.P2
+.NH 1
+Syntax notation
+.PP
+In this manual, Limbo syntax is described by a modified BNF
+in which syntactic categories are named in an
+.I italic
+font, and literals in
+.CW typewriter
+font.
+Alternative productions are listed on separate lines, and
+an optional symbol is indicated with
+the subscript ``opt.''
+.NH 1
+Types and objects
+.PP
+Limbo has three kinds of objects.
+.I Data
+objects exist in the storage associated with
+a module; they can be manipulated by arithmetic operations,
+assignment, selection of component entities, and other concrete
+operations.
+Each data object has a type that determines what can be stored
+in it and what operations are applicable.
+.PP
+The second kind of object is the
+.I function .
+Functions are characterized by the types of the arguments they
+accept and the values they return, and are associated with
+the modules in which they are defined.
+Their names can be made visible in their module's declaration,
+or they can be encapsulated within the
+.CW adt
+(abstract data types) of their modules,
+or they can exist privately within their module.
+.PP
+Finally, Limbo programs are organized into
+.I modules :
+a named collection of constants, abstract data types,
+data, and functions made available by that module.
+A module declaration displays the
+members visible to other modules;
+the module's implementation
+defines both the publicly visible members and its
+private parts, including the data objects it uses.
+A module that wishes to use
+the facilities of another includes its declaration in order to
+understand what it exports, but
+before using them it explicitly loads the new module.
+.NH 2
+Types
+.PP
+Limbo has several basic types, some built-in higher abstractions,
+and other ways of composing new types.
+In declarations and some other places, constructions naming
+a type are used.
+The syntax is:
+.s1
+type:
+	data-type
+	function-type
+.s2
+Functions will be discussed in §7 below.
+First, data types will be explored.
+.NH 2
+Data types
+.PP
+The syntax of data types is
+.s1
+data-type:
+	CbyteI
+	CintI
+	CbigI
+	CrealI
+	CstringI
+	tuple-type
+	Carray of Idata-type
+	Clist of Idata-type
+	Cchan of Idata-type
+	adt-type
+	Cref Iadt-type
+	Cref Ifunction-type
+	module-type
+	module-qualified-type
+	type-name
+
+data-type-list:
+	data-type
+	data-type-list C,I data-type
+.s2
+Objects of most data types have
+.I value
+semantics; when they
+are assigned or passed to functions, the destination receives a copy of the
+object.
+Subsequent changes to the assigned object itself have no effect on
+the original object.
+The value types are
+.CW byte ,
+.CW int ,
+.CW big ,
+.CW real ,
+.CW string ,
+the
+.CW tuple
+types, and
+abstract data types or
+.CW adt .
+The rest have
+.I reference
+semantics.
+When they are assigned, the quantity actually assigned
+is a reference to (a pointer to) an underlying object
+that is not copied; thus changes or operations on
+the assigned value affect the original object.
+Reference types include lists, arrays, channels, modules,
+.CW ref
+.CW adt ,
+and
+.CW ref
+.CW fn
+types.
+.NH 3
+Basic types
+.PP
+The five basic data types are denoted by
+.CW byte ,
+.CW int ,
+.CW big ,
+.CW real ,
+and
+.CW string .
+.PP
+Bytes are unsigned 8-bit quantities.
+.PP
+Integers
+.CW int ) (
+are 32-bit signed quantities represented in two's complement
+notation.
+Large integers
+.CW big  ) (
+are 64-bit signed quantities represented in two's complement notation.
+.PP
+Real numbers
+.CW real ) (
+are 64-bit quantities represented in the
+IEEE long floating notation.
+.PP
+The
+.CW byte ,
+.CW int ,
+.CW big ,
+and
+.CW real
+types are collectively called arithmetic types.
+.PP
+Strings are rows of Unicode characters.
+They may be concatenated and extended character-by-character.
+When a string is indexed with a single subscript, it yields an integer
+with the Unicode encoding of the character;
+when it is indexed by a range, it yields another string.
+.NH 3
+Tuple type
+.PP
+The
+.I tuple
+type, denoted
+.s1
+tuple-type:
+	C( Idata-type-listC )I
+.s2
+is a type consisting of an ordered collection of two or more objects,
+each having its own data type.
+For each tuple type, the types of the members are
+fixed, but need not be identical;
+for example, a function might return a tuple containing
+an integer and a string.
+Each tuple type is characterized solely by the
+the order and identity of the types it contains.
+Objects of tuple type may be assigned to a list of identifiers (to pick out the
+components), and a parenthesized, comma-separated list of expressions
+denotes a tuple.
+.NH 3
+Array types
+.PP
+The
+.I array
+type describes a dynamically-sized row of objects, all of the same
+type; it is indexed starting from 0.
+An array type is denoted by
+.s1
+	Carray of Idata-type
+.s2
+The size of an array is not part of its type; instead
+it is part of the value.
+The
+.I data-type
+may itself be an array, to achieve a multidimensional array.
+.NH 3
+List types
+.PP
+A
+.I list
+is a sequence of like-typed objects; its denotation is
+.s1
+	Clist of Idata-type
+.s2
+A list is a stack-like object, optimized for
+a few operations: get the head (the first object),
+get the tail (the rest of the list), place an object at the beginning.
+.NH 3
+Channel types
+.PP
+A
+.I channel ,
+whose type is written
+.s1
+	Cchan of Idata-type
+.s2
+is a communication mechanism capable of sending and receiving objects of the
+specified type to another agent in the system.
+Channels may be used to communicate between local processes;
+using library procedures, they may be connected
+to named destinations.
+In either case
+.I send
+and
+.I receive
+operations may be directed to them.
+For example,
+.P1
+	chan of (int, string)
+.P2
+is the type of a channel that transmits tuples consisting of
+an integer and an string.
+Once an instance of such a channel (say
+.CW c )
+has been declared and initialized,
+the statement
+.P1
+	c <-= (123, "Hello");
+.P2
+sends such a tuple across it.
+.NH 3
+Abstract data types
+.PP
+An abstract data type or
+.I adt
+is an object that can contain data objects of several
+different types and declare
+functions that operate on them.
+The syntax for declaring an
+.CW adt
+is given later.
+Once an
+.CW adt
+has been declared, the identifier associated with it
+becomes a data-type name.
+.s1
+adt-type:
+	identifier
+	module-qualified-type
+.s2
+.PP
+There is also a
+.CW ref
+.CW adt
+type representing a reference (pointer) to an
+.CW adt .
+It is denoted
+.s1
+	Cref Iadt-type
+.s2
+where the identifier is the name of an
+.CW adt
+type.
+.NH 3
+Module types
+.PP
+A module type name is an identifier:
+.s1
+module-type:
+	identifier
+.s2
+The identifier is declared as a module identifier by a
+.I module-declaration ,
+as described in §6.5 below.
+An object of module type serves as a handle for the
+module, and is used to access its functions.
+.NH 3
+Module-qualified type
+.PP
+When an
+.CW adt
+is declared within a module declaration, the type name of that
+.CW adt
+is not generally visible to the rest of the program unless a specific
+.CW import
+request is given (see §6.6, §10 below).
+Without such a request, when
+.CW adt
+objects implemented by a module are declared by a client
+of that module, the
+.CW adt
+type name is qualified:
+.s1
+module-qualified-type:
+	identifier C->I identifier
+.s2
+Here the first identifier is either the name of a module
+or a variable of the module type;
+the second is the name of a type
+mentioned in the module declaration.
+.NH 3
+Function reference types
+.PP
+A function reference type represents a reference to a function of a given type.
+It is written as
+.s1
+	Cref Ifunction-type
+.s2
+Function types are discussed in §4.3 below.
+.NH 3
+Named types
+.PP
+Finally, data types may be named, using a
+.CW type
+declaration; this is discussed in §6.4 below.
+.s1
+type-name:
+	identifier
+.s2
+.NH 2
+Function types
+.PP
+A function type characterizes the arguments and return value of
+a function.  The syntax is
+.s1
+function-type:
+	Cfn Ifunction-arg-ret
+
+function-arg-ret:
+	C( Iformal-arg-listOC ) IraisesO
+	C( Iformal-arg-listOC ) : Idata-type raisesO
+
+formal-arg-list:
+	formal-arg
+	formal-arg-listC , Iformal-arg
+
+formal-arg:
+	nil-or-ID-listC : Itype
+	nil-or-IDC : self refO Iidentifier
+	nil-or-IDC : self Iidentifier
+	C*I
+
+nil-or-ID-list:
+	nil-or-ID
+	nil-or-ID-list C, Inil-or-ID
+
+nil-or-ID:
+	identifier
+	CnilI
+
+raises:
+	Craises ( Inil-or-ID-listC )I
+	CraisesI nil-or-ID
+
+.s2
+That is, the denotation of a function type has the keyword
+.CW fn
+followed by a comma-separated list of its arguments
+enclosed in parentheses,
+and perhaps followed by the type the function returns.
+Absence of a return value means that the function returns no
+value: it is a procedure.
+The names and types of arguments are specified.
+However, the name of an argument may be replaced by
+.CW nil ;
+in this case it is nameless.
+For example,
+.P1
+	fn (nil: int, nil: int): int
+	fn (radius: int, angle: int): int
+	fn (radius, angle: int): int
+.P2
+all denote exactly the same type,
+namely a function of two integers that returns an integer.
+As another example,
+.P1
+	fn (nil: string)
+.P2
+is the type of a function that takes a string argument
+and returns no value.
+.PP
+The
+.CW self
+keyword has a specialized use within
+.CW adt
+declarations.
+It may be used only for the first argument
+of a function declared within an
+.CW adt ;
+its meaning is discussed in §6.3 below.
+.PP
+The star character
+.CW *
+may be given as the last argument in a function type.
+It declares that
+the function is variadic; during a call, actual arguments at its
+position and following are passed in a manner
+unspecified by the language.
+For example, the type of the
+.CW print
+function of the
+.CW Sys
+module is
+.P1
+	fn (s: string, *): int
+.P2
+This means that the first argument of
+.CW print
+is a string and that other arguments may be given when the function
+is called.
+The Limbo language itself has no way of accessing these arguments;
+the notation is an artifice for describing facilities
+built into the runtime system, such as the
+.CW Sys
+module.
+.PP
+The type of a function includes user-defined exceptions that it raises,
+which must be listed in a corresponding
+.CW raises
+clause.
+.NH 1
+Limbo programs
+.PP
+Limbo source programs that implement modules are stored in files,
+conventionally named with the suffix
+.CW .b .
+Each such file begins with a single
+.CW implement
+directive naming the type of the module being implemented,
+followed by a sequence of declarations.
+Other files, conventionally named with the suffix
+.CW .m ,
+contain declarations for things obtainable from other modules.
+These files are incorporated by an
+.CW include
+declaration in the implementation modules that need them.
+At the top level, a program consists of a sequence
+of declarations.
+The syntax is
+.s1
+program:
+	Cimplement Iidentifier-listC ; Itop-declaration-sequence
+
+top-declaration-sequence:
+	top-declaration
+	top-declaration-sequence top-declaration
+
+top-declaration:
+	declaration
+	identifier-listC := IexpressionC ;I
+	identifier-listC = IexpressionC ;I
+	C( Iidentifier-listC ) := IexpressionC ;I
+	module-declaration
+	function-definition
+	adt-declaration
+.s2
+The
+.CW implement
+declaration at the start identifies the type of the module that
+is being implemented.
+The rest of the program consists of a sequence of various kinds of
+declarations and definitions that announce the names
+of data objects, types, and functions, and also create
+and initialize them.
+It must include a module declaration for the module
+being implemented and the objects it announces,
+and may also include declarations for the functions, data
+objects, types, and constants used privately within the module
+as well as declarations for modules used by it.
+.PP
+Declarations are used both at the top
+level (outside of functions) and also inside functions
+and module declarations.
+Some styles of declaration
+are allowed only in certain of these places,
+but all will be discussed together.
+.PP
+Most implementation modules provide an implementation for one type of module.
+Several module types may be listed, however, in the
+.CW implement
+declaration, when the implementation module implements them all.
+When the same name appears in more than one such module type, it must
+have the same type.
+.NH 1
+Declarations
+.PP
+Declarations take several forms:
+.s1
+declaration:
+	identifier-listC : ItypeC ;I
+	identifier-listC : ItypeC = IexpressionC ;I
+	identifier-listC : con IexpressionC ;I
+	Iidentifier-listC : import Iidentifier C;I
+	identifier-listC : typeI typeC ;I
+	identifier-listC : exceptionI tuple-typeO
+	Cinclude Istring-constantC ;I
+
+identifier-list:
+	identifier
+	identifier-listC , Iidentifier
+
+expression-list:
+	expression
+	expression-listC , Iexpression
+.s2
+.NH 2
+Data declarations
+.PP
+These forms constitute the basic way to declare and
+initialize data:
+.s1
+	identifier-listC : ItypeC ;I
+	identifier-listC : ItypeC = IexpressionC ;I
+.s2
+A comma-separated sequence of identifiers is followed by a colon
+and then the name of a type.
+Each identifier is declared as having that type and denotes a
+particular object
+for rest of its scope (see §11 below).
+If the declaration contains
+.CW =
+and an expression, the type must be a data type, and
+all the objects are initialized from
+the value of the expression.
+In a declaration at the top level
+(outside of a function), the expression must be
+constant (see §8.5) or an array initialized with constant expressions;
+the bound of any array must be a constant expression.
+Lists and
+.CW ref
+.CW adt
+types may not be initialized at the top level.
+If an object is not explicitly initialized, then
+it is always set to
+.CW nil
+if it has a reference type;
+if it has arithmetic type, then it is set to 0
+at the top level and is undefined if it occurs
+within a function.
+.PP
+For example,
+.P1
+	i, j: int = 1;
+	r, s: real = 1.0;
+.P2
+declares
+.CW i
+and
+.CW j
+as integers,
+.CW r
+and
+.CW s
+as real.
+It sets
+.CW i
+and
+.CW j
+to 1,
+and
+.CW r
+and
+.CW s
+to 1.0.
+.PP
+Another kind of declaration is a shorthand.
+In either of
+.s1
+	identifierC := IexpressionC ;I
+	C( Iidentifier-listC ) := IexpressionC ;I
+
+.s2
+identifiers on the left are declared using the type of the expression,
+and are initialized with the value of the expression.
+In the second case, the expression must be a tuple or an
+.CW adt ,
+and the types and values attributed to the identifiers
+in the list are taken from the members of the tuple, or the
+data members of the
+.CW adt
+respectively.
+For example,
+.P1
+	x: int = 1;
+.P2
+and
+.P1
+	x := 1;
+.P2
+are the same.
+Similarly,
+.P1
+	(p, q) := (1, 2.1);
+.P2
+declares the identifiers on the left as
+.CW int
+and
+.CW real
+and initializes them to 1 and 2.1 respectively.
+Declarations with
+.CW :=
+can also be expressions, and are discussed again in §8.4.4 below.
+.NH 2
+Constant declarations
+.PP
+The
+.CW con
+declaration
+.s1
+	Iidentifier-listC : conI expressionC ;I
+.s2
+declares a name (or names) for constants.
+The
+.I expression
+must be constant (see §8.5).
+After the declaration,
+each identifier in the list may be used anywhere a constant
+of the appropriate type is needed;
+the type is taken from the type of the constant.
+For example, after
+.P1
+	Seven: con 3+4;
+.P2
+the name
+.CW Seven
+is exactly the same as the constant 7.
+.PP
+The identifier
+.CW iota
+has a special meaning in the expression in a
+.CW con
+declaration.
+It is equivalent to the integer constant
+.CW 0
+when evaluating the expression for the first (leftmost) identifier declared,
+.CW 1
+for the second, and so on numerically.
+For example, the declaration
+.P1
+	M0, M1, M2, M3, M4: con (1<<iota);
+.P2
+declares several constants
+.CW M0
+through
+.CW M4
+with the values 1, 2, 4, 8, 16 respectively.
+.PP
+The identifier
+.CW iota
+is not reserved except inside the expression
+of the
+.CW con
+declaration.
+.NH 2
+adt declarations
+.PP
+An
+.CW adt
+or abstract data type contains data objects and functions that
+operate on them.
+The syntax is
+.s1
+adt-declaration:
+	IidentifierC : adt { Iadt-member-listOC } ;I
+
+adt-member-list:
+	adt-member
+	adt-member-list adt-member
+
+adt-member:
+	identifier-listC : cyclicO  Idata-typeC ;I
+	identifier-listC : con IexpressionC ;I
+	identifier-listC : Ifunction-typeC ;I
+	Cpick { Ipick-member-listC }I
+.s2
+After an
+.I adt-declaration ,
+the identifier becomes the name of the type of that
+.CW adt .
+For example, after
+.P1
+	Point: adt {
+		x, y: int;
+		add: fn (p: Point, q: Point): Point;
+		eq: fn (p: Point, q: Point): int;
+	};
+.P2
+the name
+.CW Point
+is a type name for an
+.CW adt
+of two integers and two
+functions; the fragment
+.P1
+	r, s: Point;
+	xcoord: int;
+	...
+	xcoord = s.x;
+	r = r.add(r, s);
+.P2
+makes sense.
+The first assignment selects one of the data members of
+.CW s ;
+the second calls one of the function members of
+.CW r .
+.PP
+As this example indicates,
+.CW adt
+members are accessed by mentioning an object with the
+.CW adt
+type, a dot, and then the name of the member;
+the details will be discussed in §8.13 below.
+A special syntactic indulgence is available for functions declared within an
+.CW adt :
+frequently such a function
+receives as an argument the same object used to access it
+(that is, the object before the dot).
+In the example just above,
+.CW r
+was both the object being operated on and the first argument to the
+.CW add
+function.
+If the first formal argument of a function declared in an
+.CW adt
+is marked with the
+.CW self
+keyword, then in any calls to the function, the
+.CW adt
+object is implicitly passed to the function, and
+is not mentioned explicitly in the actual argument list
+at the call site.
+For example, in
+.P1
+	Rect: adt {
+		min, max: Point;
+		contains: fn(r: self Rect, p: Point): int;
+	};
+
+	r1: Rect;
+	p1: Point;
+	...
+	if (r1.contains(p1)) ...
+.P2
+because the first argument of the
+.CW contains
+function is declared with
+.CW self ,
+the subsequent call to it automatically passes
+.CW r1
+as its first argument. The
+.CW contains
+function itself is defined elsewhere with this first
+argument explicit.
+(This mechanism is analogous to the
+.I this
+construct in C++ and other languages,
+but puts the special-casing at the declaration site and makes it explicit.)
+.PP
+If
+.CW self
+is specified in the declaration of a function, it must also be
+specified in the definition as well.  For example,
+.CW contains
+would be defined
+.P1
+	Rect.contains(r: self Rect, p: Point)
+	{
+		. . .
+	}
+.P2
+.PP
+The
+.CW adt
+type in Limbo
+does not provide control over the visibility
+of its individual members; if any are accessible, all are.
+.PP
+Constant
+.CW adt
+members follow the same rules as ordinary constants (§6.2).
+.PP
+The obsolete
+.CW cyclic
+modifier will be discussed in §11.1.
+.NH 3
+pick adts
+.PP
+An
+.CW adt
+which contains a
+.CW pick
+member is known as a
+.I pick
+.I adt .
+A
+.CW pick
+.CW adt
+is Limbo's version of a
+.I "discriminated union" .
+An
+.CW adt
+can only contain one
+.CW pick
+member and it must be the last component of the
+.CW adt .
+Each
+.I identifier
+enumerated in the
+.I pick-tag-list
+names a variant type of the
+.CW pick
+.CW adt .
+The syntax is
+.s1
+pick-member-list:
+	pick-tag-listC =>I
+	pick-member-list pick-tag-listC =>I
+	pick-member-list identifier-listC : cyclicO  Idata-typeC ;I
+.s2
+.s1
+pick-tag-list:
+	identifier
+	pick-tag-listC or Iidentifier
+.s2
+.PP
+The
+.I pick-member-list
+contains a set of data members for each
+.I pick-tag-list .
+These data members are specific to those variants of the
+.CW pick
+.CW adt
+enumerated in the
+.I pick-tag-list .
+The
+.CW adt
+data members found outside of the
+.CW pick
+are common to all variants of the
+.CW adt  .
+A
+.CW pick
+.CW adt
+can only be used as a
+.CW ref
+.CW adt
+and can only be initialized from a value of one of its variants.
+For example, if
+.CW Constant
+is a
+.CW pick
+.CW adt
+and
+.CW Constant.Real
+is one of its variant types then
+.P1
+	c : ref Constant = ref Constant.Real("pi", 3.1);
+.P2
+will declare
+.CW c
+to have type
+.CW ref
+.CW Constant
+and initialize it with a value of the variant type
+.CW ref
+.CW Constant.Real .
+.NH 2
+Type declarations
+.PP
+The type declaration
+.s1
+	Iidentifier-listC : typeI data-type  ;I
+.s2
+introduces the identifiers as synonyms for the
+given type.
+Type declarations are transparent; that is,
+an object declared with the newly-named
+type has the same type as the one it abbreviates.
+.NH 2
+Module declarations
+.PP
+A module declaration collects and packages declarations of
+.CW adt ,
+functions, constants and simple types, and creates an
+interface with a name
+that serves to identify the type of the module.
+The syntax is
+.s1
+module-declaration:
+	IidentifierC : module { Imod-member-listOC } ;I
+
+mod-member-list:
+	mod-member
+	mod-member-list mod-member
+
+mod-member:
+	identifier-listC : Ifunction-typeC ;I
+	identifier-listC : Idata-typeC ;I
+	adt-declarationC ;I
+	identifier-listC : con Iexpression C;I
+	identifier-listC : type Itype C;I
+.s2
+After a module declaration, the named
+.I identifier
+becomes the name of the type of that module.
+For example, the declaration
+.P1
+Linear: module {
+	setflags: fn (flag: int);
+	TRUNCATE: con 1;
+	Vector: adt {
+		v: array of real;
+		add: fn (v1: self Vector, v2: Vector): Vector;
+		cross: fn (v1: self Vector, v2: Vector): Vector;
+		dot: fn (v1: self Vector, v2: Vector);
+		make: fn (a: array of real): Vector;
+	};
+	Matrix: adt {
+		m: array of array of real;
+		add: fn (m1: self Matrix, m2: Matrix): Matrix;
+		mul: fn (m1: self Matrix, m2: Matrix): Matrix;
+		make: fn (a: array of array of real): Matrix;
+	};
+};
+.P2
+is a module declaration for a linear algebra package that
+implements two
+.CW adt ,
+namely
+.CW Vector
+and
+.CW Matrix ,
+a constant,
+and a function
+.CW setflags .
+The name
+.CW Linear
+is the type name for the module, and it may be used to declare
+an object referring to an instance of the module:
+.P1
+	linearmodule:  Linear;
+.P2
+Before the module can be used, it must be loaded, for example in
+the style:
+.P1
+	linearmodule = load Linear "/usr/dmr/limbo/linear.dis";
+	if (linearmodule == nil) {
+		sys->print("Can't load Linear\en");
+		exit;
+	}
+.P2
+The
+.CW load
+operator is discussed more fully in §8.4.5 below.
+.PP
+To initialize data declared as part of a module
+declaration, an assignment expression may be used at the top level.
+For example:
+.P1
+	implement testmod;
+	testmod: module {
+		num:	int;
+	};
+	. . .
+	num = 5;
+.P2
+The right side of the assignment must be a constant expression (§8.5).
+.NH 2
+Declarations with
+.CW import
+.PP
+These declarations take the form
+.s1
+	Iidentifier-listC : import Iidentifier C;I
+.s2
+Identifiers for entities
+declared within a module declaration are normally
+meaningful only in a context that
+identifies the module.
+The
+.CW import
+declaration lifts the names of specified members of a module
+directly into the current scope.
+The use of
+.CW import
+will be discussed more fully in §8.1.4 below, after the syntax
+for expressions involving modules has been presented.
+.NH 2
+Exception declarations
+.PP
+Exceptions represent run-time errors not data objects or values.
+Exception declarations have the form:
+.s1
+	identifier-listC : exceptionI tuple-typeO
+.s2
+Each identifier gives a compile-time name to a distinct user-defined run-time error,
+signaled at run-time by a
+.CW raise
+statement that quotes that identifier, as described below.
+An exception optionally includes a tuple of data values that qualifies the exception;
+the types of those values are provided by the tuple type in this declaration.
+.NH 2
+Declarations with
+.CW include
+.PP
+The string following the
+.CW include
+keyword names
+a file, which is inserted into the program's
+text at that point.
+The included
+text is treated like text literally present.
+Conventionally, included files declare
+module interfaces and are named with the suffix
+.CW .m .
+The directories to be searched for included files
+may be specified to the Limbo compiler command.
+Include files may be nested.
+.NH 1
+Function definitions
+.PP
+All executable code
+is supplied as part of a function definition.
+The syntax is
+.s1
+function-definition:
+	function-name-part function-arg-retC { IstatementsC }I
+
+function-name-part:
+	identifier
+	function-name-partC . Iidentifier
+.s2
+The syntax of the statements in a function will be discussed in §9 below.
+As a brief example,
+.P1
+	add_one(a: int): int
+	{
+		return a+1;
+	}
+.P2
+is a simple function
+that might be part of the top level of a module.
+.PP
+Functions that are declared within an
+.CW adt
+use the qualified form of definition:
+.P1
+	Point: adt {
+		x, y: int;
+		add: fn (p: Point, q: Point): Point;
+		eq: fn (p: Point, q: Point): int;
+	}
+	. . .
+	Point.add(p: Point, q: Point): Point
+	{
+		return Point(p.x+q.x, p.y+q.y);
+	}
+.P2
+Because an
+.CW adt
+may contain an
+.CW adt ,
+more than one qualification is possible.
+.NH 1
+Expressions
+.PP
+Expressions in Limbo resemble those of C, although some
+of the operators are different.
+The most salient difference between Limbo's expression
+semantics and those of C is that Limbo
+has no automatic coercions between types; in Limbo every
+type conversion is explicit.
+.NH 2
+Terms
+.PP
+The basic elements of expressions are terms:
+.s1
+term:
+	identifier
+	constant
+	real-constant
+	string-constant
+	CnilI
+	C( Iexpression-listC )I
+	termC . Iidentifier
+	termC -> Iterm
+	termC ( Iexpression-listOC )I
+	termC [ IexpressionC ]I
+	termC [ IexpressionC : IexpressionC ]I
+	termC [ IexpressionC : ]I
+	termC ++I
+	termC --I
+.s2
+The operators on terms all associate to the left,
+and their order of precedence, with tightest listed first, is as follows:
+.P1
+			.
+			->
+			() [] ++ --
+.P2
+.NH 3
+Simple terms
+.PP
+The first five kinds of term are constants and identifiers.
+Constants have a type indicated by their syntax.
+An identifier used in an expression is often a previously declared
+data object with a particular data type; when used as a term
+in an expression
+it denotes the value stored in the object, and the term has
+the declared object's type.
+Sometimes, as discussed below, identifiers used in expressions
+are type names, function names, or module identifiers.
+.NH 3
+Parenthesized terms
+.PP
+A comma-separated list of expressions enclosed in parentheses
+is a term.
+If a single expression is present in the list,
+the type and value are those of the expression;
+the parentheses affect only the binding
+of operators in the expression of which the term
+is a part.
+If there is more than one expression in the list,
+the value is a tuple.
+The member types
+and values are taken from those of the expressions.
+.NH 3
+Selection
+.PP
+A term of the form
+.s1
+	termC . Iidentifier
+.s2
+denotes selection of a member of an
+.CW adt
+or one element from a tuple.
+.PP
+In the first case,
+the term must be a
+type name or yield an object;
+its type must be
+.CW adt
+or
+.CW ref
+.CW adt ;
+the identifier must be a member of the
+.CW adt .
+The result denotes the named member (either a data object
+or a function).
+.PP
+In the second case,
+the term must yield a value of a tuple type,
+and the identifier must have the form \f(CWt\fP\fIn\fP
+where
+.I n
+is a decimal number giving the index (starting from 0) of an element of the tuple.
+The result is the value of that element.
+.NH 3
+Module qualification
+.PP
+A term of the form
+.s1
+	termC -> Iterm
+.s2
+denotes module qualification.
+The first term identifies a module: either it is a module type name,
+or it is an expression of module type.
+The second term is a constant name, type, or function specified within
+that module's declaration.
+Either the module type name or
+an object of the module's type suffices to qualify constants and types;
+functions directly exported by the module or contained within its
+.CW adt
+must be qualified by an object of the module's type, initialized with
+.CW load .
+.PP
+An example using an abridged version of an example above: given
+.P1
+	Linear: module {
+		setflags: fn(flag: int);
+		TRUNCATE: con 1;
+		Vector: adt {
+			make: fn(v: array of real): Vector;
+			v: array of real;
+		};
+	};
+.P2
+one might say
+.P1
+	lin := load Linear "/dis/linear.dis";
+	a: array of real;
+
+	v1: lin->Vector;
+	v2: Linear->Vector;
+	lin->setflags(Linear->TRUNCATE);
+	v1 = lin->(Linear->Vector).make(a);
+	v1 = lin->v1.make(a);
+	v1 = lin->v1.add(v1);
+	v1.v = nil;
+.P2
+Here, the declarations for
+.CW v1
+and
+.CW v2
+are equivalent; either a module type name (here,
+.CW Linear )
+or a handle (here,
+.CW lin )
+suffices to identify the module.
+In the call to
+.CW setflags ,
+a handle
+is required for the call itself;
+the type name is sufficient for the constant.
+.PP
+When calling a function associated with an
+.CW adt
+of another module, it is necessary to identify
+both the module and the
+.CW adt
+as well as the function.
+The two calls to the
+.CW make
+function illustrate two ways of doing this.
+In the first,
+.P1
+	v1 = lin->(Linear->Vector).make(a);
+.P2
+the module handle
+.CW lin
+is specified first, then
+the type name of the
+.CW Vector
+.CW adt
+within it, and then the function.
+In the second call
+.P1
+	v1 = lin->v1.make(a);
+.P2
+instead of using a type name to specify the
+.CW adt ,
+an instance of an object of the appropriate type is
+used instead.
+In the first example, the parentheses are required because
+the qualification operators associate to the left.
+.P1
+	v1 = lin->Vector.make(a);	# Wrong
+	v1 = lin->Linear->Vector.make(a);	# Wrong
+.P2
+The first is wrong because the same
+.CW lin
+can't serve as a qualifier for both the type and the call;
+the second is wrong because
+.CW lin->Linear
+is meaningless.
+.PP
+Using
+.CW import
+makes the code less verbose:
+.P1
+	lin := load Linear "/usr/dmr/limbo/linear.dis";
+	Vector, TRUNCATE, setflags: import lin;
+	a: array of real;
+
+	v1: Vector;
+	v2: Vector;
+	setflags(TRUNCATE);
+	v1 = Vector.make(a);
+	v1 = v1.make(a);
+	v1 = v1.add(v1);
+	v1.v = nil;
+.P2
+.NH 3
+Function calls
+.PP
+The interpretation of an expression in the form
+.s1
+	termC ( Iexpression-listOC )
+.s2
+depends on the declaration of the term.
+If it is the (perhaps qualified) name of an
+.CW adt ,
+then the expression is a cast; this is discussed in §8.2.11 below.
+If the term is either the (perhaps qualified) name of a function
+or a value of a function reference type, and
+the expression means a function call; this is discussed here.
+.PP
+A plain identifier as the
+.I term
+can name a function defined
+in the current module or imported into it.
+A term qualified by using the selection operator
+.CW .
+specifies a function member of an
+.CW adt ;
+a term using
+.CW ->
+specifies a function defined in another module.
+.PP
+The
+.I term ,
+including a plain identifier denoting a variable of function reference type,
+can also yield a function reference value.
+The value specifies both a function and its module,
+established when the value was created,
+and cannot be qualified by the
+.B ->
+specifier.
+.PP
+Function calls in Limbo
+create a copy of each argument of value type,
+and the execution of a function cannot
+affect the value of the corresponding actual argument.
+For arguments of reference type,
+execution of the function may affect the value of the object
+to which the reference refers, although it cannot
+change the argument itself.
+The actual arguments to a function are evaluated
+in an unspecified order,
+although any side effects caused by argument evaluation
+occur before the function is called.
+.PP
+Function calls may be directly or indirectly recursive;
+objects declared within each function are distinct from
+those in their dynamic predecessors.
+.PP
+Functions (§4.3, §7) may either return a value
+of a specified type, or return no value.
+If a function returns a value, it has the specified type.
+A call to a function that returns no value may appear only as the
+sole expression in a statement (§9.1).
+.PP
+A function name is converted to a reference to that function when it appears
+in a context requiring a function reference type, including assignment to a variable,
+as an actual parameter, or the return value of a function.
+The resulting reference value includes the appropriate module value for the function name,
+following the rules given above for implicit and explicit qualifiers, and imports.
+For example, the following program fragment defines a table of commands:
+.P1
+	Cmd: adt {
+		c:	int;
+		f:	ref fn(a: array of string): int;
+	};
+
+	mkcmds(): array of Cmd
+	{
+		return array[] of {
+			('.', editdot),
+			('a', editadd),
+			('d', editdel),
+			('?', edithelp),
+			('w', editwrite),
+			('q', editquit),
+		};
+	}
+
+	editdot(a: array of string): int
+	{
+		...
+	}
+	\&...
+	editquit(a: array of string): int
+	{
+		...
+	}
+.P2
+which might be used as follows:
+.P1
+	cmd := mkcmds();
+	...
+	for(i := 0; i < len cmd; i++)
+		if(cmd[i].c == c){
+			cmd[i].f(args);
+			return;
+		}
+	error("unknown command");
+.P2
+.NH 3
+Subscripting and slicing
+.PP
+In a term of the form
+.s1
+	termC [ IexpressionC ]I
+.s2
+the first term must be an array or a string, and the
+bracketed expression must have
+.CW int
+type.
+The whole term
+designates a member of the array or string, indexed by the bracketed expression;
+the index origin is 0.
+For an array, the type of the whole term is
+the type from which the array is constructed;
+for a string, the type is an
+.CW int
+whose value is the Unicode character at that position in the string.
+.PP
+It is erroneous to refer to a nonexisting
+part of an array or string.
+(A single exception to this rule, discussed in §8.4.1 below,
+allows extending a string by assigning a character at its end.)
+.PP
+In a term of the form
+.s1
+	termC [ IexpressionC : IexpressionC ]I
+.s2
+the first term must be an array or a string, and the whole term
+denotes a slice of it.
+The first expression is the lower bound, and the second
+is the upper.
+If
+.CW e1
+is the first expression and
+.CW e2
+is the second, then in
+.CW a[e1:e2]
+it must be the case that
+.CW "0<=e1, e1<=e2, e2<=len a" ,
+where
+.CW len
+gives the number of elements in the array or string.
+When the term is an array, the value is an
+array of the same type beginning at the indicated
+lower bound and extending to the element just before
+the upper bound.
+When the term is a string, the value is similarly the substring
+whose first character is indexed by the lower bound
+and whose last character lies just before the upper bound.
+.PP
+Thus, for both arrays and strings, the number of elements in
+.CW "a[e1:e2]
+is equal to
+.CW e2-e1 .
+.PP
+A slice of the form
+.CW a[e:]
+means
+.CW "a[e:len a].
+.PP
+When a string slice is assigned to another string or passed as an
+argument, a copy of its value is made.
+.PP
+A slice of an array produces a reference to the designated subarray;
+a change to an element of either the original array or
+the slice is reflected in the other.
+.PP
+In general, slice expressions cannot be the subject of
+assignments.
+However, as a special case, an array slice expression of the
+form
+.CW a[e1:]
+may be assigned to.
+This is discussed in §8.4.1.
+.PP
+The following example shows how slices
+can be used to accomplish what would
+need to be done with pointer arithmetic in C:
+.P1
+	fd := sys->open( ... );
+	want := 1024;
+	buf := array[want] of byte;
+	b := buf[0:];
+	while (want>0) {
+		got := sys->read(fd, b, want);
+		if (got<=0)
+			break;
+		b = b[got:];
+		want -= got;
+	}
+.P2
+Here the array
+.CW buf
+is filled by successive calls to
+.CW sys->read
+that may supply fewer bytes than requested; each call
+stores up to
+.CW want
+bytes
+starting at
+.CW b[0] ,
+and returns the number of bytes stored.
+The invariant is that the slice
+.CW b
+always refers to the part of the array still to be stored into.
+.NH 3
+Postfix increment and decrement
+.PP
+A term of the form
+.s1
+	termC ++I
+.s2
+is called a
+.I post-increment .
+The term must be an lvalue (see §8.4 below) and must have an
+arithmetic type.
+The type and value of the whole term is
+that of the incremented term.
+After the value is taken, 1 of the appropriate
+type is added to the lvalue.
+The result is undefined if the same object is changed
+more than once in the same expression.
+.PP
+The term
+.s1
+	termC --I
+.s2
+behaves analogously to the increment case except
+that 1 is subtracted from the lvalue.
+.PP
+.NH 2
+Monadic expressions
+.PP
+Monadic expressions are expressions with
+monadic operators, together with a few more
+specialized notations:
+.s1
+monadic-expression:
+	term
+	monadic-operator monadic-expression
+	Carray [ IexpressionC ] of Idata-type
+	Carray [ IexpressionOC ] of { Iinit-listC }I
+	Clist of { Iexpression-listC }I
+	Cchan of Idata-type
+	Cchan [ IexpressionC ] of Idata-type
+	data-type monadic-expression
+
+monadic-operator: one of
+	C+ - ! ~ ref * ++ -- <- hd tl lenI
+.s2
+.NH 3
+Monadic additive operators
+.PP
+The
+.CW -
+operator produces the negative of its operand, which
+must have an arithmetic type.
+The type of the result is the same as the type of
+its operand.
+.PP
+The
+.CW +
+operator has no effect; it is supplied only for
+symmetry.
+However, its argument must have an arithmetic type
+and the type of the result is the same.
+.NH 3
+Logical negation
+.PP
+The
+.CW !
+operator yields the
+.CW int
+value 1 if its operand
+has the value 0, and yields 0 otherwise.
+The operand must have type
+.CW int .
+.NH 3
+One's complement
+.PP
+The
+.CW ~
+operator yields the 1's complement of its
+operand, which must have type
+.CW int
+or
+.CW byte .
+The type of the result is the same as that of its operand.
+.NH 3
+Reference and indirection operators
+.PP
+If
+.I e
+is an expression of an
+.CW adt
+type, then
+.CW ref
+.I e
+is an expression of
+.CW ref
+.CW adt
+type whose value refers to (points to) an anonymous object with value
+.I e .
+The
+.CW ref
+operator differs from the unary
+.CW &
+operator of C; it makes a new object and returns a reference
+to it, rather than generating a reference to an existing object.
+.PP
+If
+.I e
+is an expression of type
+.CW ref
+.CW adt ,
+then
+.CW *
+.I e
+is the value
+of the
+.CW adt
+itself.
+The value of
+.I e
+must not be
+.CW nil .
+.PP
+For example, in
+.P1
+	Point: adt { ... };
+	p: Point;
+	pp: ref Point;
+	p = Point(1, 2);
+	pp = ref p;	# pp is a new Point; *pp has value (1, 2)
+	p = Point(3, 4);	# This makes *pp differ from p
+	*pp = Point(4, 5);	# This does not affect p
+.P2
+the expression
+.CW *pp
+at first refers to a copy of the value stored in
+.CW p ,
+so
+.CW "*pp == p
+is true; however, when
+.CW p
+is changed later,
+.CW *pp
+does not change.
+.NH 3
+Prefix increment and decrement
+.PP
+A monadic expression of the form
+.s1
+	C++ Imonadic-expression
+.s2
+is called a
+.I pre-increment .
+The monadic expression must be an lvalue (see §8.4 below) and must have an
+arithmetic type.
+Before the value is taken, 1 of the appropriate type
+is added to the lvalue.
+The type and value of the whole expression is
+that of the now incremented term.
+The result is undefined if the same object is changed
+more than once in the same expression.
+.PP
+The term
+.s1
+	C-- Imonadic-expression
+.s2
+behaves analogously to the increment case except
+that 1 is subtracted from the lvalue.
+.NH 3
+Head and tail
+.PP
+The operand of the
+.CW hd
+operator must be a non-empty list.
+The value is the first member of the list
+and has that member's type.
+.PP
+The operand of the
+.CW tl
+operator must be a non-empty list.
+The value is the tail of the list,
+that is, the part of the list after its
+first member.
+The tail of a list with one member is
+.CW nil .
+.NH 3
+Length
+.PP
+The operand of the
+.CW len
+operator is a string, an array, or a list.
+The value is an
+.CW int
+giving the number of elements currently in the item.
+.NH 3
+Tagof
+.PP
+The operand of the
+.CW tagof
+operator is a monadic expression of type
+.CW ref
+.CW adt
+that refers to a
+.CW pick
+.CW adt .
+or the type name of a
+.CW pick
+.CW adt
+or one of its variants.
+The value is an
+.CW int
+giving a unique value for each of the variants and for the
+.CW pick
+.CW adt
+type itself.
+.NH 3
+Channel communication
+.PP
+The operand of the communication operator
+.CW <-
+has type
+.CW chan
+.CW  of
+.I sometype .
+The value of the expression
+is the first unread object previously sent over that
+channel, and has the type associated with the channel.
+If the channel is empty, the program delays
+until something is sent.
+.PP
+As a special case, the operand of
+.CW <-
+may have type
+.CW array
+.CW of
+.CW chan
+.CW of
+.I sometype .
+In this case, all of the channels in the array are tested;
+one is fairly selected from those that have data.
+The expression yields a tuple of type
+.CW (int,
+.I sometype
+.CW ) ;
+its first member gives the index of the channel from
+which data was read, and its second member is the
+value read from the channel.
+If no member of the array has data ready, the expression delays.
+.PP
+Communication channels are treated more fully in §9.8 and
+§9.13 below with the discussion of the
+.CW alt
+and
+.CW spawn
+statements.
+.NH 3
+Creation of arrays
+.PP
+In the expressions
+.s1
+	Carray [ IexpressionC ] of Idata-type
+	Carray [ IexpressionOC ] of { Iinit-listC ,OC }I
+.s2
+the value is a new array of the specified type.
+In both forms, the
+.I expression
+must be of type
+.CW int ,
+and it supplies the size of the array.
+In the first form, the type is given,
+and the values in the array are initialized as
+appropriate to the underlying type.
+In the second form, a comma-separated list of values to initialize
+the array is given, optionally followed by a trailing comma.
+The type of the array is taken from the types of
+the initializers, which must all be the same.
+The list of initializers has the syntax
+.s1
+init-list:
+	element
+	init-listC , Ielement
+
+element:
+	expression
+	expressionC => Iexpression
+	C* => Iexpression
+.s2
+In an
+.I init-list
+of plain expressions (without
+.CW => ),
+the members of the array
+are successively initialized with the corresponding
+elements of the init-list.
+An element of the form
+.CW e1=>e2
+initializes the member of the array at subscript
+.CW e1
+with the expression
+.CW e2 .
+After such an element has been given, subsequent
+simple elements (without
+.CW => )
+begin initializing at position
+.CW e1+1
+and so on.
+Each of the first expressions must be of type
+.CW int
+and must evaluate to a constant (§8.5).
+.PP
+If an element of the form
+.CW *
+.CW =>e2
+is present, all members of the array not otherwise
+initialized are set to the value
+.CW e2 .
+The expression
+.CW e2
+is evaluated for each subscript position,
+but in an undefined order.
+For example,
+.P1
+	arr := array[3] of { * => array[3] of { * => 1 } };
+.P2
+yields a 2-dimensional array (actually an array of arrays) filled with
+.CW 1 's.
+.PP
+If the expression giving the size of the array is omitted, its size
+is taken from the largest subscript of
+a member explicitly initialized.
+It is erroneous to initialize a member twice.
+.NH 3
+Creation of lists
+.PP
+The value of an expression
+.s1
+	Clist of { Iexpression-listC }I
+.s2
+is a list consisting of the expressions given.
+The types of the expressions must be identical,
+and this type is the underlying type of the list.
+The first expression is the head of the list, and the
+remaining expressions are a list constituting its tail.
+Where a list is expected,
+.CW nil
+specifies an empty list.
+.NH 3
+Creation of channels
+.PP
+The value of
+.s1
+	Cchan of Idata-type
+.s2
+is an initialized channel of the specified type.
+Just a declaration of a channel leaves it initialized only to
+.CW nil ;
+before it can be used it must be created.  For example,
+.P1
+	ch: chan of int;		# just declares, sets ch to nil
+	. . .
+	ch = chan of int;	# creates the channel and assigns it
+.P2
+Such a channel is unbuffered.
+The value of
+.s1
+	Cchan [ IexpressionC ] of Idata-type
+.s2
+is an initialized channel of the specified type.
+The
+.I expression
+must be of type
+.CW int ,
+and sets the size of the channel's buffer.
+If the size is zero, the channel is unbuffered, as for the first form.
+.NH 3
+Casts
+.PP
+An expression of the form
+.s1
+	data-type monadic-expression
+.s2
+in which a type name is followed by an expression
+is called a
+.I cast ,
+and converts the monadic expression to the named type.
+Only certain specialized forms are provided for.
+.NH 4
+Arithmetic casts
+.PP
+In arithmetic casts, the named type must be one of
+.CW byte ,
+.CW int ,
+.CW big ,
+or
+.CW real ,
+and the monadic-expression must have arithmetic type.
+For example,
+.P1
+	byte 10
+.P2
+is an expression of
+.CW byte
+type and value 10.
+When real values are converted to integral ones,
+they are rounded to the nearest integer, and away from 0
+if there is a tie.
+The effect of overflow during conversion is undefined.
+.NH 4
+Casts to strings
+.PP
+Here the named data type is
+.CW string .
+In a first form, the monadic expression has arithmetic type
+.CW byte , (
+.CW int ,
+.CW big ,
+or
+.CW real )
+and the value is a string containing the decimal representation
+of the value, which may be either positive or negative.
+A
+.CW real
+operand is converted as if by format
+.CW %g ,
+and if the result is converted back to
+.CW real ,
+the original value will be recovered exactly.
+.PP
+In a second form,
+the monadic expression has type
+.CW array
+.CW of
+.CW byte .
+The value is a new string containing the Unicode characters
+obtained by interpreting the bytes in the array as a UTF-8 representation
+of that string.
+(UTF-8 is a representation of 16-bit Unicode characters as one,
+two, or three bytes.)
+The result of the conversion is undefined if the byte array
+ends within a multi-byte UTF-8 sequence.
+.NH 4
+Casts from strings
+.PP
+In a first form, the monadic expression is a string,
+and the named type is an arithmetic type.
+The value is obtained by converting the string to
+that type.  Initial white space is ignored; after a possible
+sign, conversion
+ceases at the first character not part of a number.
+.PP
+In a second form, the named type is
+.CW array
+.CW of
+.CW byte
+and the monadic-expression is a string.
+The value is a new array of bytes containing the UTF-8 representation
+of the Unicode characters in the string.
+For example,
+.P1
+	s := "Ångström";
+	a := array of byte s;
+	s = string a;
+.P2
+takes the string
+.CW s
+apart into bytes in the second line,
+and puts it back in the third.
+The length of
+.CW s
+is 8, because it contains that many characters;
+the length of
+.CW a
+is larger, because some of its characters require more than
+one byte in the UTF-8 representation.
+.NH 4
+Casts to
+.CW adt
+and
+.CW ref
+.CW adt
+.PP
+Here the named type is that of an
+.CW adt
+or
+.CW ref
+.CW adt ,
+and the monadic expression is a comma-separated list of expressions
+within parentheses.
+The value of the expression is an instance of an
+.CW adt
+of the named type whose data members are initialized with
+the members of the list, or whose single data member
+is initialized with the parenthesized expression.
+In case the type is
+.CW ref
+.CW adt ,
+the value is a reference to the new
+instance of the
+.CW adt .
+.PP
+The expressions in the list, read in order, correspond with the data
+members of the
+.CW adt
+read in order; their types and number must agree.
+Placement of any function members of the
+.CW adt
+is ignored.
+For example,
+.P1
+	Point: adt {
+		x: int;
+		eq: fn (p: Point): int;
+		y: int;
+	};
+	. . .
+	p: Point;
+	p = Point(1, 2);
+.P2
+puts in
+.CW p
+a
+.CW Point
+whose
+.CW x
+value is 1 and whose
+.CW y
+value is 2.
+The declaration and assignment could also be written
+.P1
+	p := Point(1, 2);
+.P2
+.NH 2
+Binary expressions
+.PP
+Binary expressions are either monadic expressions,
+or have two operands and an infix operator;
+the syntax is
+.s1
+binary-expression:
+	monadic-expression
+	binary-expression binary-operator binary-expression
+
+binary-operator: one of
+	C** * / % + - << >> < > <= >= == != & ^ | :: && ||I
+.s2
+All these binary operators are left-associative except for
+.CW **
+and
+.CW :: ,
+which associate to the right.
+Their precedence is as listed here, with tightest first:
+.P1
+			**
+			* / %
+			+ -
+			<< >>
+			< > <= >=
+			== !=
+			&
+			^
+			|
+			::
+			&&
+			||
+.P2
+.NH 3
+Exponentiation
+.PP
+The
+.CW **
+operator accomplishes exponentiation.
+The type of the left operand must be
+.CW int ,
+.CW big
+or
+.CW real .
+The type of the right operand must be
+.CW int .
+The result has the type of the left operand.
+The operator is right associative, thus
+.P1
+	3**4*2 = (3**4)*2 = 81*2 = 162
+	-3**4 = (-3)**4 = 81
+	2**3**2 = 2**(3**2) = 2**9 = 512
+.P2
+.NH 3
+Multiplicative operators
+.PP
+The
+.CW * ,
+.CW / ,
+and
+.CW %
+operators respectively accomplish multiplication, division, and remainder.
+The operands must be of identical arithmetic type, and the result has that
+same type.
+The remainder operator does not apply to type
+.CW real .
+If overflow or division by 0 occurs, the result is undefined.
+The absolute value of
+.CW a%b
+is less than the absolute value of
+.CW b ;
+.CW "(a/b)*b + a%b
+is always equal to
+.CW a ;
+and
+.CW a%b
+is non-negative if
+.CW a
+and
+.CW b
+are.
+.NH 3
+Additive operators
+.PP
+The
+.CW +
+and
+.CW -
+operators respectively accomplish addition and subtraction
+of arithmetic operands of identical type;
+the result has the same type.
+The behavior on overflow or underflow is undefined.
+The
+.CW +
+operator may also be applied to strings;
+the result is a string that is the concatenation of the operands.
+.NH 3
+Shift operators
+.PP
+The shift operators are
+.CW <<
+and
+.CW >> .
+The left operand may be
+.CW big ,
+.CW int ,
+or
+.CW byte ;
+the right operand is
+.CW int .
+The type of the value is the same as its left operand.
+The value of the right operand must be non-negative
+and smaller than the number of bits in the left operand.
+For the left-shift operator
+.CW << ,
+the fill bits are 0;
+for the right-shift operator
+.CW >> ,
+the fill bits are a copy of the sign for the
+.CW int
+case, and 0 for the
+.CW byte
+case.
+.NH 3
+Relational operators
+.PP
+The relational operators are
+.CW <
+(less than),
+.CW >
+(greater than),
+.CW <=
+(less than or equal),
+.CW >=
+(greater than or equal),
+.CW ==
+(equal to),
+.CW !=
+(not equal to).
+The first four operators, which generate orderings,
+apply only to arithmetic types
+and to strings; the types of their operands
+must be identical, except that a string may be
+compared to
+.CW nil .
+Comparison on strings is lexicographic over the
+Unicode character set.
+.PP
+The equality operators
+.CW ==
+and
+.CW !=
+accept operands of arithmetic, string, and reference types.
+In general, the operands must have identical type,
+but reference types and strings may be compared for identity with
+.CW nil .
+Equality for reference types occurs when the operands
+refer to the same object, or when both are
+.CW nil .
+An uninitialized string, or one set to
+.CW nil ,
+is identical to the empty string denoted
+.CW \&""
+for all the relational operators.
+.PP
+The value of any comparison is the
+.CW int
+value 1 if the stated
+relation is true, 0 if it is false.
+.NH 3
+Bitwise logical operators
+.PP
+The logical operators
+.CW &
+(and),
+.CW ^
+(exclusive or) and
+.CW |
+(inclusive or)
+require operands of the same type,
+which must be
+.CW byte ,
+.CW int ,
+or
+.CW big .
+The result has the same type and its
+value is obtained by applying the operation
+bitwise.
+.NH 3
+List concatenation
+.PP
+The concatenation operator
+.CW ::
+takes a object of any data type
+as its left operand and a list as its right operand.
+The list's underlying type must be the same as
+the type of the left operand.
+The result is a new list with the left operand
+tacked onto the front:
+.P1
+	hd (a :: l)
+.P2
+is the same as
+.CW a .
+.NH 3
+Logical operators
+.PP
+The logical
+.I and
+operator
+.CW &&
+first evaluates its left operand.
+If the result is zero, then the value of the
+whole expression is the
+.CW int
+value 0.
+Otherwise the right operand is evaluated; if
+the result is zero, the value of the whole
+expression is again 0; otherwise it is 1.
+The operands must have the same arithmetic type.
+.PP
+The logical
+.I or
+operator
+.CW ||
+first evaluates its left operand.
+If the result is non-zero, then the value of the
+whole expression is the
+.CW int
+value 1.
+Otherwise the right operand is evaluated; if
+the result is non-zero, the value of the whole
+expression is again 1; otherwise it is 0.
+The operands must have the same arithmetic type.
+.NH 2
+General Expressions
+.PP
+The remaining syntax for expressions is
+.s1
+expression:
+	binary-expression
+	lvalue-expression assignment-operator expression
+	C( Ilvalue-expression-listC ) = Iexpression
+	send-expression
+	declare-expression
+	load-expression
+
+assignment-operator: one of
+	C= &= |= ^= <<= >>= += -= *= /= %=I
+.s2
+The left operand of an assignment can take only certain forms, called lvalues.
+.s1
+lvalue-expression:
+	identifier
+	CnilI
+	termC [ IexpressionC ]I
+	termC [ IexpressionC : ]I
+	termC . Iidentifier
+	C( Ilvalue-expression-listC )I
+	C* Imonadic-expression
+
+lvalue-expression-list:
+	lvalue
+	lvalue-expression-listC , Ilvalue
+.s2
+.NH 3
+Simple assignments with
+.CW =
+.PP
+In general, the types of the left and right operands
+must be the same; this type must be a data type.
+The value of an assignment is its new left operand.
+All the assignment operators associate right-to-left.
+.PP
+In the ordinary assignment with
+.CW = ,
+the value of the right side is assigned to the object
+on the left.
+For simple assignment only, the left operand may be a
+parenthesized list of lvalues and the right operand
+either a tuple or an
+.CW adt
+whose data members correspond
+in number and type to the lvalues in the list.
+The members of the tuple, or
+the data members of the
+.CW adt ,
+are assigned in sequence to
+lvalues in the list.
+For example,
+.P1
+	p: Point;
+	x, y: int;
+	(x, y) = p;
+.P2
+splits out the coordinates of the point into
+.CW x
+and
+.CW y .
+These rules apply recursively, so that if one of the
+components of the left side is a parenthesized list of lvalues,
+it is assigned from a corresponding
+.CW adt
+or tuple on the right.
+.PP
+If the left operand of a simple assignment is an
+.CW adt
+and the right side is a tuple, then the assignment
+assigns the members of the tuple to the
+.CW adt
+data members; these must correspond in number and type
+with the members of the tuple.
+.PP
+The constant
+.CW nil
+may be assigned to an lvalue of any reference type.
+This lvalue will compare equal to
+.CW nil
+until it is subsequently reassigned.
+Such an assignment also
+triggers the removal of the object referred to unless other references
+to it remain.
+.PP
+The left operand of an assignment may be the constant
+.CW nil
+to indicate that a value is discarded.
+This applies in particular to any of the lvalues in
+a tuple appearing on the left; to extend the examples above,
+.P1
+	(x, nil) = p;
+.P2
+assigns the
+.CW x
+member of the Point
+.CW p
+to the variable
+.CW x .
+.PP
+A special consideration applies to
+strings.
+If an
+.CW int
+containing a Unicode character is assigned to a subscripted
+string, the subscript
+is normally required to lie within the string.
+As a special case, the subscript's value may be equal to
+the length of the string (that is, just beyond its end);
+in this case, the character is appended to
+the string, and the string's length increases by 1.
+.PP
+A final special case applies to array slices in the form
+.CW e1[e2:] .
+Such expressions may lie on the left of
+.CW = .
+The right side must be an array of the same type as
+.CW e1 ,
+and its length must be less than or equal to
+.CW "(len e1)-e2.
+In this case, the
+elements in the array on the right replace the elements of
+.CW e1
+starting at position
+.CW e2 .
+The length of the array is unchanged.
+.NH 3
+Compound assignments
+.PP
+A compound assignment with
+.I op\f(CW=\fP
+is interpreted in terms of the plain assignment;
+.P1
+	e1 \fIop\f(CW= e2;
+.P2
+is equivalent to
+.P1
+	e1 \f(CW= (e1) \fIop \f(CW(e2);
+.P2
+except that
+.CW e1
+is evaluated only once.
+.NH 3
+Send expressions
+.PP
+A
+.I send-expression
+takes the form
+.s1
+send-expression:
+	lvalue-expressionC <- = Iexpression
+.s2
+In the expression
+.P1
+	e1 <- = e2
+.P2
+the lvalue
+.CW e1
+must have type
+.CW chan
+.CW of
+.I type ,
+and
+.CW e2
+must be of that type.
+The value of
+.CW e2
+is sent over the channel.
+If no task is executing a
+channel receive operation on the specified channel, and the channel is unbuffered or its buffer
+is full, the sender blocks.
+Task synchronization is discussed in §9.8 and §9.13 below.
+.NH 3
+Declare-expressions
+.PP
+A
+.I declare-expression
+is an assignment that also declares identifiers on its left:
+.s1
+declare-expression:
+	lvalue-expressionC := Iexpression
+.s2
+Each of the constituent terms in the
+.I lvalue-expression
+must be an identifier or
+.CW nil .
+A plain identifier on the left
+is declared as having the type of the expression,
+and it is initialized with the expression's value.
+When a parenthesized list of identifiers is given, the expression
+must be a tuple or an
+.CW adt ,
+and the individual identifiers in the list are declared and initialized
+with the members of the tuple, or the data members of the
+.CW adt .
+As with ordinary assignments, the keyword
+.CW nil
+may stand for an identifier whose declaration and assignment
+are skipped.
+.PP
+The value and type of a declare-expression are the same as those of the expression.
+.NH 3
+Load expressions
+.PP
+A
+.I load-expression
+has the form
+.s1
+load-expression:
+	Cload Iidentifier expression
+.s2
+The identifier is the identifier of a module, that is, the type
+name declared in a
+.CW module
+declaration.
+The expression following
+.CW load
+has type
+.CW string
+and names a file containing the
+compiled form of the module.
+The
+.CW load
+expression yields a handle for referring to the functions provided
+by a module and its
+.CW adt .
+.PP
+Execution of
+.CW load
+brings the file containing the module into local memory and dynamically type-checks
+its interface: the run-time system ascertains that
+the declarations exported by the module are compatible
+with the module declaration visible in the scope of the
+.CW load
+operator (see §11.2).
+In the scope of a module declaration, the types and constants
+exported by the module may be referred to without a handle, but
+the functions and data exported by the module
+(directly at its top level, or within its
+.CW adt )
+may be called only using a valid
+handle acquired by the
+.CW load
+operator.
+.PP
+The value of
+.CW load
+is
+.CW nil
+if the attempt to load fails, either because the file containing
+the module can not be found, or because the found module does not
+export the specified interface.
+.PP
+Each evaluation of
+.CW load
+creates a separate instance of the specified module;
+it does not share data with any other instance.
+.NH 2
+Constant expressions
+.PP
+In several places a constant expression is required.
+Such an expression contains operands that are
+identifiers previously declared with
+.CW con ,
+or
+.CW int ,
+.CW big ,
+.CW real ,
+or
+.CW string
+constants.
+These may be connected by any of the following operators:
+.P1
+.ta .5i 1i 1.5i 2i 2.5i 3i 3.5i 4i 4.5i 5i 5.5i
+	+	-	*	/	%	&	|	^
+	==	<	>	<=	>=	!=	<<	>>
+	&&	||
+	~	!
+.P2
+together with arithmetic and string casts, and parentheses for
+grouping.
+.NH 2
+Expression evaluation
+.PP
+Expressions in Limbo are not reordered by the compiler;
+values are computed in accordance with the parse of the expression.
+However there is no guarantee of temporal evaluation order for expressions
+with side effects, except in the following circumstances:
+function arguments are fully evaluated before the function
+is called; the logical operators
+.CW &&
+and
+.CW ||
+have fully defined order of evaluation, as explained above.
+All side effects from an expression in one statement are
+completed before the next statement is begun.
+.PP
+In an expression containing a constant subexpression (in the
+sense of §8.5), the constant subexpression is evaluated at
+compile-time with all exceptions ignored.
+.PP
+Underflow, overflow, and zero-divide conditions during integer
+arithmetic produce undefined results.
+.PP
+The
+.CW real
+arithmetic of Limbo is all performed in IEEE double precision,
+although denormalized numbers may not be supported.
+By default,
+invalid operations, zero-divide, overflow, and underflow
+during real arithmetic are fatal; inexact-result is quiet.
+The default rounding mode is round-to-nearest-even.
+A set of routines in the
+.CW Math
+library module permits independent control of these modes within each thread.
+.NH 1
+Statements
+.PP
+The executable code within a function definition consists
+of a sequence of statements and declarations.
+As discussed in the Scope section §11 below,
+declarations become effective at the place they appear.
+Statements are executed in sequence except as discussed below.
+In particular, the optional labels on some of the statements are used with
+.CW break
+and
+.CW continue
+to exit from or re-execute the labeled statement.
+.s1
+statements:
+	(empty)
+	statements declaration
+	statements statement
+
+statement:
+	expressionC ;I
+	C;I
+	C{ IstatementsC }I
+	Cif ( IexpressionC ) Istatement
+	Cif ( IexpressionC ) IstatementC else Istatement
+	labelO  Cwhile ( IexpressionOC ) Istatement
+	labelO  Cdo IstatementC while ( IexpressionOC ) ;I
+	labelO  Cfor ( IexpressionOC ; IexpressionOC ; IexpressionOC ) Istatement
+	labelO  Ccase IexpressionC { Iqual-statement-sequenceC }I
+	labelO  Calt { Iqual-statement-sequenceC }I
+	labelO  Cpick IidentifierC := IexpressionC { Ipqual-statement-sequenceC }I
+	Cbreak IidentifierOC ;I
+	Ccontinue IidentifierOC ;I
+	Creturn IexpressionOC ;I
+	Cspawn ItermC ( Iexpression-listOC ) ;I
+	Cexit ;I
+	C{ IstatementsC } exceptionI identifierOC{ Iqual-statement-sequenceC }I
+	Craise IexpressionOC ;I
+.s2
+.s1
+label:
+	identifier C:I
+.s2
+.NH 2
+Expression statements
+.PP
+Expression statements consist of an expression followed by
+a semicolon:
+.s1
+	expressionC ;I
+.s2
+Most often expression statements are assignments, but other expressions
+that cause effects are often useful, for example calling a function
+or sending or receiving on a channel.
+.NH 2
+Null statement
+.PP
+The null statement consists of a lone semicolon.
+It is most useful for supplying an empty body
+to a looping statement with internal side effects.
+.NH 2
+Blocks
+.PP
+Blocks are
+.I statements
+enclosed in
+.CW {}
+characters.
+.s1
+	C{ IstatementsC }I
+.s2
+A block starts a new scope.
+The effect of any declarations within a block disappears
+at the end of the block.
+.NH 2
+Conditional statements
+.PP
+The conditional statement takes two forms:
+.s1
+	Cif ( IexpressionC ) Istatement
+	Cif ( IexpressionC ) IstatementC else Istatement
+.s2
+The
+.I expression
+is evaluated; it must have type
+.CW int .
+If it is non-zero, then the first
+.I statement
+is executed.
+In the second form, the second
+.I statement
+is executed if the
+.I expression
+is 0.
+The statement after
+.CW else
+is connected to the nearest
+.CW else -less
+.CW if .
+.NH 2
+Simple looping statements
+.PP
+The simple looping statements are
+.s1
+	labelO  Cwhile ( IexpressionOC ) Istatement
+	labelO  Cdo IstatementC while ( IexpressionOC ) ;I
+.s2
+In both cases the expression must be of type
+.CW int .
+In the first form, the
+.I expression
+is first tested against 0;
+while it is not equal, the
+.I statement
+is repeatedly executed.
+In the second form, the
+.I statement
+is executed, and then, while the
+.I expression
+is not 0, the statement is repeatedly executed.
+If the
+.I expression
+is missing, it is understood to be non-zero.
+.NH 2
+.CW for
+statement
+.PP
+The
+.CW for
+statement has the form
+.s1
+	labelO  Cfor ( Iexpression-1OC ; Iexpression-2OC ; Iexpression-3OC ) Istatement
+.s2
+It is equivalent to
+.s1
+	expression-1C ;I
+	Cwhile ( Iexpression-2C ) {
+		Istatement
+		expression-3C ;
+	C}I
+.s2
+in the absence of
+.CW continue
+or
+.CW break
+statements.
+Thus (just as in C), the first expression is an initialization,
+the second a test for starting and continuing the loop, and the third
+a re-initialization for subsequent travels around the loop.
+.NH 2
+.CW case
+statement
+.PP
+The
+.CW case
+statement transfers control to one of several places
+depending on the value of an expression:
+.s1
+	labelO  Ccase IexpressionC { Iqual-statement-sequenceC }I
+.s2
+The expression must have type
+.CW int ,
+.CW big
+or
+.CW string .
+The
+.CW case
+statement is followed by sequence of
+qualified statements, which are statements labeled by
+expressions or expression ranges:
+.s1
+qual-statement-sequence:
+	qual-listC =>I
+	qual-statement-sequence qual-listC =>I
+	qual-statement-sequence statement
+	qual-statement-sequence declaration
+
+qual-list:
+	qualifier
+	qual-listC or Iqualifier
+
+qualifier:
+	expression
+	expressionC to Iexpression
+	C*I
+.s2
+A
+.I qual-statement-sequence
+is a sequence of
+statements and declarations, each of which
+is preceded by one or more qualifiers.
+Syntactically, the qualifiers are
+expressions, expression ranges with
+.CW to ,
+or
+.CW * .
+If the expression mentioned after
+.CW case
+has
+.CW int
+or
+.CW big
+type,
+all the expressions appearing in the qualifiers
+must evaluate to integer constants of the same type (§8.5).
+If the expression has
+.CW string
+type, all the qualifiers must be
+string constants.
+.PP
+The
+.CW case
+statement is executed by comparing
+the expression at its head with the constants
+in the qualifiers.
+The test is for equality in the case
+of simple constant qualifiers;
+in range qualifiers, the test determines
+whether the expression is greater than or
+equal to the first constant and less than
+or equal to the second.
+.PP
+None of the ranges or constants may overlap.
+If no qualifier is selected and
+there is a
+.CW *
+qualifier,
+then that qualifier is selected.
+.PP
+Once a qualifier is selected, control passes
+to the set of statements headed by that
+qualifier.
+When control reaches the end of that set
+of statements, control passes to the end
+of the
+.CW case
+statement.
+If no qualifier is selected, the
+.CW case
+statement is skipped.
+.PP
+Each qualifier and the statements following it
+up to the next qualifier together form a separate
+scope, like a block; declarations within this scope
+disappear at the next qualifier (or at the end of
+the statement.)
+.PP
+As an example, this fragment separates small numbers
+by the initial letter of their spelling:
+.P1
+	case i {
+	1 or 8 =>
+		sys->print("Begins with a vowel\en)";
+	0 or 2 to 7 or 9 =>
+		sys->print("Begins with a consonant\en");
+	* =>
+		sys->print("Sorry, didn't understand\en");
+	}
+.P2	
+.NH 2
+.CW alt
+statement
+.PP
+The
+.CW alt
+statement transfers control to one of several groups
+of statements depending on the readiness of communication
+channels.
+Its syntax resembles that of
+.CW case :
+.s1
+	labelO  Calt { Iqual-statement-sequenceC }I
+.s2
+However, the qualifiers take a form different
+from those of
+.CW case .
+In
+.CW alt ,
+each qualifier must be a
+.CW * ,
+or an expression containing a communication
+operator
+.CW <-
+on a channel;
+the operator may specify either sending or receiving.
+For example,
+.P1
+	outchan := chan of string;
+	inchan := chan of int;
+	alt {
+	i := <-inchan =>
+		sys->print("Received %d\en", i);
+
+	outchan <- = "message" =>
+		sys->print("Sent the message\en");
+	}
+.P2
+The
+.CW alt
+statement is executed by testing each of
+the channels mentioned in the
+.I qual-list
+expressions for ability to send or receive,
+depending on the operator;
+if none is ready, the program blocks
+until at least one is ready.
+Then a random choice from the ready channels is selected
+and control passes to the associated set
+of statements.
+.PP
+If a qualifier of the form
+.CW *
+is present, then the statement does not block;
+if no channel is ready the statements associated with
+.CW *
+are executed.
+.PP
+If two communication operators are present
+in the same qualifier expression, only the leftmost one is
+tested by
+.CW alt .
+If two or more
+.CW alt
+statements referring to the same receive (or send)
+channel are executed in different
+threads, the requests are queued;
+when the channel becomes unblocked, the thread
+that executed
+.CW alt
+first is activated.
+.PP
+As with
+.CW case ,
+each qualifier and the statements following it
+up to the next qualifier together form a separate
+scope, like a block; declarations within this scope
+disappear at the next qualifier (or at the end of
+the statement.)
+Thus, in the example above, the scope of
+.CW i
+in the arm
+.P1
+		i := <-inchan =>
+			sys->print("Received %d\en", i);
+.P2
+is restricted to these two lines.
+.PP
+As mentioned in the specification
+of the channel receive operator
+.CW <-
+in §8.2.8, that operator can take an array of channels as an argument.
+This notation serves as a kind of simplified
+.CW alt
+in which all the channels have the same type
+and are treated similarly.
+In this variant,
+the value of the communication expression is a tuple
+containing the index of the
+channel over which a communication was received and
+the value received.
+For example, in
+.P1
+	a: array [2] of chan of string;
+	a[0] = chan of string;
+	a[1] = chan of string;
+	. . .
+	(i, s) := <- a;
+	# s has now has the string from channel a[i]
+.P2
+the
+.CW <-
+operator waits until at least one of the
+members of
+.CW a
+is ready, selects one of them at random,
+and returns the index and the transmitted string
+as a tuple.
+.PP
+During execution of an
+.CW alt ,
+the expressions in the qualifiers are evaluated in an undefined
+order, and in particular subexpressions may be evaluated before
+the channels are tested for readiness.
+Therefore qualifying expressions should not invoke side effects,
+and should avoid subparts that might delay execution.
+For example, in the qualifiers
+.P1
+	ch <- = getchar() =>	# Bad idea
+	ich <- = next++ =>	# Bad idea
+.P2
+.CW getchar()
+may be called early in the elaboration of the
+.CW alt
+statement; if it delays, the entire
+.CW alt
+may wait.
+Similarly, the
+.CW next++
+expression may be evaluated before testing the readiness of
+.CW ich .
+.NH 2
+.CW pick
+statement
+.PP
+The
+.CW pick
+statement transfers control to one of several groups of statements
+depending upon the resulting variant type of a
+.CW pick
+.CW adt
+expression. The syntax resembles that of
+.CW case :
+.s1
+	labelO  Cpick IidentifierC := IexpressionC { Ipqual-statement-sequenceC }I
+.s2
+The expression must have type
+.CW ref
+.CW adt
+and the
+.CW adt
+must be a
+.CW pick
+.CW adt .
+The
+.CW pick
+statement is followed by a sequence of qualified statements, which are
+statements labeled by the
+.CW pick
+variant names:
+.s1
+pqual-statement-sequence:
+	pqual-listC =>I
+	pqual-statement-sequence pqual-listC =>I
+	pqual-statement-sequence statement
+	pqual-statement-sequence declaration
+
+pqual-list:
+	pqualifier
+	pqual-listC or Ipqualifier
+
+pqualifier:
+	identifier
+	C*I
+.s2
+A
+.I pqual-statement-sequence
+is a sequence of statements and declarations, each of which
+is preceded by one or more qualifiers.
+Syntactically, the qualifiers are identifiers, identifier lists (constructed with
+.CW or ),
+or
+.CW * .
+The identifiers must be names of the variant types of the
+.CW pick
+.CW adt .
+The
+.CW pick
+statement is executed by comparing the variant type of the
+.CW pick
+.CW adt
+referenced by the expression at its head with the variant type names in the qualifiers.
+The matching qualifier is selected.
+None of the variant type names may appear more than once.
+If no qualifier is selected and there is a
+.CW *
+qualifier, then that qualifier is selected.
+.PP
+Once a qualifier is selected, control passes
+to the set of statements headed by that qualifier.
+When control reaches the end of that set of statements,
+control passes to the end of the
+.CW pick
+statement.
+If no qualifier is selected, the
+.CW pick
+statement is skipped.
+.PP
+Each qualifier and the statements following it
+up to the next qualifier together form a separate
+scope, like a block; declarations within this scope
+disappear at the next qualifier (or at the end of
+the statement.)
+.PP
+The
+.I identifier
+and
+.I expression
+given in the
+.CW pick
+statement are used to bind a new variable to a
+.CW pick
+.CW adt
+reference expression, and within the statements associated with the
+selected qualifier the variable can be used as if it were of the corresponding
+variant type.
+.PP
+As an example, given a
+.CW pick
+.CW adt
+of the following form:
+.P1
+	Constant: adt {
+		name: string;
+		pick {
+			Str or Pstring =>
+				s: string;
+			Real =>
+				r: real;
+		}
+	};
+.P2
+the following function could be used to print out the value of
+an expression of type
+.CW "ref Constant" :
+.P1
+	printconst(c: ref Constant)
+	{
+		sys->print("%s: ", c.name);
+		pick x := c {
+		Str =>
+			sys->print("%s\en", x.s);
+		Pstring =>
+			sys->print("[%s]\en", x.s);
+		Real =>
+			sys->print("%f\en", x.r);
+		};
+	}
+.P2
+.NH 2
+.CW break
+statement
+.PP
+The
+.CW break
+statement
+.s1
+	Cbreak IidentifierO C;I
+.s2
+terminates execution of
+.CW while ,
+.CW do ,
+.CW for ,
+.CW case ,
+.CW alt ,
+and
+.CW pick
+statements.
+Execution of
+.CW break
+with no identifier
+transfers control to
+the statement after the innermost
+.CW while ,
+.CW do ,
+.CW for ,
+.CW case ,
+.CW alt ,
+or
+.CW pick
+statement in which it appears as a substatement.
+Execution of
+.CW break
+with an identifier
+transfers control to the next statement after the unique enclosing
+.CW while ,
+.CW do ,
+.CW for ,
+.CW case ,
+.CW alt ,
+or
+.CW pick
+labeled with that identifier.
+.NH 2
+.CW continue
+statement
+.PP
+The
+.CW continue
+statement
+.s1
+	Ccontinue IidentifierO C;I
+.s2
+restarts execution of
+.CW while ,
+.CW do ,
+and
+.CW for
+statements.
+Execution of
+.CW continue
+with no identifier
+transfers control to the end of
+the innermost
+.CW while ,
+.CW do ,
+or
+.CW for
+statement in which the
+.CW continue
+appears as a substatement.
+The expression that controls the loop is tested
+and if it succeeds, execution continues in the loop.
+The initialization portion of
+.CW for
+is not redone.
+.PP
+Similarly, execution of
+.CW continue
+with an identifier transfers control to the end of the enclosing
+.CW while ,
+.CW do ,
+or
+.CW for
+labeled with the same identifier.
+.NH 2
+.CW return
+statement
+.PP
+The
+.CW return
+statement,
+.s1
+	Creturn IexpressionOC ;I
+.s2
+returns control to the caller of a function.
+If the function returns a value (that is, if its definition
+and declaration mention a return type),
+the expression must be given and it must have the same type that the
+function returns.
+If the function returns no value, the expression
+must generally be omitted.
+However, if a function returns no value, and its
+last action before returning is to call
+another function with no value, then it may
+use a special form of
+.CW return
+that names the function being called.
+For example,
+.P1
+	f, g: fn(a: int);
+	f(a: int) {
+		. . .
+		return g(a+1);
+	}
+.P2
+is permitted.
+Its effect is the same as
+.P1
+	f(a: int) {
+		. . .
+		g(a+1);
+		return;
+	}
+.P2
+This
+.I "ad hoc
+syntax offers the compiler a cheap opportunity to recognize
+tail-recursion.
+.PP
+Running off the end of a function is equivalent to
+.CW return
+with no expression.
+.NH 2
+.CW spawn
+statement
+.PP
+The
+.CW spawn
+statement creates a new thread of control.
+It has the form
+.s1
+	Cspawn ItermC ( Iexpression-listOC ) ;I
+.s2
+The term and expression-list are taken to be
+a function call.
+Execution of
+.CW spawn
+creates an asynchronous, independent thread
+of control, which calls the function in the new thread context.
+This function may access the accessible objects
+in the spawning thread; the two threads share
+a common memory space.
+These accessible objects include the data global to
+the current module and reference data passed to the
+spawned function.
+Threads are preemptively scheduled, so that
+changes to objects used in common between
+threads may occur at any time.
+The Limbo language provides no explicit synchronization
+primitives; §12.3 shows examples of how to use channel
+communication to control concurrency.
+.NH 2
+.CW exit
+statement
+.PP
+The
+.CW exit
+statement
+.s1
+	Cexit ;I
+.s2
+terminates a thread and frees any resources
+belonging exclusively to it.
+.NH 2
+.CW raise
+statement
+.PP
+The
+.CW raise
+statement
+.s1
+	Craise IexpressionOC ;I
+.s2
+raises an exception in a thread.
+The
+.I expression
+is either a string describing the failure, or an exception name and its parameter values, if any.
+If an expression is not given, the
+.CW raise
+statement must appear in the body of an exception handler; it raises the currently active exception.
+.NH 2
+Exception handler
+.PP
+Various errors in a Limbo program can be detected only at run-time.
+These include programming errors such as an attempt to index outside the bounds of an array,
+system errors such as exhausting memory, and user-defined exceptions
+declared at compile-time by exception declarations and caused at run-time by the
+.CW raise
+statement.
+A group of statements can have an associated exception handler:
+.s1
+	C{ IstatementsC } exceptionI identifierOC{ Iqual-statement-sequenceC }I
+.s2
+The first run-time exception raised by any of the
+.I statements ,
+or functions they call,
+that is not handled by an exception handler enclosing the statement raising the exception
+will terminate execution of the
+.I statements
+at that point, and transfer control to the clause in the sequence of qualified statements
+that matches the exception.
+An exception represented by a string is matched by a qualifier that is either the same
+string value, or a prefix of it followed by
+.CW * .
+The optional identifier following
+.CW exception
+is set to the value of the exception string for the execution of the qualified statement.
+If execution of the qualified statement completes, control passes to the statement following
+the exception-handling statement.
+.PP
+A qualified statement labeled by a user-defined exception name matches that exception.
+If the exception has parameters, the identifier following
+.CW exception
+will be be declared and initialized as a tuple of the parameter values for the scope
+of the qualified statement, allowing the values to be recovered by tuple assigment.
+.PP
+The qualifier
+.CW *
+matches any string or user-defined exception.
+An exception that is raised and not successfully handled by a thread will terminate the thread.
+.NH
+Referring to modules;
+.CW import
+.PP
+As discussed above, modules present
+constants, functions, and types
+in their interface.
+Their names may be the same as names
+in other modules or of local objects or types within
+a module that uses another.
+Name clashes are avoided because references
+to the entities presented by a module are
+qualified by the module type name or an object
+of that module type.
+.PP
+For example,
+after the module and variable declarations
+.P1
+	M: module {
+		One: con 1;
+		Thing: adt {
+			t: int;
+			f: fn();
+		};
+		g: fn();
+	};
+	m: M;
+.P2
+the name
+.CW One
+refers to the constant defined in
+module
+.CW M
+only in the contexts
+.CW M->One
+or
+.CW m->One ;
+the name
+.CW Thing
+as the particular data type
+associated with the
+.CW M
+module can be referred to only in contexts
+like
+.P1
+	th1: M->Thing;
+	th2: m->Thing;
+.P2
+Finally, to call a function defined either as a top-level
+member of the module, or as a member of one of its
+.CW adt ,
+it is necessary to declare, and also dynamically initialize using
+.CW load ,
+a handle for the module.
+Then calls of the form
+.P1
+	m->g();
+	m->th1.f();
+.P2
+become appropriate.
+It is possible to use just the type name of a module to qualify
+its constants and types because constants and types can be understood
+without having the code and data present.
+Calling a function declared by a module or one of its
+.CW adt
+requires loading the module.
+.PP
+The
+.CW import
+declaration
+.s1
+	Iidentifier-listC : import Iidentifier C;I
+.s2
+lifts the identifiers in the
+.I identifier-list
+into the scope in which
+.CW import
+appears, so that they are usable without a qualifier.
+The identifier after the
+.CW import
+keyword is either
+a module identifier, or an identifier declared as having
+that type.
+The initial list of identifiers specifies those
+constants,
+types,
+and functions of the module whose names are promoted.
+In the case of constants and types,
+.CW import
+merely makes their names accessible without using a qualifier.
+In the example above, if the
+.CW module
+declaration above had been followed by
+.P1
+	One, Thing: import M;
+.P2
+then one could refer to just
+.CW One
+instead of
+.CW M->One ;
+similarly an object could be declared like
+.P1
+	th: Thing;
+.P2
+For functions, and also
+.CW adt
+with functions as members,
+.CW import
+must specify a module
+variable (as opposed to a module identifier).
+Each imported name is associated with the specified module
+variable, and the current value of this module variable
+controls which instance of the module will
+be called.
+For example, after
+.P1
+	g, Thing: import m;
+.P2
+then
+.P1
+	g();
+.P2
+is equivalent to
+.P1
+	m->g();
+.P2
+and
+.P1
+	th: Thing;
+	th.f();
+.P2
+is equivalent to
+.P1
+	th: M->Thing;
+	m->th.f();
+.P2
+When the module declaration for the module being
+implemented is encountered, an implicit
+.CW import
+of all the names of the module is executed.
+That is, given
+.P1
+	implement Mod;
+	. . .
+	Mod: module {
+		. . .
+	};
+.P2
+the constants and types of
+.CW Mod
+are accessed as if they had been imported;
+the functions declared in
+.CW Mod
+are imported as well, and refer dynamically to the
+current instance of the module being implemented.
+.NH
+Scope
+.PP
+The scope of an identifier is the lexical range of
+a program throughout which the identifier means a particular
+type of, or instance of, an object.
+The same identifier may be associated with several
+different objects in different parts of the same program.
+.PP
+The names of members of an
+.CW adt
+occupy a separate, nonconflicting space from other identifiers;
+they are declared in a syntactically distinct position,
+and are always used in a distinguishable way, namely
+after the
+.CW .
+selection operator.
+Although the same scope rules apply to
+.CW adt
+members as to other identifiers, their names may
+coincide with other entities in the same scope.
+.PP
+Similarly, the names of constants, functions, and
+.CW adt
+appearing
+within a
+.CW module
+declaration are ordinarily qualified either with
+the name of the module or with a module variable
+using the
+.CW ->
+notation.
+As discussed above, the
+.CW import
+declaration lifts these names into the current scope.
+.PP
+Identifiers declared in a top-declaration
+(§5) have scope that lasts from the
+declaration throughout the remainder of the
+file in which it occurs, unless it is overridden
+by a redeclaration of that name within an inner
+scope.
+Each function definition, and each block
+within a function,
+introduces a new scope.
+A name declared within the block or function
+(including a formal argument name of a function)
+has a scope that begins
+at the completion of its declaration and lasts until
+the end of the block or function.
+If an already-declared identifier is redeclared within
+such an inner scope, the declaration previously in
+force is used in any initialization expression
+that is part of the new declaration.
+.PP
+As discussed above, within
+.CW case
+.CW alt
+and
+.CW pick ,
+each qualifier
+and the statements following it form an inner
+scope just like a block.
+.PP
+The scope of a label is restricted to the
+labeled statement,
+and label names may coincide with those of other
+entities in the same scope.
+.NH 2
+Forward referencing
+.PP
+In general, names must be declared before they are used.
+.PP
+The first exception to this rule is that a
+function local to a module need not have a
+declaration at all; it is sufficient to give
+its definition, and that definition may appear anywhere
+in the module.
+.PP
+The general rule implies that no
+.CW adt
+may contain, as a member, an
+.CW adt
+not previously declared (including an instance of itself).
+A second exception to this rule applies to
+.CW ref
+.CW adt
+types.
+An
+.CW adt
+may contain a member whose type is a
+.CW ref
+to itself, or to another
+.CW adt
+even if the second
+.CW adt
+has not yet been declared.
+.PP
+For example, a tree structure where nodes contain references to children can be declared and created as follows:
+.P1
+	Tree: adt {
+		l: ref Tree;
+		r: ref Tree;
+		v: int;
+	};
+
+	t1a := ref Tree(nil, nil, 0);
+	t1b := ref Tree(nil, nil, 1);
+	t1c := ref Tree(nil, nil, 2);
+	t2 := Tree(t1a, t1b, 0);
+	t2.l = t1c;	# replace reference to t1a by reference to t1c
+.P2
+The tree structure resulting above is non-circular, since no
+.CW adt
+value refers back to itself directly or indireclty.
+Circular data structures can also be created. For example,
+.P1
+	Graph: adt {
+		next: ref Graph;
+		v: int;
+	};
+
+	g1 := ref Graph(nil, 0);
+	g2 := ref Graph(g1, 1);
+	g1.next = g2;
+.P2
+creates a pair of nodes that refer to each other.
+.PP
+Limbo implementations guarantee to
+destroy all data objects not involved in circular data structures
+immediately after they become non-referenced by active
+tasks, whether because
+their names go out of scope or because they are assigned new values.
+This property has visible effect because certain system resources,
+like windows and file descriptors, can be seen outside the program.
+In particular, if a reference to such a resource is held only within an
+.CW adt ,
+then that resource too is destroyed when the
+.CW adt
+is.
+Circular data structures can also be created.
+When they become unreferenced except by themselves, they will
+be garbage-collected eventually, but not instantly.
+.PP
+An earlier version of the language required circular references to be annoted by the word
+.CW cyclic ,
+but that is no longer required.
+The notation can still be seen in some system source code, because the
+.CW cyclic
+qualifier is taken into account in type checking, as described below, and some instances remain to provide backward compatibility.
+.NH 2
+Type equality and compatibility
+.PP
+In an assignment and in passing an actual argument to a function,
+the types of the target and the expression being assigned or
+passed must be equal (with certain exceptions, e.g. assignment of
+.CW nil
+to a reference type).
+When a function is defined, its type must be equal to the type
+of a function with the same name if one is in scope.
+Type equality is determined as follows.
+.PP
+Two basic types are equal if and only if they are identical.
+.PP
+Two tuple types are equal if and only if they are composed
+of equal types in the same order.
+.PP
+Two array types are equal if and only if they are arrays
+of equal types.
+The size of an array is not part of its type.
+.PP
+Two list types are equal if and only if they are composed
+of equal types.
+.PP
+Two channel types are equal if and only if they transmit
+equal types.
+.PP
+Two
+.CW adt
+types are equal if and only if their data members
+have the same names and correspondingly
+equal types, including any
+.CW cyclic
+attribute.
+The order of member declaration is insignificant, and
+constant and function members of an
+.CW adt
+do not enter into the comparison,
+nor does the name of the
+.CW adt
+type itself.
+In particular, with the declarations
+.P1
+	A: adt { x: ref B; };
+	B: adt { x: ref A; };
+.P2
+the types
+.CW A
+and
+.CW B
+are equal.
+.PP
+Two
+.CW ref
+.CW adt
+types are equal if and only if they are references to equal
+.CW adt
+types.
+.PP
+Two module types are equal if and only if their data and function members
+have the same names and correspondingly equal types; the order
+of their mention is insignificant.
+Constant members and type members do not enter into the comparison.
+.PP
+Two function types are equal if and only if their return
+values have the same type
+and their argument lists have correspondingly equal types.
+Any
+.CW self
+attributes given to arguments must match.
+Names given to arguments do not enter into the comparison.
+.PP
+A type name has the same type as the type from
+which it was constructed.
+.PP
+When a module is loaded, the module stored
+in the file system must have a type that is
+.I compatible
+with the type mentioned in the
+.CW load
+expression.
+The type of the stored module
+type is compatible with the mentioned type if and only if
+all data members of the two types are equal in name and type,
+and all
+.CW adt
+or functions actually mentioned by the program executing
+.CW load
+have names and types equal to corresponding members of
+the stored module.
+.NH
+Examples
+.PP
+Because Limbo was designed for the Inferno environment, several
+of these examples consist of simplified versions of already simple
+Inferno applications in a prototype Inferno implementation.
+Some appreciation for the resources available in this environment
+should become evident, but its full description is available
+elsewhere;
+the discussion here will focus on language features.
+However, several of the programs use facilities
+from the module
+.CW Sys ,
+which provides an interface to a file system and its methods
+resembling those of Unix or Plan 9,
+as well as other useful library facilities.
+.PP
+Some of the programs are annotated with line numbers;
+they are there only for descriptive purposes.
+.NH 2
+A simple command interpreter module
+.PP
+This version of a shell program reads from a keyboard and
+executes `commands' typed by the user.
+Its own interface has the type of a
+.CW Command
+module, and that is the type of the things it executes.
+In particular, it can call modules like the
+.CW hello
+example at the beginning of the paper.
+.P1
+1	implement Command;
+
+2	include "sys.m";
+3	include "draw.m";
+
+4	sys: Sys;
+5	stdin: ref Sys->FD;
+
+6	Command: module
+7	{
+8		init: fn(nil: ref Draw->Context, nil: list of string);
+9	};
+.P2
+After the boilerplate on lines 1-3, the variables
+.CW sys
+and
+.CW stdin
+are declared on lines 4 and 5.
+The I/O operations of the
+.CW Sys
+module use the
+.CW ref
+.CW FD
+type to refer to open files.
+.P1
+10	init(ctx: ref Draw->Context, nil: list of string)
+11	{
+12
+13
+14		buf := array[256] of byte;
+
+15		sys = load Sys Sys->PATH;
+16		stdin = sys->fildes(0);
+
+17		for(;;) {
+18			sys->print("$ ");
+19			n := sys->read(stdin, buf, len buf);
+20			if(n <= 0)
+21				break;
+22			(nw, arg) :=
+			   sys->tokenize(string buf[0:n], " \et\en");
+23			if(nw != 0)
+24				exec(ctx, arg);
+25		}
+26	}
+.P2
+Line 10: conventionally, stand-alone modules are started
+by calling their
+.CW init
+functions.
+The
+.CW Command
+module follows this convention.
+The arguments are presented as a list of strings.
+In this simple example, the command interpreter itself
+ignores its argument, so it need not be given a name.
+.PP
+Local variables are declared on lines 12-14; line 15
+loads the
+.CW Sys
+module and stores a handle for it in the variable
+.CW sys .
+Line 16 creates an
+.CW FD
+for the standard input by calling the
+.CW fildes
+function of the
+.CW Sys
+module using the
+.CW ->
+operator; the notation
+.CW modhandle->func(...)
+specifies a call to the function named
+.CW func
+in the module currently referred to by
+.CW modhandle .
+(In general there can be several modules of the same type and name
+active, and there can also be unrelated modules containing identically
+named functions.
+The
+.CW import
+declaration, described in §6.6 above, can be used to abbreviate
+the references when names do not clash.)
+.PP
+The loop on lines 17-25 prints a prompt (line 18), reads a line from
+the standard input (line 19), parses it into tokens (line 22), and
+executes the command.
+.PP
+The function call
+.CW sys->tokenize
+is worth discussing as an example of style.
+It takes two strings as arguments.
+The characters in the second string are interpreted as separators
+of tokens in the first string.
+It returns a tuple whose first member is the number of
+tokens found, and whose second is a list of strings
+containing the tokens found: its declaration is
+.P1
+	tokenize: fn (s: string, sep: string): (int, list of string);
+.P2
+In the example, the second argument is
+\f(CW" \et\en"\fP,
+so that the routine returns the number of, and a list of,
+`words' separated by blanks, tabs, and new-lines.
+The free use of strings, lists, and tuple-returning
+functions is common in Limbo.
+.PP
+The
+.CW sys->read
+routine gathers an array of bytes into
+.CW buf .
+Thus the expression for the first argument of
+.CW sys->tokenize
+converts this array to a string by slicing the
+array with
+.CW [0:n] ,
+using the actual number of bytes
+gathered by the
+.CW read ,
+and using a cast.
+.PP
+At lines 23-24, if there were any words found,
+.CW exec
+is called:
+.P1
+27	exec(ctx: ref Draw->Context, args: list of string)
+28	{
+29		c: Command;
+30		cmd, file: string;
+
+31		cmd = hd args;
+
+32		file = cmd + ".dis";
+33		c = load Command file;
+34		if(c == nil)
+35			c = load Command "/dis/"+file;
+
+36		if(c == nil) {
+37			sys->print("%s: not found\en", cmd);
+38			return;
+39		}
+40		c->init(ctx, args);
+41	}
+.P2
+On lines 31 and 32 of
+.CW exec ,
+.CW cmd
+is set to the first of the words in the argument list,
+and the string
+.CW .dis
+is concatenated to it (to account for the fact that Limbo
+object program files are conventionally named using this suffix).
+On line 33 an attempt is made to load the named module
+from the derived file name; it will fail if the file
+does not exist.
+The attempt will succeed,
+and a non-nil handle assigned to
+.CW c ,
+if the file is found, and if
+the module stored in that file does in fact implement the
+.CW Command
+module type.
+In case this fails, lines 34-35 make another attempt, after prefixing
+.CW /dis/
+to the file name.
+.PP
+If either attempt to get a handle to the named module
+succeeds,
+.CW c
+will contain a valid handle to it; line 40 calls its
+.CW init
+function, passing it the whole argument list.
+When it returns, the
+.CW exec
+function returns, and the main loop resumes.
+.NH 2
+Infrared remote control
+.PP
+This example shows two instances of a module
+for interfacing to a TV remote control; one
+is for the real remote, which in this case
+is connected to a serial port on a set-top
+box, and the other is simulated for testing
+programs running on a regular operating
+system.
+The techniques of special interest are the
+dynamic use of modules and the communication
+using a channel.
+.PP
+The module is used by creating a channel and passing
+it to the module's
+.CW init
+function,
+which returns a success/error indicator and starts an
+asynchronous process to read the remote control.
+The user of the module executes a receive
+on the channel whenever it wishes to accept
+a button-push.
+.PP
+The (abridged) module declaration is
+.P1
+Ir: module
+{
+	# Codes buttons on IR remote control
+	Zero:	con 0;
+	One:	con 1;
+	. . .
+	Mute:	con 23;
+	Error:	con 9999;
+
+	init: fn(chan of int): int;
+	PATH: con "/dis/ir.dis";
+	SIMPATH: con "/dis/irsim.h";
+};
+.P2
+The implementation for the `real' remote control is
+.P1
+implement Ir;
+
+include "ir.m";
+include "sys.m";
+FD, Dir: import Sys;
+
+sys: Sys;
+
+init(keys: chan of int): int
+{
+	cfd, dfd: ref FD;
+
+	sys = load Sys Sys->PATH;
+
+	cfd = sys->open("/dev/eia1ctl", sys->OWRITE);
+	if(cfd == nil)
+		return -1;
+	sys->fprint(cfd, "b9600");
+
+	dfd = sys->open("/dev/eia1", sys->OREAD);
+	cfd = nil;
+
+	spawn reader(keys, dfd);
+	return 0;
+}
+.P2
+The
+.CW init
+routine accepts a
+.CW chan
+argument; it will be used by the module to
+send codes for the buttons pressed by the user.
+In this routine, the calls to
+.CW sys->open
+and
+.CW sys->fprint
+open and set up the device data and control files
+.CW /dev/eia1
+and
+.CW /dev/eia1ctl
+used to communicate with the device itself.
+The important step is at the end: the
+.CW spawn
+statement creates a new,
+asynchronous task to read the device, using a routine
+that is passed the communications channel and the
+FD for the device:
+.P1
+reader(keys: chan of int, dfd: ref FD)
+{
+	n, ta, tb: int;
+	dir: Dir;
+	b1:= array[1] of byte;
+	b2:= array[1] of byte;
+
+	# find the number of bytes already
+	# queued and flush that many
+	(n, dir) = sys->fstat(dfd);
+	if(n >= 0 && dir.length > 0) {
+		while(dir.length) {
+			n = sys->read(dfd,
+			   array[dir.length] of byte,
+			   dir.length);
+			if(n < 0)
+				break;
+			dir.length -= n;
+		}
+	}
+.P2
+.P1
+loop:	for(;;) {
+		n = sys->read(dfd, b1, len b1);
+		if(n <= 0)
+			break;
+		ta = sys->millisec();
+		# Button pushes are pairs of characters
+		# that arrive closer together than
+		# 200 ms.  Longer than that is likely
+		# to be noise.
+		for(;;) {
+			n = sys->read(dfd, b2, 1);
+			if(n <= 0)
+				break loop;
+			tb = sys->millisec();
+			if(tb - ta <= 200)
+				break;
+			ta = tb;
+			b1[0] = b2[0];
+		}
+		# map the character pair; the significant
+		# bits are the lowest 5.
+		case ((int b1[0]&16r1f)<<5) | (int b2[0]&16r1f) {
+		975 =>	n = Ir->Zero;
+		479 =>	n = Ir->One;
+		. . .
+		791 =>	n = Ir->Mute;
+		* =>	n = Ir->Error;
+		}
+		# found a button-push; send the value
+		keys <-= n;
+	}
+	keys <-= Ir->Error;
+}
+.P2
+The code in the middle is related to noise-filtering
+and is uninteresting in detail except as it illustrates
+some of the methods provided by the
+.CW Sys
+module; the crucial actions are found at the bottom,
+where the routine sends either
+a true button-push or an error code over the channel to
+the module's client.
+.PP
+Here is another implementation of the same interface.
+Its
+.CW init
+function performs the same kind of initialization
+as the other version, but using the operating system's
+keyboard files
+.CW /dev/cons
+and
+.CW /dev/consctl .
+In the Inferno environment, operations corresponding to the Unix
+`stty' primitive are accomplished by writing messages to
+a control file associated with the file that handles the data.
+.P1
+implement Ir;
+
+include "ir.m";
+include "sys.m";
+FD: import Sys;
+
+sys: Sys;
+cctlfd: ref FD;
+
+init(keys: chan of int): int
+{
+	dfd: ref FD;
+
+	sys = load Sys Sys->PATH;
+
+	cctlfd = sys->open("/dev/consctl", sys->OWRITE);
+	if(cctlfd == nil)
+		return -1;
+	sys->write(cctlfd, array of byte "rawon", 5);
+
+	dfd = sys->open("/dev/cons", sys->OREAD);
+	if(dfd == nil)
+		return -1;
+
+	spawn reader(keys, dfd);
+	return 0;
+}
+.P2
+A fine point: the variable
+.CW cctlfd
+that contains the FD for the control device is
+declared external to the
+init function, even though it appears to be used
+only inside it.
+Programming cleanliness suggests that
+its declaration be moved inside, but here that
+won't work;
+device control files
+in Inferno retain settings like `raw mode' only
+while they remain open.
+If
+.CW cctlfd
+were declared inside
+.CW init ,
+then returning from
+.CW init
+would destroy the last reference to the FD for the control file,
+and the device would be closed automatically.
+.PP
+The reader function for this module has the same structure as the first
+example, but doesn't have to worry about a noisy infrared detector:
+.P1
+reader(keys: chan of int, dfd: ref FD)
+{
+	n: int;
+	b:= array[1] of byte;
+
+	for(;;) {
+		n = sys->read(dfd, b, 1);
+		if(n != 1)
+			break;
+		case int b[0] {
+		'0' =>	n = Ir->Zero;
+		'1' =>	n = Ir->One;
+		. . .
+		16r7f =>	n = Ir->Mute;
+		* =>	n = Ir->Error;
+		}
+		keys <-= n;
+	}
+	keys <-= Ir->Error;
+}
+.P2
+The following module can be used to test the above code.
+It simply prints the name of the button that was pressed.
+.P1
+implement Irtest;
+
+include "sys.m";
+include "draw.m";
+FD: import Sys;
+include "ir.m";
+
+Irtest: module
+{
+	init:  fn(nil: ref Draw->Context, nil: list of string);
+};
+ir: Ir;
+sys: Sys;
+.P2
+.P1
+init(nil: ref Draw->Context, nil: list of string)
+{
+	c: int;
+	stderr: ref FD;
+	irchan := chan of int;
+
+	sys = load Sys Sys->PATH;
+	stderr = sys->fildes(2);
+
+	# If the real IR remote application can
+	# be found, use it, otherwise use the simulator:
+	ir = load Ir Ir->PATH;
+	if(ir == nil)
+		ir = load Ir Ir->SIMPATH;
+	if(ir == nil) {
+		# %r format code means the last system error string
+		sys->fprint(stderr, "load ir: %r\en");
+		return;
+	}
+	if(ir->init(irchan) != 0) {
+		sys->fprint(stderr, "Ir.init: %r\en");
+		return;
+	}
+	names := array[] of {
+		"Zero",
+		"One",
+		. . .
+		"Mute",
+	};
+	for(;;) {
+		c = <-irchan;
+		if(c == ir->Error)
+			sys->print("Error %d\en", c);
+		else
+			sys->print("%s\en", names[c]);
+	}
+}
+.P2
+Finally, here is a snippet from a movie application that
+uses the IR module; it demonstrates how
+.CW alt
+is useful for dealing with multiple events.
+This is only one of the functions of the
+movie module, so not everything is defined.
+It uses the
+.CW Mpeg
+module, which actually
+copies the MPEG data stream to the screen
+asynchronously.
+Its
+.CW play
+function takes, as one of its arguments,
+a channel;
+before starting to play it writes a
+string on the channel.
+An empty string indicates success at
+locating the movie; a non-empty
+string contains an error message.
+When it finishes, it writes another string.
+.P1
+movie(entry: ref Dbinfo, cc: chan of int)
+{
+	i: int;
+	m: Mpeg;
+	b: ref Image;
+
+	m = load Mpeg Mpeg->PATH;
+	if (m == nil)
+		return;
+	# make a place on the screen
+	w := screen.window(screen.image.r);
+
+	mr := chan of string;
+	s := m->play(w, 1, w.r, entry.movie, mr);
+	if(s != "")
+		return;
+	# wait for the end of the movie
+	# while watching for button pushes
+	for(;;) {
+		alt {
+		<-mr =>
+			return;
+		i = <-cc =>
+			case i {
+			Ir->Select =>
+				m->ctl("stop");
+			Ir->Up or Ir->Dn =>
+				m->ctl("pause");
+			}
+		}
+	}
+}
+.P2
+.NH 2
+Monitors
+.PP
+Statically allocated storage within a module is accessible to
+all the functions of that module,
+and there is no explicit mechanism in Limbo for synchronizing
+concurrent updates to this storage from several tasks.
+However, it is straightforward to build a variety of concurrency-control
+mechanisms by using channel communications.
+.PP
+An example is a module that implements a
+.CW Monitor
+abstract data type.
+Each instance of
+.CW Monitor
+has a
+.CW lock
+and an
+.CW unlock
+operation;
+calling
+.CW lock
+delays if another task holds the lock; calling
+.CW unlock
+releases the lock and enables any other task attempting
+to execute
+.CW lock .
+.P1
+implement Monitors;
+
+Monitors: module
+{
+	Monitor: adt {
+		create: fn(): Monitor;
+		lock: fn(m: self Monitor);
+		unlock: fn(m: self Monitor);
+		ch: chan of int;
+	};
+};
+.P2
+.P1
+Monitor.create(): Monitor
+{
+	m := Monitor(chan of int);
+	spawn lockproc(m.ch);
+	return m;
+}
+.P2
+.P1
+Monitor.lock(m: self Monitor)
+{
+	m.ch <- = 0;
+}
+.P2
+.P1
+Monitor.unlock(m: self Monitor)
+{
+	<- m.ch;
+}
+.P2
+.P1
+lockproc(ch: chan of int)
+{
+	for (;;) {
+		<- ch;	# wait for someone to lock
+		ch <- = 0; # wait for someone to unlock
+	}
+}
+.P2
+It would be used like this:
+.P1
+mp: Mon;
+Monitor: import mp;
+mp = load Mon "...";
+l := Monitor.create();
+\. . .
+l.lock();
+# region of code to be protected;
+# only one thread can execute here at once.
+l.unlock();
+.P2
+The
+.CW create
+method of
+.CW Monitor
+allocates an instance of a
+.CW Monitor
+containing an initialized channel.
+It also creates a thread executed in the
+.CW lockproc
+routine, which repeatedly reads from the channel,
+then writes on it.
+The values transmitted over the channel are of no
+interest; it is the pure fact of communication that is put to use.
+The
+.CW lock
+routine sends a message; in the idle state, the
+.CW lockproc
+thread reads it and the sender proceeds.
+Meanwhile,
+.CW lockproc
+tries to send a message over the same channel.
+If another thread attempts to
+.CW lock ,
+there is no reader for the channel, and so its transmission will block.
+At some point, the thread that gained the lock
+calls
+.CW unlock ,
+which receives from the channel.
+Depending on timing, this reception enables execution of either
+.CW lockproc
+or one of the threads attempting to send via
+.CW lock .
+.PP
+There is a simpler implementation of
+.CW Monitor ,
+using a buffered channel.
+The
+.CW create
+operation simply allocates a channel with a one-element buffer:
+.P1
+Monitor.create(): Monitor
+{
+	return Monitor(chan[1] of int);
+}
+.P2
+The
+.CW lock
+and
+.CW unlock
+operations have the same implementation.
+Because of the buffer, when a process locks an unlocked
+.CW Monitor ,
+the send succeeds but fills the channel.
+Subsequent attempts to
+.CW lock
+will therefore block as long as the channel is full.
+.CW Unlock
+removes the value from the channel, making it empty,
+and allowing another
+.CW lock
+to proceed.
+The
+.CW lockproc
+is not needed.
+Note that a program using the module would not need to be recompiled to
+use the new implementation, because the module's signature and use
+remains the same.
+This is the implementation of the
+.CW Lock
+module in the Limbo library for Inferno.
+.PP
+Limbo channels are usually unbuffered:
+a sender blocks until there
+is a receiver, and processes synchronise at each communication.
+Buffered channels are used sparingly in Limbo programs, typically to improve throughput or,
+less often, in specialized ways as in the monitor example above.
+.NH 2
+Guarding sends and receives
+.PP
+In some applications, a process takes input from one channel,
+and sends it on to another channel, possibly having transformed it.
+In case the input and output processes run at different rates,
+the process itself acts as a buffer, holding a queue of values internally.
+If the input process were faster than the output process, the queue
+would accumulate values faster than they are consumed, exhausting memory.
+To prevent that, when the queue reaches a specified limit, the process should guard against
+receiving from the input channel, but continue sending to the output channel.
+Conversely, when the queue is empty, it should not attempt to send.
+The
+.CW alt
+statement allows a process to choose between sending and receiving based on
+which channels are ready, but the process must also account for the current state
+of the queue.
+This example shows a way to make a buffered
+channel of strings from an unbuffered channel.
+It is written as a module whose
+.CW bufchan
+function takes a
+.CW chan
+.CW of
+.CW string
+and a size as argument, and returns a new channel;
+it creates an asynchronous task that accepts input from the argument
+channel and saves up to
+.CW size
+strings, meanwhile trying to send them to its user.
+.P1
+implement Bufchan;
+Bufchan: module {
+	bufchan: fn(c: chan of string, size: int): chan of string;
+};
+
+xfer(oldchan, newchan: chan of string, size: int)
+{
+	temp := array[size] of string;
+	fp := 0;        # first string in buffer
+	n := 0;         # number of strings in buffer
+	dummy := chan of string;
+	sendch, recvch: chan of string;
+	s: string;
+
+	for (;;) {
+		sendch = recvch = dummy;
+		if (n > 0)
+			sendch = newchan;
+		if (n < size)
+			recvch = oldchan;
+		alt {
+		s = <-recvch =>
+			temp[(fp+n)%size] = s;
+			n++;
+
+		sendch <- = temp[fp] =>
+			temp[fp++] = nil;
+			n--;
+			if (fp>=size)
+				fp -= size;
+		}
+	}
+}
+.P2
+.P1
+bufchan(oldchan: chan of string, size: int): chan of string
+{
+	newchan := chan of string;
+	spawn xfer(oldchan, newchan, size);
+	return newchan;
+}
+.P2
+The module is somewhat specialized, but it illustrates
+useful programming techniques.
+The most interesting occurs in
+.CW xfer ,
+which does the work.
+The problem
+.CW xfer
+faces is that it doesn't want to receive input when its
+buffer is full, nor to try to send when it has nothing to
+transmit.
+The solution here is to use a dummy channel
+on which nothing is ever sent or received; in the
+.CW alt
+statement,
+that channel substitutes for the real input channel
+when the buffer is full, and for the output channel
+when the buffer is empty.
+.PP
+The module could be used in the following way:
+.P1
+Bufchan: module {
+	PATH: con "/dis/lib/bufchan.dis";
+	bufchan: fn(c: chan of string, size: int): chan of string;
+};
+\. . .
+bufc := load Bufchan Bufchan->PATH;
+sourcech := chan of string;
+
+# ... (here, hand off sourcech to a process that
+#      reads strings from it and copies them to ch)
+ch: chan of string = bufc->bufchan(sourcech, 10);
+\. . .
+s := <- ch;
+\. . .
+.P2
+.NH 1
+Syntax summary
+.PP
+This section summarizes the grammar of Limbo
+above the lexical level; constants and identifiers
+are left undefined.
+.PP
binary files /dev/null b/doc/limbo/limbo.pdf differ
--- /dev/null
+++ b/doc/limbo/limbo.rc
@@ -1,0 +1,20 @@
+#!/bin/rc
+cat limbo.ms synsum | awk 'BEGIN	{ inside = 0 }
+
+		{ if ($1==".s1") {
+			inside = 1;
+		  }
+		  if ($1==".s2") {
+			inside = 0;
+		  }
+		  if (inside) {
+			gsub(/C/, "\\f(CW")
+			gsub(/ID/, "@D")
+			gsub(/I/, "\\fI")
+			gsub(/@D/, "ID")
+			gsub(/O/, "\\fI\\s-3\\v''+2p''opt\\v''-2p''\\s+3")
+		  }
+		  print $0
+		}
+' 
+
--- /dev/null
+++ b/doc/limbo/mkfile
@@ -1,0 +1,12 @@
+<../fonts
+
+all:V: limbo.pdf addendum.pdf
+
+limbo.ps:D:	limbo.ms limbo.rc synsum mkfile
+	rc limbo.rc | troff -mpm | dpost >limbo.ps
+
+%.pdf: %.ps
+	ps2pdf <$stem.ps >$stem.pdf
+
+addendum.ps:D:	addendum.ms mkfile
+	cat addendum.ms |troff -mpm | dpost >$target
--- /dev/null
+++ b/doc/limbo/synsum
@@ -1,0 +1,335 @@
+.s1
+program:
+	Cimplement Iidentifier-listC ; Itop-declaration-sequence
+.s2
+.s1
+top-declaration-sequence:
+	top-declaration
+	top-declaration-sequence top-declaration
+.s2
+.s1
+top-declaration:
+	declaration
+	identifier-listC := IexpressionC ;I
+	identifier-listC = IexpressionC ;I
+	C( Iidentifier-listC ) := IexpressionC ;I
+	module-declaration
+	function-definition
+	adt-declaration
+.s2
+.s1
+declaration:
+	identifier-listC : ItypeC ;I
+	identifier-listC : ItypeC = IexpressionC ;I
+	identifier-listC : con IexpressionC ;I
+	Iidentifier-listC : import Iidentifier C;I
+	identifier-listC : typeI typeC ;I
+	identifier-listC : exceptionI tuple-typeO
+	Cinclude Istring-constantC ;I
+.s2
+.s1
+identifier-list:
+	identifier
+	identifier-listC , Iidentifier
+.s2
+.s1
+expression-list:
+	expression
+	expression-listC , Iexpression
+.s2
+.s1
+type:
+	data-type
+	function-type
+.s2
+.s1
+data-type:
+	CbyteI
+	CintI
+	CbigI
+	CrealI
+	CstringI
+	tuple-type
+	Carray of Idata-type
+	Clist of Idata-type
+	Cchan of Idata-type
+	adt-type
+	Cref Iadt-type
+	Cref Ifunction-type
+	module-type
+	module-qualified-type
+	type-name
+.s2
+.s1
+tuple-type:
+	C( Idata-type-listC )I
+.s2
+.s1
+data-type-list:
+	data-type
+	data-type-list C,I data-type
+.s2
+.s1
+adt-type:
+	identifier
+	module-qualified-type
+.s2
+.s1
+module-type:
+	identifier
+.s2
+.s1
+module-qualified-type:
+	identifier C->I identifier
+.s2
+.s1
+type-name:
+	identifier
+.s2
+.s1
+function-type:
+	Cfn Ifunction-arg-ret
+.s2
+.s1
+function-arg-ret:
+	C( Iformal-arg-listOC ) IraisesO
+	C( Iformal-arg-listOC ) : Idata-type raisesO
+.s2
+.s1
+formal-arg-list:
+	formal-arg
+	formal-arg-listC , Iformal-arg
+.s2
+.s1
+formal-arg:
+	nil-or-ID-listC : Itype
+	nil-or-IDC : self refO Iidentifier
+	nil-or-IDC : self Iidentifier
+	C*I
+.s2
+.s1
+nil-or-ID-list:
+	nil-or-ID
+	nil-or-ID-list C, Inil-or-ID
+.s2
+.s1
+nil-or-ID:
+	identifier
+	CnilI
+.s2
+.s1
+raises:
+	Craises ( Inil-or-ID-listC )I
+	CraisesI nil-or-ID
+.s2
+.s1
+module-declaration:
+	IidentifierC : module { Imod-member-listOC } ;I
+.s2
+.s1
+mod-member-list:
+	mod-member
+	mod-member-list mod-member
+.s2
+.s1
+mod-member:
+	identifier-listC : Ifunction-typeC ;I
+	identifier-listC : Idata-typeC ;I
+	adt-declarationC I
+	identifier-listC : con Iexpression C;I
+	identifier-listC : type Itype C;I
+.s2
+.s1
+adt-declaration:
+	IidentifierC : adt { Iadt-member-listOC } ;I
+.s2
+.s1
+adt-member-list:
+	adt-member
+	adt-member-list adt-member
+.s2
+.s1
+adt-member:
+	identifier-listC : cyclicO  Idata-typeC ;I
+	identifier-listC : con  IexpressionC ;I
+	identifier-listC : Ifunction-typeC ;I
+	Cpick { Ipick-member-listC }I
+.s2
+.s1
+pick-member-list:
+	pick-tag-listC =>I
+	pick-member-list pick-tag-listC =>I
+	pick-member-list identifier-listC : cyclicO  Idata-typeC ;I
+.s2
+.s1
+pick-tag-list:
+	identifier
+	pick-tag-listC or Iidentifier
+.s2
+.s1
+function-definition:
+	function-name-part function-arg-retC { IstatementsC }I
+.s2
+.s1
+function-name-part:
+	identifier
+	function-name-partC . Iidentifier
+.s2
+.s1
+statements:
+	(empty)
+	statements declaration
+	statements statement
+.s2
+.s1
+statement:
+	expressionC ;I
+	C;I
+	C{ IstatementsC }I
+	Cif ( IexpressionC ) Istatement
+	Cif ( IexpressionC ) IstatementC else Istatement
+	labelO  Cwhile ( IexpressionOC ) Istatement
+	labelO  Cdo IstatementC while ( IexpressionOC ) ;I
+	labelO  Cfor ( IexpressionOC ; IexpressionOC ; IexpressionOC ) Istatement
+	labelO  Ccase IexpressionC { Iqual-statement-sequenceC }I
+	labelO  Calt { Iqual-statement-sequenceC }I
+	labelO  Cpick IidentifierC := IexpressionC { Ipqual-statement-sequenceC }I
+	Cbreak IidentifierOC ;I
+	Ccontinue IidentifierOC ;I
+	Creturn IexpressionOC ;I
+	Cspawn ItermC ( Iexpression-listOC ) ;I
+	Cexit ;I
+	Craise IexpressionOC ;I
+	C{ IstatementsC } exceptionI identifierOC{ Iqual-statement-sequenceC }I
+.s2
+.s1
+label:
+	identifier C:I
+.s2
+.s1
+qual-statement-sequence:
+	qual-listC =>I
+	qual-statement-sequence qual-listC =>I
+	qual-statement-sequence statement
+	qual-statement-sequence declaration
+.s2
+.s1
+qual-list:
+	qualifier
+	qual-listC or Iqualifier
+.s2
+.s1
+qualifier:
+	expression
+	expressionC to Iexpression
+	C*I
+.s2
+.s1
+pqual-statement-sequence:
+	pqual-listC =>I
+	pqual-statement-sequence pqual-listC =>I
+	pqual-statement-sequence statement
+	pqual-statement-sequence declaration
+.s2
+.s1
+pqual-list:
+	pqualifier
+	pqual-listC or Ipqualifier
+.s2
+.s1
+pqualifier:
+	identifier
+	C*I
+.s2
+.s1
+expression:
+	binary-expression
+	lvalue-expression assignment-operator expression
+	C( Ilvalue-expression-listC ) = Iexpression
+	send-expression
+	declare-expression
+	load-expression
+.s2
+.s1
+binary-expression:
+	monadic-expression
+	binary-expression binary-operator binary-expression
+.s2
+.s1
+binary-operator: one of
+	C** * / % + - << >> < > <= >= == != & ^ | :: && ||I
+.s2
+.s1
+assignment-operator: one of
+	C= &= |= ^= <<= >>= += -= *= /= %=I
+.s2
+.s1
+lvalue-expression:
+	identifier
+	CnilI
+	termC [ IexpressionC ]I
+	termC [ IexpressionC : ]I
+	termC . Iidentifier
+	C( Ilvalue-expression-listC )I
+	C* Imonadic-expression
+.s2
+.s1
+lvalue-expression-list:
+	lvalue-expression
+	lvalue-expression-listC , Ilvalue-expression
+.s2
+.s1
+expression:
+	term
+	monadic-operator monadic-expression
+	Carray [ IexpressionC ] of Idata-type
+	Carray [ IexpressionOC ] of { Iinit-listC }I
+	Clist of { Iexpression-listC }I
+	Cchan of Idata-type
+	Cchan [ IexpressionOC ] of Idata-type
+	data-type monadic-expression
+.s2
+.s1
+term:
+	identifier
+	constant
+	real-constant
+	string-constant
+	CnilI
+	C( Iexpression-listC )I
+	termC . Iidentifier
+	termC -> Iterm
+	termC ( Iexpression-listOC )I
+	termC [ IexpressionC ]I
+	termC [ IexpressionC : IexpressionC ]I
+	termC [ IexpressionC : ]I
+	termC ++I
+	termC --I
+.s2
+.s1
+monadic-operator: one of
+	C+ - ! ~ ref * ++ -- <- hd tl len tagofI
+.s2
+.s1
+init-list:
+	element
+	init-listC , Ielement
+.s2
+.s1
+element:
+	expression
+	expressionC => Iexpression
+	C* => Iexpression
+.s2
+.s1
+send-expression:
+	lvalue-expressionC <- = Iexpression
+.s2
+.s1
+declare-expression:
+	lvalue-expressionC := Iexpression
+.s2
+.s1
+load-expression:
+	Cload Iidentifier expression
+.s2
binary files /dev/null b/doc/limbotk/f1.gif differ
--- /dev/null
+++ b/doc/limbotk/f1.ps
@@ -1,0 +1,234 @@
+%!
+%%BoundingBox: 0 0 2691 216
+/picstr 299 string def
+2691 216 scale
+299 24 8
+[ 299 0 0 -24 0 24 ]
+{ currentfile picstr readhexstring pop }
+false 3 colorimage
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffff808080ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffff
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffff
+c0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffff
+ffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080
+ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0000000c0c0c0000000000000000000000000c0c0c0c0c0c0000000000000000000c0c0c0000000c0c0c0c0c0c0
+c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0000000
+000000c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000000000000000000000c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000c0c0c0c0c0c0c0c0c0000000000000000000000000000000c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000c0c0c0000000000000000000000000c0c0c0c0c0c0000000c0c0c0000000000000000000000000c0c0c0000000000000000000000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0000000c0c0c0000000000000000000000000
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0
+000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0000000000000000000000000000000
+c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0000000000000000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0
+c0c0c0000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0000000
+000000000000c0c0c0c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0000000000000c0c0c0c0c0c0c0c0c0000000c0c0c0000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0000000c0c0c0c0c0c0c0c0c0000000000000c0c0c0000000000000c0c0c0000000000000c0c0c0000000c0c0c0000000000000000000000000c0c0c0c0c0c0c0c0c0000000000000000000c0c0c0c0c0c0c0c0c0c0c0c0
+000000c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffffc0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0808080ffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0ffffffc0c0c0c0c0c0ffffffffffff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffffffffffff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0c0c0c0c0c0ffffff808080808080808080808080808080808080808080808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffffff808080808080808080808080808080808080
+808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0808080ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+showpage
binary files /dev/null b/doc/limbotk/f2.gif differ
--- /dev/null
+++ b/doc/limbotk/f2.ps
@@ -1,0 +1,2044 @@
+%!
+%%BoundingBox: 0 0 318 216
+/picstr 310 string def
+318 216 scale
+310 210 8
+[ 310 0 0 -210 0 210 ]
+{ currentfile picstr readhexstring pop }
+false 3 colorimage
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0
+c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffff999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+9999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+999999999999ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999ffffffdddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddd000000000000000000000000000000000000000000000000000000000000000000dddddd
+dddddddddddd999999999999ffffffdddddddddddddddddd000000000000000000000000000000000000000000000000000000000000000000000000000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddd000000
+000000dddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffffffffffffffffffffffffff
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffffffff
+ffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddd000000dddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000dddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddd000000000000000000dddddddddddddddddddddddd000000000000000000dddddd
+dddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddd
+dddddddddddddddddddddddddddddd000000dddddddddddd000000dddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bbffffffffffffffffff0000bb0000bb0000bbffffff0000bb0000bbffffffffffff0000bb0000bb0000bbffffffffffff0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bbffffffffffff0000bb0000bb0000bbffffff0000bb0000bbffffffffffff0000bb0000bb0000bbffffffffffff0000bb0000bbffffffffffff0000bb
+0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffffffffffffff0000bb0000bb0000bbffffffffffffffffff0000bb0000bb0000bb0000bbffffff0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddd000000dddddd
+000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddd
+dddddddddddddddddd000000000000dddddddddddd000000000000dddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff
+0000bb0000bb0000bb0000bbffffff0000bb0000bbffffffffffff0000bb0000bbffffffffffff0000bbffffff0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffff
+ffffffffffff0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bbffffff0000bbffffffffffff0000bb0000bbffffff0000bbffffffffffff0000bbffffff0000bb0000bb0000bb0000bbffffff0000bb0000bb0000bb0000bb
+0000bb0000bbffffff0000bb0000bb0000bbffffff0000bb0000bb0000bbffffffffffff0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddd000000dddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd
+000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddd000000000000000000000000dddddddddddd
+dddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bbffffffffffffffffffffffffffffff0000bb
+0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bbffffff0000bb0000bb0000bb0000bbffffff0000bb0000bb
+0000bb0000bb0000bbffffffffffff0000bb0000bbffffff0000bbffffffffffff0000bbffffffffffff0000bb0000bb0000bbffffffffffffffffffffffff0000bb0000bb0000bbffffffffffffffffffffffffffffff0000bb0000bb0000bb
+ffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddd
+dddddddddddddddddddddddddddddddddddddddddd000000dddddddddddd000000dddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddd000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddd000000000000000000000000dddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999
+ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bbffffff
+ffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bbffffffffffff0000bb0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bbffffff0000bbffffff
+ffffff0000bbffffffffffff0000bb0000bb0000bb0000bbffffffffffffffffffffffff0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddd000000000000000000000000000000000000dddddddddddd
+000000dddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd999999ffffffffffffdddddd
+dddddddddddddddddddddddddddddddddddd000000000000000000000000dddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+ffffffffffff0000bb0000bb0000bb0000bbffffffffffff0000bb0000bbffffff0000bb0000bbffffff0000bb0000bbffffffffffff0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bbffffffffffff0000bbffffffffffff0000bb0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bbffffff0000bbffffffffffff0000bb0000bbffffffffffff0000bbffffffffffff0000bb0000bbffffff0000bb0000bb
+0000bbffffff0000bb0000bb0000bbffffff0000bb0000bbffffff0000bb0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddd000000dddddddddddddddddd999999999999ffffffdddddd
+dddddddddddd000000000000000000000000000000000000000000000000000000000000000000000000000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddd
+000000000000dddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bb0000bb0000bbffffffffffffffffff
+0000bb0000bb0000bbffffff0000bb0000bbffffffffffff0000bb0000bb0000bb0000bbffffffffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffffffffffffff0000bb0000bb0000bb0000bbffffff
+0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff0000bb0000bb0000bbffffffffffff0000bbffffffffffff0000bb0000bb0000bbffffffffffffffffffffffff0000bb0000bb0000bbffffffffffffffffff0000bb0000bb
+0000bb0000bbffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffff
+dddddddddddddddddddddddd000000000000000000000000000000000000000000000000000000dddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000000000000000000000000000000000000000000000
+000000000000000000000000000000dddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddd000000000000000000dddddddddddddddddddddddd000000000000000000dddddddddddddddddddddddd9999999999990000bb
+999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddd000000dddddddddddddddddd999999999999ffffffdddddddddddddddddd000000000000000000000000000000000000000000000000000000000000000000000000000000dddddddddddddddddd999999ffffff
+ffffffdddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddd000000000000000000000000000000000000000000000000000000000000000000dddddddddddddddddd999999999999
+ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999
+9999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffffffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+999999999999ffffffdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999ffffffffffffdddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd9999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bbffffffffffff999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999ffffff999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999ffffffffffff999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+9999999999999999990000bb999999999999ffffffffffff0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bbffffff999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999ffffff999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999ffffff9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999990000bb999999999999ffffffffffff0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb
+0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb0000bb999999999999ffffffffffff999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+999999999999999999999999999999999999999999999999ffffffffffff999999ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff999999999999ffffffffffff
+999999dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999
+ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999
+999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddd000000000000000000000000dddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000
+dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddd000000000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddd
+dddddddddddd000000000000000000000000000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000000000000000000000dddddddddddddddddddddddddddddddddddd000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddd
+000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000
+000000000000000000dddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+000000000000dddddddddddddddddddddddddddddddddddddddddd000000000000000000dddddddddddd000000000000000000000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+000000dddddddddddddddddd000000dddddddddddddddddd000000000000000000dddddddddddddddddddddddddddddd000000dddddddddddddddddd000000000000dddddd000000dddddddddddddddddddddddddddddddddddddddddddddddd
+dddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000
+dddddddddddddddddddddddd000000dddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddd000000dddddd
+dddddd000000dddddddddddddddddddddddd000000000000dddddddddddddddddd000000000000000000000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd000000dddddddddddd000000000000dddddd
+000000000000dddddddddddddddddddddddd000000dddddddddddddddddd000000000000000000dddddd000000dddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddd
+dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000dddddddddddddddddd000000000000dddddddddddd000000dddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000000000000000dddddddddddddddddd000000000000dddddddddddd000000dddddddddddddddddddddddd000000000000dddddddddddd
+dddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000000000000000000000dddddddddddd000000dddddddddddd000000000000dddddddddddddddddddddddd000000dddddddddddddddddd
+000000000000dddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddd
+dddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000dddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000dddddddddddd000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddd000000dddddddddddddddddd000000dddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd000000000000dddddddddddd000000000000dddddddddddddddddddddddd
+dddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd
+000000000000dddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000
+000000dddddddddddd000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd000000dddddddddddd000000
+dddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd000000000000dddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddd
+dddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddd000000dddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddd000000dddddd000000000000dddddddddddddddddddddddd000000000000
+dddddddddddddddddddddddd000000000000dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
+dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd000000dddddddddddddddddd000000dddddddddddd000000000000dddddddddddd000000dddddddddddddddddddddddd000000dddddd
+dddddddddddd000000000000dddddddddddd000000dddddddddddddddddddddddddddddddddddddddddddddddd999999999999999999ffffffffffff999999dddddddddddddddddddddddddddddddddddddddddd000000000000dddddddddddd
+dddddddddddddddddddddd