Initial revision
diff --git a/Lib/calendar.py b/Lib/calendar.py
new file mode 100644
index 0000000..49e8e63
--- /dev/null
+++ b/Lib/calendar.py
@@ -0,0 +1,213 @@
+# module calendar
+
+##############################
+# Calendar support functions #
+##############################
+
+# This is based on UNIX ctime() et al. (also Standard C and POSIX)
+# Subtle but crucial differences:
+# - the order of the elements of a 'struct tm' differs, to ease sorting
+# - months numbers are 1-12, not 0-11; month arrays have a dummy element 0
+# - Monday is the first day of the week (numbered 0)
+
+# These are really parameters of the 'time' module:
+epoch = 1970		# Time began on January 1 of this year (00:00:00 UCT)
+day_0 = 3		# The epoch begins on a Thursday (Monday = 0)
+
+# Return 1 for leap years, 0 for non-leap years
+def isleap(year):
+	return year % 4 = 0 and (year % 100 <> 0 or year % 400 = 0)
+
+# Constants for months referenced later
+January = 1
+February = 2
+
+# Number of days per month (except for February in leap years)
+mdays = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
+
+# Exception raised for bad input (with string parameter for details)
+error = 'calendar error'
+
+# Turn seconds since epoch into calendar time
+def gmtime(secs):
+	if secs < 0: raise error, 'negative input to gmtime()'
+	mins, secs = divmod(secs, 60)
+	hours, mins = divmod(mins, 60)
+	days, hours = divmod(hours, 24)
+	wday = (days + day_0) % 7
+	year = epoch
+	# XXX Most of the following loop can be replaced by one division
+	while 1:
+		yd = 365 + isleap(year)
+		if days < yd: break
+		days = days - yd
+		year = year + 1
+	yday = days
+	month = January
+	while 1:
+		md = mdays[month] + (month = February and isleap(year))
+		if days < md: break
+		days = days - md
+		month = month + 1
+	return year, month, days + 1, hours, mins, secs, yday, wday
+	# XXX Week number also?
+
+# Return number of leap years in range [y1, y2)
+# Assume y1 <= y2 and no funny (non-leap century) years
+def leapdays(y1, y2):
+	return (y2+3)/4 - (y1+3)/4
+
+# Inverse of gmtime():
+# Turn UCT calendar time (less yday, wday) into seconds since epoch
+def mktime(year, month, day, hours, mins, secs):
+	days = day - 1
+	for m in range(January, month): days = days + mdays[m]
+	if isleap(year) and month > February: days = days+1
+	days = days + (year-epoch)*365 + leapdays(epoch, year)
+	return ((days*24 + hours)*60 + mins)*60 + secs
+
+# Full and abbreviated names of weekdays
+day_name = ('Monday', 'Tuesday', 'Wednesday', 'Thursday')
+day_name = day_name + ('Friday', 'Saturday', 'Sunday')
+day_abbr = ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
+
+# Full and abbreviated of months (1-based arrays!!!)
+month_name =          ('', 'January',   'February', 'March',    'April')
+month_name = month_name + ('May',       'June',     'July',     'August')
+month_name = month_name + ('September', 'October',  'November', 'December')
+month_abbr =       ('   ', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun')
+month_abbr = month_abbr + ('Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
+
+# Zero-fill string to two positions (helper for asctime())
+def dd(s):
+	while len(s) < 2: s = '0' + s
+	return s
+
+# Blank-fill string to two positions (helper for asctime())
+def zd(s):
+	while len(s) < 2: s = ' ' + s
+	return s
+
+# Turn calendar time as returned by gmtime() into a string
+# (the yday parameter is for compatibility with gmtime())
+def asctime(year, month, day, hours, mins, secs, yday, wday):
+	s = day_abbr[wday] + ' ' + month_abbr[month] + ' ' + zd(`day`)
+	s = s + ' ' + dd(`hours`) + ':' + dd(`mins`) + ':' + dd(`secs`)
+	return s + ' ' + `year`
+
+# Localization: Minutes West from Greenwich
+# timezone = -2*60	# Middle-European time with DST on
+timezone = 5*60		# EST (sigh -- THINK time() doesn't return UCT)
+
+# Local time ignores DST issues for now -- adjust 'timezone' to fake it
+def localtime(secs):
+	return gmtime(secs - timezone*60)
+
+# UNIX-style ctime (except it doesn't append '\n'!)
+def ctime(secs):
+	return asctime(localtime(secs))
+
+######################
+# Non-UNIX additions #
+######################
+
+# Calendar printing etc.
+
+# Return weekday (0-6 ~ Mon-Sun) for year (1970-...), month (1-12), day (1-31)
+def weekday(year, month, day):
+	secs = mktime(year, month, day, 0, 0, 0)
+	days = secs / (24*60*60)
+	return (days + day_0) % 7
+
+# Return weekday (0-6 ~ Mon-Sun) and number of days (28-31) for year, month
+def monthrange(year, month):
+	day1 = weekday(year, month, 1)
+	ndays = mdays[month] + (month = February and isleap(year))
+	return day1, ndays
+
+# Return a matrix representing a month's calendar
+# Each row represents a week; days outside this month are zero
+def _monthcalendar(year, month):
+	day1, ndays = monthrange(year, month)
+	rows = []
+	r7 = range(7)
+	day = 1 - day1
+	while day <= ndays:
+		row = [0, 0, 0, 0, 0, 0, 0]
+		for i in r7:
+			if 1 <= day <= ndays: row[i] = day
+			day = day + 1
+		rows.append(row)
+	return rows
+
+# Caching interface to _monthcalendar
+mc_cache = {}
+def monthcalendar(year, month):
+	key = `year` + month_abbr[month]
+	try:
+		return mc_cache[key]
+	except RuntimeError:
+		mc_cache[key] = ret = _monthcalendar(year, month)
+		return ret
+
+# Center a string in a field
+def center(str, width):
+	n = width - len(str)
+	if n < 0: return str
+	return ' '*(n/2) + str + ' '*(n-n/2)
+
+# XXX The following code knows that print separates items with space!
+
+# Print a single week (no newline)
+def prweek(week, width):
+	for day in week:
+		if day = 0: print ' '*width,
+		else:
+			if width > 2: print ' '*(width-3),
+			if day < 10: print '',
+			print day,
+
+# Return a header for a week
+def weekheader(width):
+	str = ''
+	for i in range(7):
+		if str: str = str + ' '
+		str = str + day_abbr[i%7][:width]
+	return str
+
+# Print a month's calendar
+def prmonth(year, month):
+	print weekheader(3)
+	for week in monthcalendar(year, month):
+		prweek(week, 3)
+		print
+
+# Spacing between month columns
+spacing = '    '
+
+# 3-column formatting for year calendars
+def format3c(a, b, c):
+	print center(a, 20), spacing, center(b, 20), spacing, center(c, 20)
+
+# Print a year's calendar
+def prcal(year):
+	header = weekheader(2)
+	format3c('', `year`, '')
+	for q in range(January, January+12, 3):
+		print
+		format3c(month_name[q], month_name[q+1], month_name[q+2])
+		format3c(header, header, header)
+		data = []
+		height = 0
+		for month in range(q, q+3):
+			cal = monthcalendar(year, month)
+			if len(cal) > height: height = len(cal)
+			data.append(cal)
+		for i in range(height):
+			for cal in data:
+				if i >= len(cal):
+					print ' '*20,
+				else:
+					prweek(cal[i], 2)
+				print spacing,
+			print
diff --git a/Lib/cmp.py b/Lib/cmp.py
new file mode 100644
index 0000000..434caee
--- /dev/null
+++ b/Lib/cmp.py
@@ -0,0 +1,61 @@
+# Module 'cmp'
+
+# Efficiently compare files, boolean outcome only (equal / not equal).
+
+# Tricks (used in this order):
+#	- Files with identical type, size & mtime are assumed to be clones
+#	- Files with different type or size cannot be identical
+#	- We keep a cache of outcomes of earlier comparisons
+#	- We don't fork a process to run 'cmp' but read the files ourselves
+
+import posix
+
+cache = {}
+
+def cmp(f1, f2): # Compare two files, use the cache if possible.
+	# Return 1 for identical files, 0 for different.
+	# Raise exceptions if either file could not be statted, read, etc.
+	s1, s2 = sig(posix.stat(f1)), sig(posix.stat(f2))
+	if s1[0] <> 8 or s2[0] <> 8:
+		# Either is a not a plain file -- always report as different
+		return 0
+	if s1 = s2:
+		# type, size & mtime match -- report same
+		return 1
+	if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother
+		# types or sizes differ -- report different
+		return 0
+	# same type and size -- look in the cache
+	key = f1 + ' ' + f2
+	try:
+		cs1, cs2, outcome = cache[key]
+		# cache hit
+		if s1 = cs1 and s2 = cs2:
+			# cached signatures match
+			return outcome
+		# stale cached signature(s)
+	except RuntimeError:
+		# cache miss
+		pass
+	# really compare
+	outcome = do_cmp(f1, f2)
+	cache[key] = s1, s2, outcome
+	return outcome
+
+def sig(st): # Return signature (i.e., type, size, mtime) from raw stat data
+	# 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid
+	# 6-9: st_size, st_atime, st_mtime, st_ctime
+	type = st[0] / 4096
+	size = st[6]
+	mtime = st[8]
+	return type, size, mtime
+
+def do_cmp(f1, f2): # Compare two files, really
+	bufsize = 8096 # Could be tuned
+	fp1 = open(f1, 'r')
+	fp2 = open(f2, 'r')
+	while 1:
+		b1 = fp1.read(bufsize)
+		b2 = fp2.read(bufsize)
+		if b1 <> b2: return 0
+		if not b1: return 1
diff --git a/Lib/cmpcache.py b/Lib/cmpcache.py
new file mode 100644
index 0000000..a47a4fd
--- /dev/null
+++ b/Lib/cmpcache.py
@@ -0,0 +1,74 @@
+# Module 'cmpcache'
+#
+# Efficiently compare files, boolean outcome only (equal / not equal).
+#
+# Tricks (used in this order):
+#	- Use the statcache module to avoid statting files more than once
+#	- Files with identical type, size & mtime are assumed to be clones
+#	- Files with different type or size cannot be identical
+#	- We keep a cache of outcomes of earlier comparisons
+#	- We don't fork a process to run 'cmp' but read the files ourselves
+#
+# XXX There is a dependency on constants in <sys/stat.h> here.
+
+import posix
+import statcache
+
+
+# The cache.
+#
+cache = {}
+
+
+# Compare two files, use the cache if possible.
+# May raise posix.error if a stat or open of either fails.
+#
+def cmp(f1, f2):
+	# Return 1 for identical files, 0 for different.
+	# Raise exceptions if either file could not be statted, read, etc.
+	s1, s2 = sig(statcache.stat(f1)), sig(statcache.stat(f2))
+	if s1[0] <> 8 or s2[0] <> 8: # XXX 8 is S_IFREG in <sys/stat.h>
+		# Either is a not a plain file -- always report as different
+		return 0
+	if s1 = s2:
+		# type, size & mtime match -- report same
+		return 1
+	if s1[:2] <> s2[:2]: # Types or sizes differ, don't bother
+		# types or sizes differ -- report different
+		return 0
+	# same type and size -- look in the cache
+	key = f1 + ' ' + f2
+	if cache.has_key(key):
+		cs1, cs2, outcome = cache[key]
+		# cache hit
+		if s1 = cs1 and s2 = cs2:
+			# cached signatures match
+			return outcome
+		# stale cached signature(s)
+	# really compare
+	outcome = do_cmp(f1, f2)
+	cache[key] = s1, s2, outcome
+	return outcome
+
+# Return signature (i.e., type, size, mtime) from raw stat data.
+#
+def sig(st):
+	# 0-5: st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid
+	# 6-9: st_size, st_atime, st_mtime, st_ctime
+	type = st[0] / 4096 # XXX dependent on S_IFMT in <sys/stat.h>
+	size = st[6]
+	mtime = st[8]
+	return type, size, mtime
+
+# Compare two files, really.
+#
+def do_cmp(f1, f2):
+	#print '    cmp', f1, f2 # XXX remove when debugged
+	bufsize = 8096 # Could be tuned
+	fp1 = open(f1, 'r')
+	fp2 = open(f2, 'r')
+	while 1:
+		b1 = fp1.read(bufsize)
+		b2 = fp2.read(bufsize)
+		if b1 <> b2: return 0
+		if not b1: return 1
diff --git a/Lib/commands.py b/Lib/commands.py
new file mode 100644
index 0000000..145f5db
--- /dev/null
+++ b/Lib/commands.py
@@ -0,0 +1,73 @@
+# Module 'commands'
+#
+# Various tools for executing commands and looking at their output and status.
+
+import rand
+import posix
+import path
+
+
+# Get 'ls -l' status for an object into a string
+#
+def getstatus(file):
+	return getoutput('ls -ld' + mkarg(file))
+
+
+# Get the output from a shell command into a string.
+# The exit status is ignored; a trailing newline is stripped.
+# Assume the command will work with ' >tempfile 2>&1' appended.
+# XXX This should use posix.popen() instead, should it exist.
+#
+def getoutput(cmd):
+	return getstatusoutput(cmd)[1]
+
+
+# Ditto but preserving the exit status.
+# Returns a pair (sts, output)
+#
+def getstatusoutput(cmd):
+	tmp = '/usr/tmp/wdiff' + `rand.rand()`
+	sts = -1
+	try:
+		sts = posix.system(cmd + ' >' + tmp + ' 2>&1')
+		text = readfile(tmp)
+	finally:
+		altsts = posix.system('rm -f ' + tmp)
+	if text[-1:] = '\n': text = text[:-1]
+	return sts, text
+
+
+# Return a string containing a file's contents.
+#
+def readfile(fn):
+	fp = open(fn, 'r')
+	a = ''
+	n = 8096
+	while 1:
+		b = fp.read(n)
+		if not b: break
+		a = a + b
+	return a
+
+
+# Make command argument from directory and pathname (prefix space, add quotes).
+#
+def mk2arg(head, x):
+	return mkarg(path.cat(head, x))
+
+
+# Make a shell command argument from a string.
+# Two strategies: enclose in single quotes if it contains none;
+# otherwis, enclose in double quotes and prefix quotable characters
+# with backslash.
+#
+def mkarg(x):
+	if '\'' not in x:
+		return ' \'' + x + '\''
+	s = ' "'
+	for c in x:
+		if c in '\\$"':
+			s = s + '\\'
+		s = s + c
+	s = s + '"'
+	return s
diff --git a/Lib/dircache.py b/Lib/dircache.py
new file mode 100644
index 0000000..b40f76e
--- /dev/null
+++ b/Lib/dircache.py
@@ -0,0 +1,36 @@
+# Module 'dircache'
+#
+# Return a sorted list of the files in a POSIX directory, using a cache
+# to avoid reading the directory more often than necessary.
+# Also contains a subroutine to append slashes to directories.
+
+import posix
+import path
+
+cache = {}
+
+def listdir(path): # List directory contents, using cache
+	try:
+		cached_mtime, list = cache[path]
+		del cache[path]
+	except RuntimeError:
+		cached_mtime, list = -1, []
+	try:
+		mtime = posix.stat(path)[8]
+	except posix.error:
+		return []
+	if mtime <> cached_mtime:
+		try:
+			list = posix.listdir(path)
+		except posix.error:
+			return []
+		list.sort()
+	cache[path] = mtime, list
+	return list
+
+opendir = listdir # XXX backward compatibility
+
+def annotate(head, list): # Add '/' suffixes to directories
+	for i in range(len(list)):
+		if path.isdir(path.cat(head, list[i])):
+			list[i] = list[i] + '/'
diff --git a/Lib/dircmp.py b/Lib/dircmp.py
new file mode 100644
index 0000000..762a186
--- /dev/null
+++ b/Lib/dircmp.py
@@ -0,0 +1,215 @@
+# Module 'dirmp'
+#
+# Defines a class to build directory diff tools on.
+
+import posix
+
+import path
+
+import dircache
+import cmpcache
+import statcache
+
+
+# File type constants from <sys/stat.h>.
+#
+S_IFDIR = 4
+S_IFREG = 8
+
+# Extract the file type from a stat buffer.
+#
+def S_IFMT(st): return st[0] / 4096
+
+
+# Directory comparison class.
+#
+class dircmp():
+	#
+	def new(dd, (a, b)): # Initialize
+		dd.a = a
+		dd.b = b
+		# Properties that caller may change before callingdd. run():
+		dd.hide = ['.', '..'] # Names never to be shown
+		dd.ignore = ['RCS', 'tags'] # Names ignored in comparison
+		#
+		return dd
+	#
+	def run(dd): # Compare everything except common subdirectories
+		dd.a_list = filter(dircache.listdir(dd.a), dd.hide)
+		dd.b_list = filter(dircache.listdir(dd.b), dd.hide)
+		dd.a_list.sort()
+		dd.b_list.sort()
+		dd.phase1()
+		dd.phase2()
+		dd.phase3()
+	#
+	def phase1(dd): # Compute common names
+		dd.a_only = []
+		dd.common = []
+		for x in dd.a_list:
+			if x in dd.b_list:
+				dd.common.append(x)
+			else:
+				dd.a_only.append(x)
+		#
+		dd.b_only = []
+		for x in dd.b_list:
+			if x not in dd.common:
+				dd.b_only.append(x)
+	#
+	def phase2(dd): # Distinguish files, directories, funnies
+		dd.common_dirs = []
+		dd.common_files = []
+		dd.common_funny = []
+		#
+		for x in dd.common:
+			a_path = path.cat(dd.a, x)
+			b_path = path.cat(dd.b, x)
+			#
+			ok = 1
+			try:
+				a_stat = statcache.stat(a_path)
+			except posix.error, why:
+				# print 'Can\'t stat', a_path, ':', why[1]
+				ok = 0
+			try:
+				b_stat = statcache.stat(b_path)
+			except posix.error, why:
+				# print 'Can\'t stat', b_path, ':', why[1]
+				ok = 0
+			#
+			if ok:
+				a_type = S_IFMT(a_stat)
+				b_type = S_IFMT(b_stat)
+				if a_type <> b_type:
+					dd.common_funny.append(x)
+				elif a_type = S_IFDIR:
+					dd.common_dirs.append(x)
+				elif a_type = S_IFREG:
+					dd.common_files.append(x)
+				else:
+					dd.common_funny.append(x)
+			else:
+				dd.common_funny.append(x)
+	#
+	def phase3(dd): # Find out differences between common files
+		xx = cmpfiles(dd.a, dd.b, dd.common_files)
+		dd.same_files, dd.diff_files, dd.funny_files = xx
+	#
+	def phase4(dd): # Find out differences between common subdirectories
+		# A new dircmp object is created for each common subdirectory,
+		# these are stored in a dictionary indexed by filename.
+		# The hide and ignore properties are inherited from the parent
+		dd.subdirs = {}
+		for x in dd.common_dirs:
+			a_x = path.cat(dd.a, x)
+			b_x = path.cat(dd.b, x)
+			dd.subdirs[x] = newdd = dircmp().new(a_x, b_x)
+			newdd.hide = dd.hide
+			newdd.ignore = dd.ignore
+			newdd.run()
+	#
+	def phase4_closure(dd): # Recursively call phase4() on subdirectories
+		dd.phase4()
+		for x in dd.subdirs.keys():
+			dd.subdirs[x].phase4_closure()
+	#
+	def report(dd): # Print a report on the differences between a and b
+		# Assume that phases 1 to 3 have been executed
+		# Output format is purposely lousy
+		print 'diff', dd.a, dd.b
+		if dd.a_only:
+			print 'Only in', dd.a, ':', dd.a_only
+		if dd.b_only:
+			print 'Only in', dd.b, ':', dd.b_only
+		if dd.same_files:
+			print 'Identical files :', dd.same_files
+		if dd.diff_files:
+			print 'Differing files :', dd.diff_files
+		if dd.funny_files:
+			print 'Trouble with common files :', dd.funny_files
+		if dd.common_dirs:
+			print 'Common subdirectories :', dd.common_dirs
+		if dd.common_funny:
+			print 'Common funny cases :', dd.common_funny
+	#
+	def report_closure(dd): # Print reports on dd and on subdirs
+		# If phase 4 hasn't been done, no subdir reports are printed
+		dd.report()
+		try:
+			x = dd.subdirs
+		except NameError:
+			return # No subdirectories computed
+		for x in dd.subdirs.keys():
+			print
+			dd.subdirs[x].report_closure()
+	#
+	def report_phase4_closure(dd): # Report and do phase 4 recursively
+		dd.report()
+		dd.phase4()
+		for x in dd.subdirs.keys():
+			print
+			dd.subdirs[x].report_phase4_closure()
+
+
+# Compare common files in two directories.
+# Return:
+#	- files that compare equal
+#	- files that compare different
+#	- funny cases (can't stat etc.)
+#
+def cmpfiles(a, b, common):
+	res = ([], [], [])
+	for x in common:
+		res[cmp(path.cat(a, x), path.cat(b, x))].append(x)
+	return res
+
+
+# Compare two files.
+# Return:
+#	0 for equal
+#	1 for different
+#	2 for funny cases (can't stat, etc.)
+#
+def cmp(a, b):
+	try:
+		if cmpcache.cmp(a, b): return 0
+		return 1
+	except posix.error:
+		return 2
+
+
+# Remove a list item.
+# NB: This modifies the list argument.
+#
+def remove(list, item):
+	for i in range(len(list)):
+		if list[i] = item:
+			del list[i]
+			break
+
+
+# Return a copy with items that occur in skip removed.
+#
+def filter(list, skip):
+	result = []
+	for item in list:
+		if item not in skip: result.append(item)
+	return result
+
+
+# Demonstration and testing.
+#
+def demo():
+	import sys
+	import getopt
+	options, args = getopt.getopt(sys.argv[1:], 'r')
+	if len(args) <> 2: raise getopt.error, 'need exactly two args'
+	dd = dircmp().new(args[0], args[1])
+	dd.run()
+	if ('-r', '') in options:
+		dd.report_phase4_closure()
+	else:
+		dd.report()
+
+# demo()
diff --git a/Lib/dump.py b/Lib/dump.py
new file mode 100644
index 0000000..cecc275
--- /dev/null
+++ b/Lib/dump.py
@@ -0,0 +1,63 @@
+# Module 'dump'
+#
+# Print python code that reconstructs a variable.
+# This only works in certain cases.
+#
+# It works fine for:
+# - ints and floats (except NaNs and other weird things)
+# - strings
+# - compounds and lists, provided it works for all their elements
+# - imported modules, provided their name is the module name
+#
+# It works for top-level dictionaries but not for dictionaries
+# contained in other objects (could be made to work with some hassle
+# though).
+#
+# It does not work for functions (all sorts), classes, class objects,
+# windows, files etc.
+#
+# Finally, objects referenced by more than one name or contained in more
+# than one other object lose their sharing property (this is bad for
+# strings used as exception identifiers, for instance).
+
+# Dump a whole symbol table
+#
+def dumpsymtab(dict):
+	for key in dict.keys():
+		dumpvar(key, dict[key])
+
+# Dump a single variable
+#
+def dumpvar(name, x):
+	import sys
+	t = type(x)
+	if t = type({}):
+		print name, '= {}'
+		for key in x.keys():
+			item = x[key]
+			if not printable(item):
+				print '#',
+			print name, '[', `key`, '] =', `item`
+	elif t in (type(''), type(0), type(0.0), type([]), type(())):
+		if not printable(x):
+			print '#',
+		print name, '=', `x`
+	elif t = type(sys):
+		print 'import', name, '#', x
+	else:
+		print '#', name, '=', x
+
+# check if a value is printable in a way that can be read back with input()
+#
+def printable(x):
+	t = type(x)
+	if t in (type(''), type(0), type(0.0)):
+		return 1
+	if t in (type([]), type(())):
+		for item in x:
+			if not printable(item):
+				return 0
+		return 1
+	if x = {}:
+		return 1
+	return 0
diff --git a/Lib/getopt.py b/Lib/getopt.py
new file mode 100644
index 0000000..ef72fbc
--- /dev/null
+++ b/Lib/getopt.py
@@ -0,0 +1,47 @@
+# module getopt -- Standard command line processing.
+
+# Function getopt.getopt() has a different interface but provides the
+# same functionality as the Unix getopt() function.
+
+# It has two arguments: the first should be argv[1:] (it doesn't want
+# the script name), the second the string of option letters as passed
+# to Unix getopt() (i.e., a string of allowable option letters, with
+# options requiring an argument followed by a colon).
+
+# It raises the exception getopt.error with a string argument if it
+# detects an error.
+
+# It returns two items:
+# (1)	a list of pairs (option, option_argument) giving the options in
+#	the order in which they were specified.  (I'd use a dictionary
+#	but applications may depend on option order or multiple
+#	occurrences.)  Boolean options have '' as option_argument.
+# (2)	the list of remaining arguments (may be empty).
+
+error = 'getopt error'
+
+def getopt(args, options):
+    list = []
+    while args and args[0][0] = '-' and args[0] <> '-':
+    	if args[0] = '--':
+    	    args = args[1:]
+    	    break
+    	optstring, args = args[0][1:], args[1:]
+    	while optstring <> '':
+    	    opt, optstring = optstring[0], optstring[1:]
+    	    if classify(opt, options): # May raise exception as well
+    	    	if optstring = '':
+    	    	    if not args:
+    	    	    	raise error, 'option -' + opt + ' requires argument'
+    	    	    optstring, args = args[0], args[1:]
+    	    	optarg, optstring = optstring, ''
+    	    else:
+    	    	optarg = ''
+    	    list.append('-' + opt, optarg)
+    return list, args
+
+def classify(opt, options): # Helper to check type of option
+    for i in range(len(options)):
+	if opt = options[i] <> ':':
+	    return options[i+1:i+2] = ':'
+    raise error, 'option -' + opt + ' not recognized'
diff --git a/Lib/irix5/DEVICE.py b/Lib/irix5/DEVICE.py
new file mode 100755
index 0000000..00eddfc
--- /dev/null
+++ b/Lib/irix5/DEVICE.py
@@ -0,0 +1,423 @@
+#/**************************************************************************
+# *									  *
+# * 		 Copyright (C) 1984, Silicon Graphics, Inc.		  *
+# *									  *
+# *  These coded instructions, statements, and computer programs  contain  *
+# *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
+# *  are protected by Federal copyright law.  They  may  not be disclosed  *
+# *  to  third  parties  or copied or duplicated in any form, in whole or  *
+# *  in part, without the prior written consent of Silicon Graphics, Inc.  *
+# *									  *
+# **************************************************************************/
+#/* file with device definitions (see /usr/include/device.h) */
+
+NULLDEV =  0
+BUTOFFSET = 1
+VALOFFSET = 256
+TIMOFFSET = 515
+XKBDOFFSET = 143
+INOFFSET = 1024
+OUTOFFSET = 1033
+BUTCOUNT = 190
+VALCOUNT = 27
+TIMCOUNT = 4
+XKBDCOUNT = 28
+INCOUNT =  8
+OUTCOUNT = 8
+#
+#
+#
+#
+BUT0 =   1	
+BUT1 =   2	
+BUT2 =   3	
+BUT3 =   4	
+BUT4 =   5	
+BUT5 =   6	
+BUT6 =   7	
+BUT7 =   8	
+BUT8 =   9	
+BUT9 =  10	
+BUT10 =  11	
+BUT11 =  12	
+BUT12 =  13	
+BUT13 =  14	
+BUT14 =  15	
+BUT15 =  16	
+BUT16 =  17	
+BUT17 =  18	
+BUT18 =  19	
+BUT19 =  20	
+BUT20 =  21	
+BUT21 =  22	
+BUT22 =  23	
+BUT23 =  24	
+BUT24 =  25	
+BUT25 =  26	
+BUT26 =  27	
+BUT27 =  28	
+BUT28 =  29	
+BUT29 =  30	
+BUT30 =  31	
+BUT31 =  32	
+BUT32 =  33	
+BUT33 =  34	
+BUT34 =  35	
+BUT35 =  36	
+BUT36 =  37	
+BUT37 =  38	
+BUT38 =  39	
+BUT39 =  40	
+BUT40 =  41	
+BUT41 =  42	
+BUT42 =  43	
+BUT43 =  44	
+BUT44 =  45	
+BUT45 =  46	
+BUT46 =  47	
+BUT47 =  48	
+BUT48 =  49	
+BUT49 =  50	
+BUT50 =  51	
+BUT51 =  52	
+BUT52 =  53	
+BUT53 =  54	
+BUT54 =  55	
+BUT55 =  56	
+BUT56 =  57	
+BUT57 =  58	
+BUT58 =  59	
+BUT59 =  60	
+BUT60 =  61	
+BUT61 =  62	
+BUT62 =  63	
+BUT63 =  64	
+BUT64 =  65	
+BUT65 =  66	
+BUT66 =  67	
+BUT67 =  68	
+BUT68 =  69	
+BUT69 =  70	
+BUT70 =  71	
+BUT71 =  72	
+BUT72 =  73	
+BUT73 =  74	
+BUT74 =  75	
+BUT75 =  76	
+BUT76 =  77	
+BUT77 =  78	
+BUT78 =  79	
+BUT79 =  80	
+BUT80 =  81	
+BUT81 =  82	
+BUT82 =  83	
+MAXKBDBUT = 83 
+BUT100 =  101	
+BUT101 =  102	
+BUT102 =  103	
+BUT110 =  111	
+BUT111 =  112	
+BUT112 =  113	
+BUT113 =  114	
+BUT114 =  115	
+BUT115 =  116	
+BUT116 =  117	
+BUT117 =  118	
+BUT118 =  119	
+BUT119 =  120	
+BUT120 =  121	
+BUT121 =  122	
+BUT122 =  123	
+BUT123 =  124	
+BUT124 =  125	
+BUT125 =  126	
+BUT126 =  127	
+BUT127 =  128	
+BUT128 =  129	
+BUT129 =  130	
+BUT130 =  131	
+BUT131 =  132	
+BUT132 =  133	
+BUT133 =  134	
+BUT134 =  135	
+BUT135 =  136	
+BUT136 =  137	
+BUT137 =  138	
+BUT138 =  139	
+BUT139 =  140	
+BUT140 =  141	
+BUT141 =  142	
+BUT142 =  143	
+BUT143 =  144	
+BUT144 =  145	
+BUT145 =  146	
+BUT146 =  147	
+BUT147 =  148	
+BUT148 =  149	
+BUT149 =  150	
+BUT150 =  151	
+BUT151 =  152	
+BUT152 =  153	
+BUT153 =  154	
+BUT154 =  155	
+BUT155 =  156 	
+BUT156 =  157	
+BUT157 =  158	
+BUT158 =  159	
+BUT159 =  160	
+BUT160 =  161	
+BUT161 =  162	
+BUT162 =  163	
+BUT163 =  164	
+BUT164 =  165	
+BUT165 =  166	
+BUT166 =  167	
+BUT167 =  168	
+BUT168 =  169	
+BUT181 =  182	
+BUT182 =  183	
+BUT183 =  184	
+BUT184 =  185	
+BUT185 =  186	
+BUT186 =  187	
+BUT187 =  188	
+BUT188 =  189	
+BUT189 =  190	
+MOUSE1 =  101	
+MOUSE2 =  102	
+MOUSE3 =  103	
+LEFTMOUSE = 103 
+MIDDLEMOUSE = 102 
+RIGHTMOUSE = 101 
+LPENBUT =  104	
+BPAD0 =  105	
+BPAD1 =  106	
+BPAD2 =  107	
+BPAD3 =  108	
+LPENVALID = 109 
+SWBASE =  111	
+SW0 =  111	
+SW1 =  112	
+SW2 =  113	
+SW3 =  114	
+SW4 =  115	
+SW5 =  116	
+SW6 =  117	
+SW7 =  118	
+SW8 =  119	
+SW9 =  120	
+SW10 =  121	
+SW11 =  122	
+SW12 =  123	
+SW13 =  124	
+SW14 =  125	
+SW15 =  126	
+SW16 =  127	
+SW17 =  128	
+SW18 =  129	
+SW19 =  130	
+SW20 =  131	
+SW21 =  132	
+SW22 =  133	
+SW23 =  134	
+SW24 =  135	
+SW25 =  136	
+SW26 =  137	
+SW27 =  138	
+SW28 =  139	
+SW29 =  140	
+SW30 =  141	
+SW31 =  142	
+SBBASE =  182	
+SBPICK =  182	
+SBBUT1 =  183	
+SBBUT2 =  184	
+SBBUT3 =  185	
+SBBUT4 =  186	
+SBBUT5 =  187	
+SBBUT6 =  188	
+SBBUT7 =  189	
+SBBUT8 =  190	
+AKEY =  11	
+BKEY =  36	
+CKEY =  28	
+DKEY =  18	
+EKEY =  17	
+FKEY =  19	
+GKEY =  26	
+HKEY =  27	
+IKEY =  40	
+JKEY =  34	
+KKEY =  35	
+LKEY =  42	
+MKEY =  44	
+NKEY =  37	
+OKEY =  41	
+PKEY =  48	
+QKEY =  10	
+RKEY =  24	
+SKEY =  12	
+TKEY =  25	
+UKEY =  33	
+VKEY =  29	
+WKEY =  16	
+XKEY =  21	
+YKEY =  32	
+ZKEY =  20	
+ZEROKEY =  46	
+ONEKEY =  8	
+TWOKEY =  14	
+THREEKEY = 15 
+FOURKEY =  22	
+FIVEKEY =  23	
+SIXKEY =  30	
+SEVENKEY = 31 
+EIGHTKEY = 38 
+NINEKEY =  39	
+BREAKKEY = 1 
+SETUPKEY = 2 
+CTRLKEY =  3	
+LEFTCTRLKEY = CTRLKEY 
+CAPSLOCKKEY = 4 
+RIGHTSHIFTKEY = 5 
+LEFTSHIFTKEY = 6 
+NOSCRLKEY = 13 
+ESCKEY =  7	
+TABKEY =  9	
+RETKEY =  51	
+SPACEKEY = 83 
+LINEFEEDKEY = 60 
+BACKSPACEKEY = 61 
+DELKEY =  62	
+SEMICOLONKEY = 43 
+PERIODKEY = 52 
+COMMAKEY = 45 
+QUOTEKEY = 50 
+ACCENTGRAVEKEY = 55 
+MINUSKEY = 47 
+VIRGULEKEY = 53 
+BACKSLASHKEY = 57 
+EQUALKEY = 54 
+LEFTBRACKETKEY = 49 
+RIGHTBRACKETKEY = 56 
+LEFTARROWKEY = 73 
+DOWNARROWKEY = 74 
+RIGHTARROWKEY = 80 
+UPARROWKEY = 81 
+PAD0 =  59	
+PAD1 =  58	
+PAD2 =  64	
+PAD3 =  65	
+PAD4 =  63	
+PAD5 =  69	
+PAD6 =  70	
+PAD7 =  67	
+PAD8 =  68	
+PAD9 =  75	
+PADPF1 =  72	
+PADPF2 =  71	
+PADPF3 =  79	
+PADPF4 =  78	
+PADPERIOD = 66 
+PADMINUS = 76 
+PADCOMMA = 77 
+PADENTER = 82 
+LEFTALTKEY  = 143
+RIGHTALTKEY  = 144
+RIGHTCTRLKEY  = 145
+F1KEY  =  146
+F2KEY  =  147
+F3KEY  =  148
+F4KEY  =  149
+F5KEY  =  150
+F6KEY  =  151
+F7KEY  =  152
+F8KEY  =  153
+F9KEY  =  154
+F10KEY =  155
+F11KEY =  156
+F12KEY =  157
+PRINTSCREENKEY = 158
+SCROLLLOCKKEY = 159
+PAUSEKEY = 160
+INSERTKEY = 161
+HOMEKEY  = 162
+PAGEUPKEY  = 163
+ENDKEY =  164
+PAGEDOWNKEY = 165
+NUMLOCKKEY = 166
+PADVIRGULEKEY  = 167
+PADASTERKEY  = 168
+PADPLUSKEY  = 169
+SGIRESERVED = 256 
+DIAL0 =  257	
+DIAL1 =  258	
+DIAL2 =  259	
+DIAL3 =  260	
+DIAL4 =  261	
+DIAL5 =  262	
+DIAL6 =  263	
+DIAL7 =  264	
+DIAL8 =  265	
+MOUSEX =  266	
+MOUSEY =  267	
+LPENX =  268	
+LPENY =  269	
+BPADX =  270	
+BPADY =  271	
+CURSORX =  272	
+CURSORY =  273	
+GHOSTX =  274	
+GHOSTY =  275	
+SBTX =  276	
+SBTY  =  277	
+SBTZ =  278	
+SBRX =   279	
+SBRY =  280	
+SBRZ  =  281	
+SBPERIOD = 282 
+TIMER0 =  515	
+TIMER1 =  516	
+TIMER2 =  517	
+TIMER3 =  518	
+KEYBD =  513	
+RAWKEYBD = 514 
+VALMARK =  523	
+GERROR =  524	
+REDRAW =  528	
+WMSEND =  529	
+WMREPLY =  530	
+WMGFCLOSE = 531 
+WMTXCLOSE = 532 
+MODECHANGE = 533 
+INPUTCHANGE = 534 
+QFULL =  535	
+PIECECHANGE = 536 
+WINCLOSE = 537 
+QREADERROR = 538 
+WINFREEZE = 539 
+WINTHAW =  540	
+REDRAWICONIC = 541 
+WINQUIT =  542	
+DEPTHCHANGE = 543 
+KEYBDFNAMES = 544 
+KEYBDFSTRINGS = 545 
+WINSHUT =  546	
+INPUT0 =  1024	
+INPUT1 =  1025
+INPUT2 =  1026
+INPUT3 =  1027
+INPUT4 =  1028
+INPUT5 =  1029
+INPUT6 =  1030
+INPUT7 =  1032
+OUTPUT0 =  1033	
+OUTPUT1 =  1034
+OUTPUT2 =  1035
+OUTPUT3 =  1036
+OUTPUT4 =  1037
+OUTPUT5 =  1038
+OUTPUT6 =  1039
+OUTPUT7 =  1040
+MAXSGIDEVICE = 20000
+MENUBUTTON = RIGHTMOUSE 
diff --git a/Lib/irix5/GL.py b/Lib/irix5/GL.py
new file mode 100755
index 0000000..35487a7
--- /dev/null
+++ b/Lib/irix5/GL.py
@@ -0,0 +1,365 @@
+# Constants defined in <gl.h>
+
+#**************************************************************************
+#*									  *
+#* 		 Copyright (C) 1984, Silicon Graphics, Inc.		  *
+#*									  *
+#*  These coded instructions, statements, and computer programs  contain  *
+#*  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
+#*  are protected by Federal copyright law.  They  may  not be disclosed  *
+#*  to  third  parties  or copied or duplicated in any form, in whole or  *
+#*  in part, without the prior written consent of Silicon Graphics, Inc.  *
+#*									  *
+#**************************************************************************
+
+# Graphics Libary constants
+
+# Booleans
+TRUE = 1
+FALSE = 0
+
+# maximum X and Y screen coordinates 
+XMAXSCREEN = 1279
+YMAXSCREEN = 1023
+XMAXMEDIUM = 1023		# max for medium res monitor 
+YMAXMEDIUM = 767
+XMAX170 = 645		# max for RS-170 
+YMAX170 = 484
+XMAXPAL = 779		# max for PAL 
+YMAXPAL = 574
+
+# various hardware/software limits 
+ATTRIBSTACKDEPTH = 10
+VPSTACKDEPTH = 8
+MATRIXSTACKDEPTH = 32
+NAMESTACKDEPTH = 1025
+STARTTAG = -2
+ENDTAG = -3
+CPOSX_INVALID = -(2*XMAXSCREEN)
+
+# names for colors in color map loaded by greset 
+BLACK = 0
+RED = 1
+GREEN = 2
+YELLOW = 3
+BLUE = 4
+MAGENTA = 5
+CYAN = 6
+WHITE = 7
+
+# popup colors 
+PUP_CLEAR = 0
+PUP_COLOR = 1
+PUP_BLACK = 2
+PUP_WHITE = 3
+
+# defines for drawmode 
+NORMALDRAW = 0
+PUPDRAW = 1
+OVERDRAW = 2
+UNDERDRAW = 3
+CURSORDRAW = 4
+
+# defines for defpattern 
+PATTERN_16 = 16
+PATTERN_32 = 32
+PATTERN_64 = 64
+
+PATTERN_16_SIZE = 16
+PATTERN_32_SIZE = 64
+PATTERN_64_SIZE = 256
+
+# defines for readsource 
+SRC_AUTO = 0
+SRC_FRONT = 1
+SRC_BACK = 2
+SRC_ZBUFFER = 3
+SRC_PUP = 4
+SRC_OVER = 5
+SRC_UNDER = 6
+SRC_FRAMEGRABBER = 7
+
+# defines for blendfunction 
+BF_ZERO = 0
+BF_ONE = 1
+BF_DC = 2
+BF_SC = 2
+BF_MDC = 3
+BF_MSC = 3
+BF_SA = 4
+BF_MSA = 5
+BF_DA = 6
+BF_MDA = 7
+
+# defines for zfunction 
+ZF_NEVER = 0
+ZF_LESS = 1
+ZF_EQUAL = 2
+ZF_LEQUAL = 3
+ZF_GREATER = 4
+ZF_NOTEQUAL = 5
+ZF_GEQUAL = 6
+ZF_ALWAYS = 7
+
+# defines for zsource 
+ZSRC_DEPTH = 0
+ZSRC_COLOR = 1
+
+# defines for pntsmooth 
+SMP_OFF = 0
+SMP_ON = 1
+
+# defines for linesmooth 
+SML_OFF = 0
+SML_ON = 1
+
+# defines for setpup 
+PUP_NONE = 0
+PUP_GREY = 1
+
+# defines for glcompat 
+GLC_OLDPOLYGON = 0
+GLC_ZRANGEMAP = 1
+
+# defines for curstype 
+C16X1 = 0
+C16X2 = 1
+C32X1 = 2
+C32X2 = 3
+CCROSS = 4
+
+# defines for shademodel 
+FLAT = 0
+GOURAUD = 1
+
+# defines for logicop 
+### LO_ZERO = 0x0
+### LO_AND = 0x1
+### LO_ANDR = 0x2
+### LO_SRC = 0x3
+### LO_ANDI = 0x4
+### LO_DST = 0x5
+### LO_XOR = 0x6
+### LO_OR = 0x7
+### LO_NOR = 0x8
+### LO_XNOR = 0x9
+### LO_NDST = 0xa
+### LO_ORR = 0xb
+### LO_NSRC = 0xc
+### LO_ORI = 0xd
+### LO_NAND = 0xe
+### LO_ONE = 0xf
+
+
+#
+# START defines for getgdesc 
+#
+
+GD_XPMAX = 0
+GD_YPMAX = 1
+GD_XMMAX = 2
+GD_YMMAX = 3
+GD_ZMIN = 4
+GD_ZMAX = 5
+GD_BITS_NORM_SNG_RED = 6
+GD_BITS_NORM_SNG_GREEN = 7
+GD_BITS_NORM_SNG_BLUE = 8
+GD_BITS_NORM_DBL_RED = 9
+GD_BITS_NORM_DBL_GREEN = 10
+GD_BITS_NORM_DBL_BLUE = 11
+GD_BITS_NORM_SNG_CMODE = 12
+GD_BITS_NORM_DBL_CMODE = 13
+GD_BITS_NORM_SNG_MMAP = 14
+GD_BITS_NORM_DBL_MMAP = 15
+GD_BITS_NORM_ZBUFFER = 16
+GD_BITS_OVER_SNG_CMODE = 17
+GD_BITS_UNDR_SNG_CMODE = 18
+GD_BITS_PUP_SNG_CMODE = 19
+GD_BITS_NORM_SNG_ALPHA = 21 
+GD_BITS_NORM_DBL_ALPHA = 22
+GD_BITS_CURSOR = 23
+GD_OVERUNDER_SHARED = 24
+GD_BLEND = 25
+GD_CIFRACT = 26
+GD_CROSSHAIR_CINDEX = 27
+GD_DITHER = 28
+GD_LINESMOOTH_CMODE = 30
+GD_LINESMOOTH_RGB = 31
+GD_LOGICOP = 33
+GD_NSCRNS = 35
+GD_NURBS_ORDER = 36
+GD_NBLINKS = 37
+GD_NVERTEX_POLY = 39
+GD_PATSIZE_64 = 40
+GD_PNTSMOOTH_CMODE = 41
+GD_PNTSMOOTH_RGB = 42
+GD_PUP_TO_OVERUNDER = 43
+GD_READSOURCE = 44
+GD_READSOURCE_ZBUFFER = 48
+GD_STEREO = 50
+GD_SUBPIXEL_LINE = 51
+GD_SUBPIXEL_PNT = 52
+GD_SUBPIXEL_POLY = 53
+GD_TRIMCURVE_ORDER = 54
+GD_WSYS = 55
+GD_ZDRAW_GEOM = 57
+GD_ZDRAW_PIXELS = 58
+GD_SCRNTYPE = 61
+GD_TEXTPORT = 62
+GD_NMMAPS = 63
+GD_FRAMEGRABBER = 64
+GD_TIMERHZ = 66
+GD_DBBOX = 67
+GD_AFUNCTION = 68
+GD_ALPHA_OVERUNDER = 69
+GD_BITS_ACBUF = 70
+GD_BITS_ACBUF_HW = 71
+GD_BITS_STENCIL = 72
+GD_CLIPPLANES = 73
+GD_FOGVERTEX = 74
+GD_LIGHTING_TWOSIDE = 76
+GD_POLYMODE = 77
+GD_POLYSMOOTH = 78
+GD_SCRBOX = 79
+GD_TEXTURE = 80
+
+# return value for inquiries when there is no limit
+GD_NOLIMIT = 2
+
+# return values for GD_WSYS
+GD_WSYS_NONE = 0
+GD_WSYS_4S = 1
+
+# return values for GD_SCRNTYPE
+GD_SCRNTYPE_WM = 0
+GD_SCRNTYPE_NOWM = 1
+
+# 
+# END defines for getgdesc 
+#
+
+
+# 
+# START NURBS interface definitions 
+#
+
+# NURBS Rendering Properties 
+N_PIXEL_TOLERANCE = 1
+N_CULLING = 2
+N_DISPLAY = 3
+N_ERRORCHECKING = 4
+N_SUBDIVISIONS = 5
+N_S_STEPS = 6
+N_T_STEPS = 7
+N_TILES = 8
+
+N_SHADED = 1.0 	
+
+# ---------------------------------------------------------------------------
+# FLAGS FOR NURBS SURFACES AND CURVES 			
+# 
+# Bit: 9876 5432 1 0 
+#     |tttt|nnnn|f|r| :    r - 1 bit = 1 if rational coordinate exists
+# 	               :    f - 1 bit = 1 if rational coordinate is before rest 
+# 	               :              = 0 if rational coordinate is after rest 
+# 	 	       : nnnn - 4 bits for number of coordinates
+# 		       : tttt - 4 bits for type of data (color, position, etc.)
+# 
+# NURBS data type
+# N_T_ST	 	0	 parametric space data
+# N_T_XYZ		1	 model space data
+# 
+# rational or non-rational data and position in memory 
+# N_NONRATIONAL	0	 non-rational data
+# N_RATAFTER		1	 rational data with rat coord after rest
+# N_RATBEFORE		3	 rational data with rat coord before rest
+# 
+# N_MKFLAG(a,b,c) ((a<<6) | (b<<2) | c)
+# 	
+# ---------------------------------------------------------------------------
+# 
+N_ST = 0x8	# N_MKFLAG( N_T_ST, 2, N_NONRATIONAL ) 
+N_STW = 0xd	# N_MKFLAG( N_T_ST, 3, N_RATAFTER ) 
+N_WST = 0xf	# N_MKFLAG( N_T_ST, 3, N_RATBEFORE ) 
+N_XYZ = 0x4c	# N_MKFLAG( N_T_XYZ, 3, N_NONRATIONAL ) 
+N_XYZW = 0x51	# N_MKFLAG( N_T_XYZ, 4, N_RATAFTER ) 
+N_WXYZ = 0x53	# N_MKFLAG( N_T_XYZ, 4, N_RATBEFORE ) 
+
+# 
+# END NURBS interface definitions 
+# 
+
+
+# 
+# START lighting model defines 
+# 
+
+LMNULL = 0.0
+
+# MATRIX modes	
+MSINGLE = 0
+MPROJECTION = 1
+MVIEWING = 2
+
+# LIGHT constants 
+MAXLIGHTS = 8
+MAXRESTRICTIONS = 4
+
+# MATERIAL properties 
+DEFMATERIAL = 0
+EMISSION = 1
+AMBIENT = 2
+DIFFUSE = 3
+SPECULAR = 4
+SHININESS = 5
+COLORINDEXES = 6
+ALPHA = 7
+
+# LIGHT properties 
+DEFLIGHT = 100
+LCOLOR = 101
+POSITION = 102
+
+# LIGHTINGMODEL properties 
+DEFLMODEL = 200
+LOCALVIEWER = 201
+ATTENUATION = 202
+
+# TARGET constants 
+MATERIAL = 1000
+LIGHT0 = 1100
+LIGHT1 = 1101
+LIGHT2 = 1102
+LIGHT3 = 1103
+LIGHT4 = 1104
+LIGHT5 = 1105
+LIGHT6 = 1106
+LIGHT7 = 1107
+LMODEL = 1200
+
+# lmcolor modes 
+LMC_COLOR = 0
+LMC_EMISSION = 1
+LMC_AMBIENT = 2
+LMC_DIFFUSE = 3
+LMC_SPECULAR = 4
+LMC_AD = 5
+LMC_NULL = 6
+
+# 
+# END lighting model defines 
+# 
+
+
+# 
+# START distributed graphics library defines 
+# 
+
+DGLSINK = 0	# sink connection	
+DGLLOCAL = 1	# local connection	
+DGLTSOCKET = 2	# tcp socket connection
+DGL4DDN = 3	# 4DDN (DECnet)	
+
+# 
+# END distributed graphics library defines 
+# 
diff --git a/Lib/irix5/auds.py b/Lib/irix5/auds.py
new file mode 100755
index 0000000..549c0a7
--- /dev/null
+++ b/Lib/irix5/auds.py
@@ -0,0 +1,106 @@
+import audio
+
+RATE = 8192
+
+# Initialize the audio stuff
+audio.setrate(3)
+audio.setoutgain(100)	# for speaker
+
+play = audio.write
+
+def samp(n):
+	savegain = audio.getoutgain()
+	try:
+		audio.setoutgain(0)
+		x = raw_input('Hit Enter to sample ' + `n` + ' seconds: ')
+		return audio.read(n*RATE)
+	finally:
+		audio.setoutgain(savegain)
+
+def echo(s, delay, gain):
+	return s[:delay] + audio.add(s[delay:], audio.amplify(s, gain, gain))
+
+def save(s, file):
+	f = open(file, 'w')
+	f.write(s)
+
+def load(file):
+	return loadfp(open(file, 'r'))
+
+def loadfp(fp):
+	s = ''
+	while 1:
+		buf = fp.read(16*1024)
+		if not buf: break
+		s = s + buf
+	return s
+
+def unbias(s):
+	if not s: return s
+	a = audio.chr2num(s)
+	sum = 0
+	for i in a: sum = sum + i
+	bias = (sum + len(a)/2) / len(a)
+	print 'Bias value:', bias
+	if bias:
+		for i in range(len(a)):
+			a[i] = a[i] - bias
+		s = audio.num2chr(a)
+	return s
+
+# Stretch by a/b.
+# Think of this as converting the sampling rate from a samples/sec
+# to b samples/sec.  Or, if the input is a bytes long, the output
+# will be b bytes long.
+#
+def stretch(s, a, b):
+	y = audio.chr2num(s)
+	m = len(y)
+	out = []
+	n = m * b / a
+	# i, j will walk through y and out (step 1)
+	# ib, ja are i*b, j*a and are kept as close together as possible
+	i, ib = 0, 0
+	j, ja = 0, 0
+	for j in range(n):
+		ja = ja+a
+		while ib < ja:
+			i = i+1
+			ib = ib+b
+		if i >= m:
+			break
+		if ib = ja:
+			out.append(y[i])
+		else:
+			out.append((y[i]*(ja-(ib-b)) + y[i-1]*(ib-ja)) / b)
+	return audio.num2chr(out)
+
+def sinus(freq): # return a 1-second sine wave
+	from math import sin, pi
+	factor = 2.0*pi*float(freq)/float(RATE)
+	list = range(RATE)
+	for i in list:
+		list[i] = int(sin(float(i) * factor) * 127.0)
+	return audio.num2chr(list)
+
+def softclip(s):
+	if '\177' not in s and '\200' not in s:
+		return s
+	num = audio.chr2num(s)
+	extremes = (-128, 127)
+	for i in range(1, len(num)-1):
+		if num[i] in extremes:
+			num[i] = (num[i-1] + num[i+1]) / 2
+	return audio.num2chr(num)
+
+def demo():
+	gday = load('gday')[1000:6000]
+	save(gday, 'gday0')
+	gg = [gday]
+	for i in range(1, 10):
+		for g in gg: play(g)
+		g = stretch(gday, 10, 10-i)
+		save(g, 'gday' + `i`)
+		gg.append(g)
+	while 1:
+		for g in gg: play(g)
diff --git a/Lib/irix5/panel.py b/Lib/irix5/panel.py
new file mode 100755
index 0000000..eb11508
--- /dev/null
+++ b/Lib/irix5/panel.py
@@ -0,0 +1,281 @@
+# Module 'panel'
+#
+# Support for the Panel library.
+# Uses built-in module 'pnl'.
+# Applciations should use 'panel.function' instead of 'pnl.function';
+# most 'pnl' functions are transparently exported by 'panel',
+# but dopanel() is overridden and you have to use this version
+# if you want to use callbacks.
+
+
+import pnl
+
+
+debug = 0
+
+
+# Test if an object is a list.
+#
+def is_list(x):
+	return type(x) = type([])
+
+
+# Reverse a list.
+#
+def reverse(list):
+	res = []
+	for item in list:
+		res.insert(0, item)
+	return res
+
+
+# Get an attribute of a list, which may itself be another list.
+# Don't use 'prop' for name.
+#
+def getattrlist(list, name):
+	for item in list:
+		if item and is_list(item) and item[0] = name:
+			return item[1:]
+	return []
+
+
+# Get a property of a list, which may itself be another list.
+#
+def getproplist(list, name):
+	for item in list:
+		if item and is_list(item) and item[0] = 'prop':
+			if len(item) > 1 and item[1] = name:
+				return item[2:]
+	return []
+
+
+# Test if an actuator description contains the property 'end-of-group'
+#
+def is_endgroup(list):
+	x = getproplist(list, 'end-of-group')
+	return (x and x[0] = '#t')
+
+
+# Neatly display an actuator definition given as S-expression
+# the prefix string is printed before each line.
+#
+def show_actuator(prefix, a):
+	for item in a:
+		if not is_list(item):
+			print prefix, item
+		elif item and item[0] = 'al':
+			print prefix, 'Subactuator list:'
+			for a in item[1:]:
+				show_actuator(prefix + '    ', a)
+		elif len(item) = 2:
+			print prefix, item[0], '=>', item[1]
+		elif len(item) = 3 and item[0] = 'prop':
+			print prefix, 'Prop', item[1], '=>',
+			print item[2]
+		else:
+			print prefix, '?', item
+
+
+# Neatly display a panel.
+#
+def show_panel(prefix, p):
+	for item in p:
+		if not is_list(item):
+			print prefix, item
+		elif item and item[0] = 'al':
+			print prefix, 'Actuator list:'
+			for a in item[1:]:
+				show_actuator(prefix + '    ', a)
+		elif len(item) = 2:
+			print prefix, item[0], '=>', item[1]
+		elif len(item) = 3 and item[0] = 'prop':
+			print prefix, 'Prop', item[1], '=>',
+			print item[2]
+		else:
+			print prefix, '?', item
+
+
+# Exception raised by build_actuator or build_panel.
+#
+panel_error = 'panel error'
+
+
+# Dummy callback used to initialize the callbacks.
+#
+def dummy_callback(arg):
+	pass
+
+
+# Assign attributes to members of the target.
+# Attribute names in exclist are ignored.
+# The member name is the attribute name prefixed with the prefix.
+#
+def assign_members(target, attrlist, exclist, prefix):
+	for item in attrlist:
+		if is_list(item) and len(item) = 2 and item[0] not in exclist:
+			name, value = item[0], item[1]
+			ok = 1
+			if value[0] in '-0123456789':
+				value = eval(value)
+			elif value[0] = '"':
+				value = value[1:-1]
+			elif value = 'move-then-resize':
+				# Strange default set by Panel Editor...
+				ok = 0
+			else:
+				print 'unknown value', value, 'for', name
+				ok = 0
+			if ok:
+				lhs = 'target.' + prefix + name
+				stmt = lhs + '=' + `value`
+				if debug: print 'exec', stmt
+				try:
+					exec(stmt + '\n')
+				except KeyboardInterrupt: # Don't catch this!
+					raise KeyboardInterrupt
+				except:
+					print 'assign failed:', stmt
+
+
+# Build a real actuator from an actuator descriptior.
+# Return a pair (actuator, name).
+#
+def build_actuator(descr):
+	namelist = getattrlist(descr, 'name')
+	if namelist:
+		# Assume it is a string
+		actuatorname = namelist[0][1:-1]
+	else:
+		actuatorname = ''
+	type = descr[0]
+	if type[:4] = 'pnl_': type = type[4:]
+	act = pnl.mkact(type)
+	act.downfunc = act.activefunc = act.upfunc = dummy_callback
+	#
+	assign_members(act, descr[1:], ('al', 'data', 'name'), '')
+	#
+	# Treat actuator-specific data
+	#
+	datalist = getattrlist(descr, 'data')
+	prefix = ''
+	if type[-4:] = 'puck':
+		prefix = 'puck_'
+	elif type = 'mouse':
+		prefix = 'mouse_'
+	assign_members(act, datalist, (), prefix)
+	#
+	return act, actuatorname
+
+
+# Build all sub-actuators and add them to the super-actuator.
+# The super-actuator must already have been added to the panel.
+# Sub-actuators with defined names are added as members to the panel
+# so they can be referenced as p.name.
+#
+# Note: I have no idea how panel.endgroup() works when applied
+# to a sub-actuator.
+#
+def build_subactuators(panel, super_act, al):
+	#
+	# This is nearly the same loop as below in build_panel(),
+	# except a call is made to addsubact() instead of addact().
+	#
+	for a in al:
+		act, name = build_actuator(a)
+		act.addsubact(super_act)
+		if name:
+			stmt = 'panel.' + name + ' = act'
+			if debug: print 'exec', stmt
+			exec(stmt + '\n')
+		if is_endgroup(a):
+			panel.endgroup()
+		sub_al = getattrlist(a, 'al')
+		if sub_al:
+			build_subactuators(panel, act, sub_al)
+	#
+	# Fix the actuator to which whe just added subactuators.
+	# This can't hurt (I hope) and is needed for the scroll actuator.
+	#
+	super_act.fixact()
+
+
+# Build a real panel from a panel definition.
+# Return a panel object p, where for each named actuator a, p.name is a
+# reference to a.
+#
+def build_panel(descr):
+	#
+	# Sanity check
+	#
+	if (not descr) or descr[0] <> 'panel':
+		raise panel_error, 'panel description must start with "panel"'
+	#
+	if debug: show_panel('', descr)
+	#
+	# Create an empty panel
+	#
+	panel = pnl.mkpanel()
+	#
+	# Assign panel attributes
+	#
+	assign_members(panel, descr[1:], ('al'), '')
+	#
+	# Look for actuator list
+	#
+	al = getattrlist(descr, 'al')
+	#
+	# The order in which actuators are created is important
+	# because of the endgroup() operator.
+	# Unfortunately the Panel Editor outputs the actuator list
+	# in reverse order, so we reverse it here.
+	#
+	al = reverse(al)
+	#
+	for a in al:
+		act, name = build_actuator(a)
+		act.addact(panel)
+		if name:
+			stmt = 'panel.' + name + ' = act'
+			exec(stmt + '\n')
+		if is_endgroup(a):
+			panel.endgroup()
+		sub_al = getattrlist(a, 'al')
+		if sub_al:
+			build_subactuators(panel, act, sub_al)
+	#
+	return panel
+
+
+# Wrapper around pnl.dopanel() which calls call-back functions.
+#
+def my_dopanel():
+	# Extract only the first 4 elements to allow for future expansion
+	a, down, active, up = pnl.dopanel()[:4]
+	if down:
+		down.downfunc(down)
+	if active:
+		active.activefunc(active)
+	if up:
+		up.upfunc(up)
+	return a
+
+
+# Create one or more panels from a description file (S-expressions)
+# generated by the Panel Editor.
+# 
+def defpanellist(file):
+	import parser
+	descrlist = parser.parse_file(open(file, 'r'))
+	panellist = []
+	for descr in descrlist:
+		panellist.append(build_panel(descr))
+	return panellist
+
+
+# Import everything from built-in method pnl, so the user can always
+# use panel.foo() instead of pnl.foo().
+# This gives *no* performance penalty once this module is imported.
+#
+from pnl import *			# for export
+
+dopanel = my_dopanel			# override pnl.dopanel
diff --git a/Lib/irix5/panelparser.py b/Lib/irix5/panelparser.py
new file mode 100755
index 0000000..9c9ee02
--- /dev/null
+++ b/Lib/irix5/panelparser.py
@@ -0,0 +1,128 @@
+# Module 'parser'
+#
+# Parse S-expressions output by the Panel Editor
+# (which is written in Scheme so it can't help writing S-expressions).
+#
+# See notes at end of file.
+
+
+whitespace = ' \t\n'
+operators = '()\''
+separators = operators + whitespace + ';' + '"'
+
+
+# Tokenize a string.
+# Return a list of tokens (strings).
+#
+def tokenize_string(s):
+	tokens = []
+	while s:
+		c = s[:1]
+		if c in whitespace:
+			s = s[1:]
+		elif c = ';':
+			s = ''
+		elif c = '"':
+			n = len(s)
+			i = 1
+			while i < n:
+				c = s[i]
+				i = i+1
+				if c = '"': break
+				if c = '\\': i = i+1
+			tokens.append(s[:i])
+			s = s[i:]
+		elif c in operators:
+			tokens.append(c)
+			s = s[1:]
+		else:
+			n = len(s)
+			i = 1
+			while i < n:
+				if s[i] in separators: break
+				i = i+1
+			tokens.append(s[:i])
+			s = s[i:]
+	return tokens
+
+
+# Tokenize a whole file (given as file object, not as file name).
+# Return a list of tokens (strings).
+#
+def tokenize_file(fp):
+	tokens = []
+	while 1:
+		line = fp.readline()
+		if not line: break
+		tokens = tokens + tokenize_string(line)
+	return tokens
+
+
+# Exception raised by parse_exr.
+#
+syntax_error = 'syntax error'
+
+
+# Parse an S-expression.
+# Input is a list of tokens as returned by tokenize_*().
+# Return a pair (expr, tokens)
+# where expr is a list representing the s-expression,
+# and tokens contains the remaining tokens.
+# May raise syntax_error.
+#
+def parse_expr(tokens):
+	if (not tokens) or tokens[0] <> '(':
+		raise syntax_error, 'expected "("'
+	tokens = tokens[1:]
+	expr = []
+	while 1:
+		if not tokens:
+			raise syntax_error, 'missing ")"'
+		if tokens[0] = ')':
+			return expr, tokens[1:]
+		elif tokens[0] = '(':
+			subexpr, tokens = parse_expr(tokens)
+			expr.append(subexpr)
+		else:
+			expr.append(tokens[0])
+			tokens = tokens[1:]
+
+
+# Parse a file (given as file object, not as file name).
+# Return a list of parsed S-expressions found at the top level.
+#
+def parse_file(fp):
+	tokens = tokenize_file(fp)
+	exprlist = []
+	while tokens:
+		expr, tokens = parse_expr(tokens)
+		exprlist.append(expr)
+	return exprlist
+
+
+# EXAMPLE:
+#
+# The input
+#	'(hip (hop hur-ray))'
+#
+# passed to tokenize_string() returns the token list
+#	['(', 'hip', '(', 'hop', 'hur-ray', ')', ')']
+#
+# When this is passed to parse_expr() it returns the expression
+#	['hip', ['hop', 'hur-ray']]
+# plus an empty token list (because there are no tokens left.
+#
+# When a file containing the example is passed to parse_file() it returns
+# a list whose only element is the output of parse_expr() above:
+#	[['hip', ['hop', 'hur-ray']]]
+
+
+# TOKENIZING:
+#
+# Comments start with semicolon (;) and continue till the end of the line.
+#
+# Tokens are separated by whitespace, except the following characters
+# always form a separate token (outside strings):
+#	( ) '
+# Strings are enclosed in double quotes (") and backslash (\) is used
+# as escape character in strings.
diff --git a/Lib/lib-old/dump.py b/Lib/lib-old/dump.py
new file mode 100644
index 0000000..cecc275
--- /dev/null
+++ b/Lib/lib-old/dump.py
@@ -0,0 +1,63 @@
+# Module 'dump'
+#
+# Print python code that reconstructs a variable.
+# This only works in certain cases.
+#
+# It works fine for:
+# - ints and floats (except NaNs and other weird things)
+# - strings
+# - compounds and lists, provided it works for all their elements
+# - imported modules, provided their name is the module name
+#
+# It works for top-level dictionaries but not for dictionaries
+# contained in other objects (could be made to work with some hassle
+# though).
+#
+# It does not work for functions (all sorts), classes, class objects,
+# windows, files etc.
+#
+# Finally, objects referenced by more than one name or contained in more
+# than one other object lose their sharing property (this is bad for
+# strings used as exception identifiers, for instance).
+
+# Dump a whole symbol table
+#
+def dumpsymtab(dict):
+	for key in dict.keys():
+		dumpvar(key, dict[key])
+
+# Dump a single variable
+#
+def dumpvar(name, x):
+	import sys
+	t = type(x)
+	if t = type({}):
+		print name, '= {}'
+		for key in x.keys():
+			item = x[key]
+			if not printable(item):
+				print '#',
+			print name, '[', `key`, '] =', `item`
+	elif t in (type(''), type(0), type(0.0), type([]), type(())):
+		if not printable(x):
+			print '#',
+		print name, '=', `x`
+	elif t = type(sys):
+		print 'import', name, '#', x
+	else:
+		print '#', name, '=', x
+
+# check if a value is printable in a way that can be read back with input()
+#
+def printable(x):
+	t = type(x)
+	if t in (type(''), type(0), type(0.0)):
+		return 1
+	if t in (type([]), type(())):
+		for item in x:
+			if not printable(item):
+				return 0
+		return 1
+	if x = {}:
+		return 1
+	return 0
diff --git a/Lib/lib-old/rand.py b/Lib/lib-old/rand.py
new file mode 100644
index 0000000..0616483
--- /dev/null
+++ b/Lib/lib-old/rand.py
@@ -0,0 +1,12 @@
+# Module 'rand'
+
+import whrandom
+
+def srand(seed):
+	whrandom.seed(seed%256, seed/256%256, seed/65536%256)
+
+def rand():
+	return int(whrandom.random() * 32768.0) % 32768
+
+def choice(seq):
+	return seq[rand() % len(seq)]
diff --git a/Lib/lib-old/util.py b/Lib/lib-old/util.py
new file mode 100644
index 0000000..dc67686
--- /dev/null
+++ b/Lib/lib-old/util.py
@@ -0,0 +1,9 @@
+# Module 'util' -- some useful functions that dont fit elsewhere
+
+# Remove an item from a list at most once
+#
+def remove(item, list):
+	for i in range(len(list)):
+		if list[i] = item:
+			del list[i]
+			break
diff --git a/Lib/lib-stdwin/anywin.py b/Lib/lib-stdwin/anywin.py
new file mode 100644
index 0000000..bb7e865
--- /dev/null
+++ b/Lib/lib-stdwin/anywin.py
@@ -0,0 +1,14 @@
+# Module 'anywin'
+# Open a file or directory in a window
+
+import dirwin
+import filewin
+import path
+
+def open(name):
+	print 'opening', name, '...'
+	if path.isdir(name):
+		w = dirwin.open(name)
+	else:
+		w = filewin.open(name)
+	return w
diff --git a/Lib/lib-stdwin/dirwin.py b/Lib/lib-stdwin/dirwin.py
new file mode 100644
index 0000000..5df85e7
--- /dev/null
+++ b/Lib/lib-stdwin/dirwin.py
@@ -0,0 +1,28 @@
+# Module 'dirwin'
+
+# Directory windows, a subclass of listwin
+
+import gwin
+import listwin
+import anywin
+import path
+import dircache
+
+def action(w, string, i, detail):
+	(h, v), clicks, button, mask = detail
+	if clicks = 2:
+		name = path.cat(w.name, string)
+		try:
+			w = anywin.open(name)
+		except posix.error, why:
+			stdwin.message('Can\'t open ' + name + ': ' + why[1])
+
+def open(name):
+	name = path.cat(name, '')
+	list = dircache.opendir(name)[:]
+	list.sort()
+	dircache.annotate(name, list)
+	w = listwin.open(name, list)
+	w.name = name
+	w.action = action
+	return w
diff --git a/Lib/lib-stdwin/filewin.py b/Lib/lib-stdwin/filewin.py
new file mode 100644
index 0000000..1beb0b6
--- /dev/null
+++ b/Lib/lib-stdwin/filewin.py
@@ -0,0 +1,31 @@
+# Module 'filewin'
+# File windows, a subclass of textwin (which is a subclass of gwin)
+
+import stdwin
+import textwin
+import path
+
+builtin_open = open
+
+def readfile(fn): # Return a string containing the file's contents
+	fp = builtin_open(fn, 'r')
+	a = ''
+	n = 8096
+	while 1:
+		b = fp.read(n)
+		if not b: break
+		a = a + b
+	return a
+
+
+# FILE WINDOW
+
+def open_readonly(fn): # Open a file window
+	w = textwin.open_readonly(fn, readfile(fn))
+	w.fn = fn
+	return w
+
+def open(fn): # Open a file window
+	w = textwin.open(fn, readfile(fn))
+	w.fn = fn
+	return w
diff --git a/Lib/lib-stdwin/gwin.py b/Lib/lib-stdwin/gwin.py
new file mode 100644
index 0000000..15aa432
--- /dev/null
+++ b/Lib/lib-stdwin/gwin.py
@@ -0,0 +1,118 @@
+# Module 'gwin'
+# Generic stdwin windows
+
+# This is used as a base class from which to derive other window types.
+# The mainloop() function here is an event dispatcher for all window types.
+
+import stdwin
+import stdwinsupport
+
+S = stdwinsupport			# Shorthand
+
+windows = []				# List of open windows
+
+
+# Open a window
+
+def open(title):			# Open a generic window
+	w = stdwin.open(title)
+	stdwin.setdefwinsize(0, 0)
+	# Set default event handlers
+	w.draw = nop
+	w.char = nop
+	w.mdown = nop
+	w.mmove = nop
+	w.mup = nop
+	w.m2down = m2down
+	w.m2up = m2up
+	w.size = nop
+	w.move = nop
+	w.activate = w.deactivate = nop
+	w.timer = nop
+	# default command handlers
+	w.close = close
+	w.tab = tab
+	w.enter = enter
+	w.backspace = backspace
+	w.arrow = arrow
+	w.kleft = w.kup = w.kright = w.kdown = nop
+	windows.append(w)
+	return w
+
+
+# Generic event dispatching
+
+def mainloop():				# Handle events until no windows left
+	while windows:
+		treatevent(stdwin.getevent())
+
+def treatevent(e):			# Handle a stdwin event
+	type, w, detail = e
+	if type = S.we_draw:
+		w.draw(w, detail)
+	elif type = S.we_menu:
+		m, item = detail
+		m.action[item](w, m, item)
+	elif type = S.we_command:
+		treatcommand(w, detail)
+	elif type = S.we_char:
+		w.char(w, detail)
+	elif type = S.we_mouse_down:
+		if detail[1] > 1: w.m2down(w, detail)
+		else: w.mdown(w, detail)
+	elif type = S.we_mouse_move:
+		w.mmove(w, detail)
+	elif type = S.we_mouse_up:
+		if detail[1] > 1: w.m2up(w, detail)
+		else: w.mup(w, detail)
+	elif type = S.we_size:
+		w.size(w, w.getwinsize())
+	elif type = S.we_activate:
+		w.activate(w)
+	elif type = S.we_deactivate:
+		w.deactivate(w)
+	elif type = S.we_move:
+		w.move(w)
+	elif type = S.we_timer:
+		w.timer(w)
+
+def treatcommand(w, type):		# Handle a we_command event
+	if type = S.wc_close:
+		w.close(w)
+	elif type = S.wc_return:
+		w.enter(w)
+	elif type = S.wc_tab:
+		w.tab(w)
+	elif type = S.wc_backspace:
+		w.backspace(w)
+	elif type in (S.wc_left, S.wc_up, S.wc_right, S.wc_down):
+		w.arrow(w, type)
+
+
+# Methods
+
+def close(w):				# Close method
+	for i in range(len(windows)):
+		if windows[i] is w:
+			del windows[i]
+			break
+
+def arrow(w, detail):			# Arrow key method
+	if detail = S.wc_left:
+		w.kleft(w)
+	elif detail = S.wc_up:
+		w.kup(w)
+	elif detail = S.wc_right:
+		w.kright(w)
+	elif detail = S.wc_down:
+		w.kdown(w)
+
+
+# Trivial methods
+
+def tab(w): w.char(w, '\t')
+def enter(w): w.char(w, '\n')		# 'return' is a Python reserved word
+def backspace(w): w.char(w, '\b')
+def m2down(w, detail): w.mdown(w, detail)
+def m2up(w, detail): w.mup(w, detail)
+def nop(args): pass
diff --git a/Lib/lib-stdwin/listwin.py b/Lib/lib-stdwin/listwin.py
new file mode 100644
index 0000000..9480a81
--- /dev/null
+++ b/Lib/lib-stdwin/listwin.py
@@ -0,0 +1,47 @@
+# Module 'listwin'
+# List windows, a subclass of gwin
+
+import gwin
+import stdwin
+
+def maxlinewidth(a): # Compute maximum textwidth of lines in a sequence
+	max = 0
+	for line in a:
+		width = stdwin.textwidth(line)
+		if width > max: max = width
+	return max
+
+def action(w, string, i, detail): # Default item selection method
+	pass
+
+def mup(w, detail): # Mouse up method
+	(h, v), clicks, button, mask = detail
+	i = divmod(v, w.lineheight)[0]
+	if 0 <= i < len(w.data):
+		w.action(w, w.data[i], i, detail)
+
+def draw(w, ((left, top), (right, bottom))): # Text window draw method
+	data = w.data
+	d = w.begindrawing()
+	lh = w.lineheight
+	itop = top/lh
+	ibot = (bottom-1)/lh + 1
+	if itop < 0: itop = 0
+	if ibot > len(data): ibot = len(data)
+	for i in range(itop, ibot): d.text((0, i*lh), data[i])
+
+def open(title, data): # Display a list of texts in a window
+	lineheight = stdwin.lineheight()
+	h, v = maxlinewidth(data), len(data)*lineheight
+	h0, v0 = h + stdwin.textwidth(' '), v + lineheight
+	if h0 > stdwin.textwidth(' ')*80: h0 = 0
+	if v0 > stdwin.lineheight()*24: v0 = 0
+	stdwin.setdefwinsize(h0, v0)
+	w = gwin.open(title)
+	w.setdocsize(h, v)
+	w.lineheight = lineheight
+	w.data = data
+	w.draw = draw
+	w.action = action
+	w.mup = mup
+	return w
diff --git a/Lib/lib-stdwin/rect.py b/Lib/lib-stdwin/rect.py
new file mode 100644
index 0000000..c044b9f
--- /dev/null
+++ b/Lib/lib-stdwin/rect.py
@@ -0,0 +1,87 @@
+# Module 'rect'.
+#
+# Operations on rectangles.
+# There is some normalization: all results return the object 'empty'
+# if their result would contain no points.
+
+
+# Exception.
+#
+error = 'rect.error'
+
+
+# The empty rectangle.
+#
+empty = (0, 0), (0, 0)
+
+
+# Check if a rectangle is empty.
+#
+def is_empty((left, top), (right, bottom)):
+	return left >= right or top >= bottom
+
+
+# Compute the intersection or two or more rectangles.
+# This works with a list or tuple argument.
+#
+def intersect(list):
+	if not list: raise error, 'intersect called with empty list'
+	if is_empty(list[0]): return empty
+	(left, top), (right, bottom) = list[0]
+	for rect in list[1:]:
+		if not is_empty(rect):
+			(l, t), (r, b) = rect
+			if left < l: left = l
+			if top < t: top = t
+			if right > r: right = r
+			if bottom > b: bottom = b
+			if is_empty((left, top), (right, bottom)):
+				return empty
+	return (left, top), (right, bottom)
+
+
+# Compute the smallest rectangle containing all given rectangles.
+# This works with a list or tuple argument.
+#
+def union(list):
+	(left, top), (right, bottom) = empty
+	for (l, t), (r, b) in list[1:]:
+		if not is_empty((l, t), (r, b)):
+			if l < left: left = l
+			if t < top: top = t
+			if r > right: right = r
+			if b > bottom: bottom = b
+	res = (left, top), (right, bottom)
+	if is_empty(res):
+		return empty
+	return res
+
+
+# Check if a point is in a rectangle.
+#
+def pointinrect((h, v), ((left, top), (right, bottom))):
+	return left <= h < right and top <= v < bottom
+
+
+# Return a rectangle that is dh, dv inside another
+#
+def inset(((left, top), (right, bottom)), (dh, dv)):
+	left = left + dh
+	top = top + dv
+	right = right - dh
+	bottom = bottom - dv
+	r = (left, top), (right, bottom)
+	if is_empty(r):
+		return empty
+	else:
+		return r
+
+
+# Conversions between rectangles and 'geometry tuples',
+# given as origin (h, v) and dimensions (width, height).
+#
+def rect2geom((left, top), (right, bottom)):
+	return (left, top), (right-left, bottom-top)
+
+def geom2rect((h, v), (width, height)):
+	return (h, v), (h+width, v+height)
diff --git a/Lib/lib-stdwin/stdwinevents.py b/Lib/lib-stdwin/stdwinevents.py
new file mode 100644
index 0000000..889dd95
--- /dev/null
+++ b/Lib/lib-stdwin/stdwinevents.py
@@ -0,0 +1,36 @@
+# Module 'stdwinevents' -- Constants for stdwin event types
+#
+# Suggested usage:
+#	from stdwinevents import *
+
+# The function stdwin.getevent() returns a tuple containing:
+#	(type, window, detail)
+# where detail may be <no value> or a value depending on type, see below:
+
+# Values for type:
+
+WE_NULL       =  0	# not reported -- means 'no event' internally
+WE_ACTIVATE   =  1	# detail is <no object>
+WE_CHAR       =  2	# detail is the character
+WE_COMMAND    =  3	# detail is one of the WC_* constants below
+WE_MOUSE_DOWN =  4	# detail is ((h, v), clicks, button, mask)
+WE_MOUSE_MOVE =  5	# ditto
+WE_MOUSE_UP   =  6	# ditto
+WE_MENU       =  7	# detail is (menu, item)
+WE_SIZE       =  8	# detail is (width, height) [???]
+WE_MOVE       =  9	# not reported -- reserved for future use
+WE_DRAW       = 10	# detail is ((left, top), (right, bottom))
+WE_TIMER      = 11	# detail is <no object>
+WE_DEACTIVATE = 12	# detail is <no object>
+
+# Values for detail when type is WE_COMMAND:
+
+WC_CLOSE      =  1	# user hit close box
+WC_LEFT       =  2	# left arrow key
+WC_RIGHT      =  3	# right arrow key
+WC_UP         =  4	# up arrow key
+WC_DOWN       =  5	# down arrow key
+WC_CANCEL     =  6	# not reported -- turned into KeyboardInterrupt
+WC_BACKSPACE  =  7	# backspace key
+WC_TAB        =  8	# tab key
+WC_RETURN     =  9	# return or enter key
diff --git a/Lib/lib-stdwin/tablewin.py b/Lib/lib-stdwin/tablewin.py
new file mode 100644
index 0000000..05a954e
--- /dev/null
+++ b/Lib/lib-stdwin/tablewin.py
@@ -0,0 +1,237 @@
+# Module 'tablewin'
+
+# Display a table, with per-item actions:
+
+#	   A1   |   A2   |   A3   |  ....  |   AN
+#	   B1   |   B2   |   B3   |  ....  |   BN
+#	   C1   |   C2   |   C3   |  ....  |   CN
+#	   ..   |   ..   |   ..   |  ....  |   ..
+#	   Z1   |   Z2   |   Z3   |  ....  |   ZN
+
+# Not all columns need to have the same length.
+# The data structure is a list of columns;
+# each column is a list of items.
+# Each item is a pair of a string and an action procedure.
+# The first item may be a column title.
+
+import stdwin
+import gwin
+
+def open(title, data): # Public function to open a table window
+	#
+	# Set geometry parameters (one day, these may be changeable)
+	#
+	margin = stdwin.textwidth('  ')
+	lineheight = stdwin.lineheight()
+	#
+	# Geometry calculations
+	#
+	colstarts = [0]
+	totwidth = 0
+	maxrows = 0
+	for coldata in data:
+		# Height calculations
+		rows = len(coldata)
+		if rows > maxrows: maxrows = rows
+		# Width calculations
+		width = colwidth(coldata) + margin
+		totwidth = totwidth + width
+		colstarts.append(totwidth)
+	#
+	# Calculate document and window height
+	#
+	docwidth, docheight = totwidth, maxrows*lineheight
+	winwidth, winheight = docwidth, docheight
+	if winwidth > stdwin.textwidth('n')*100: winwidth = 0
+	if winheight > stdwin.lineheight()*30: winheight = 0
+	#
+	# Create the window
+	#
+	stdwin.setdefwinsize(winwidth, winheight)
+	w = gwin.open(title)
+	#
+	# Set properties and override methods
+	#
+	w.data = data
+	w.margin = margin
+	w.lineheight = lineheight
+	w.colstarts = colstarts
+	w.totwidth = totwidth
+	w.maxrows = maxrows
+	w.selection = (-1, -1)
+	w.lastselection = (-1, -1)
+	w.selshown = 0
+	w.setdocsize(docwidth, docheight)
+	w.draw = draw
+	w.mup = mup
+	w.arrow = arrow
+	#
+	# Return
+	#
+	return w
+
+def update(w, data): # Change the data
+	#
+	# Hide selection
+	#
+	hidesel(w, w.begindrawing())
+	#
+	# Get old geometry parameters
+	#
+	margin = w.margin
+	lineheight = w.lineheight
+	#
+	# Geometry calculations
+	#
+	colstarts = [0]
+	totwidth = 0
+	maxrows = 0
+	for coldata in data:
+		# Height calculations
+		rows = len(coldata)
+		if rows > maxrows: maxrows = rows
+		# Width calculations
+		width = colwidth(coldata) + margin
+		totwidth = totwidth + width
+		colstarts.append(totwidth)
+	#
+	# Calculate document and window height
+	#
+	docwidth, docheight = totwidth, maxrows*lineheight
+	#
+	# Set changed properties and change window size
+	#
+	w.data = data
+	w.colstarts = colstarts
+	w.totwidth = totwidth
+	w.maxrows = maxrows
+	w.change((0, 0), (10000, 10000))
+	w.setdocsize(docwidth, docheight)
+	w.change((0, 0), (docwidth, docheight))
+	#
+	# Show selection, or forget it if out of range
+	#
+	showsel(w, w.begindrawing())
+	if not w.selshown: w.selection = (-1, -1)
+
+def colwidth(coldata): # Subroutine to calculate column width
+	maxwidth = 0
+	for string, action in coldata:
+		width = stdwin.textwidth(string)
+		if width > maxwidth: maxwidth = width
+	return maxwidth
+
+def draw(w, ((left, top), (right, bottom))): # Draw method
+	ileft = whichcol(w, left)
+	iright = whichcol(w, right-1) + 1
+	if iright > len(w.data): iright = len(w.data)
+	itop = divmod(top, w.lineheight)[0]
+	if itop < 0: itop = 0
+	ibottom, remainder = divmod(bottom, w.lineheight)
+	if remainder: ibottom = ibottom + 1
+	d = w.begindrawing()
+	if ileft <= w.selection[0] < iright:
+		if itop <= w.selection[1] < ibottom:
+			hidesel(w, d)
+	d.erase((left, top), (right, bottom))
+	for i in range(ileft, iright):
+		col = w.data[i]
+		jbottom = len(col)
+		if ibottom < jbottom: jbottom = ibottom
+		h = w.colstarts[i]
+		v = itop * w.lineheight
+		for j in range(itop, jbottom):
+			string, action = col[j]
+			d.text((h, v), string)
+			v = v + w.lineheight
+	showsel(w, d)
+
+def mup(w, detail): # Mouse up method
+	(h, v), nclicks, button, mask = detail
+	icol = whichcol(w, h)
+	if 0 <= icol < len(w.data):
+		irow = divmod(v, w.lineheight)[0]
+		col = w.data[icol]
+		if 0 <= irow < len(col):
+			string, action = col[irow]
+			action(w, string, (icol, irow), detail)
+
+def whichcol(w, h): # Return column number (may be >= len(w.data))
+	for icol in range(0, len(w.data)):
+		if h < w.colstarts[icol+1]:
+			return icol
+	return len(w.data)
+
+def arrow(w, type):
+	import stdwinsupport
+	S = stdwinsupport
+	if type = S.wc_left:
+		incr = -1, 0
+	elif type = S.wc_up:
+		incr = 0, -1
+	elif type = S.wc_right:
+		incr = 1, 0
+	elif type = S.wc_down:
+		incr = 0, 1
+	else:
+		return
+	icol, irow = w.lastselection
+	icol = icol + incr[0]
+	if icol < 0: icol = len(w.data)-1
+	if icol >= len(w.data): icol = 0
+	if 0 <= icol < len(w.data):
+		irow = irow + incr[1]
+		if irow < 0: irow = len(w.data[icol]) - 1
+		if irow >= len(w.data[icol]): irow = 0
+	else:
+		irow = 0
+	if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
+		w.lastselection = icol, irow
+		string, action = w.data[icol][irow]
+		detail = (0, 0), 1, 1, 1
+		action(w, string, (icol, irow), detail)
+
+
+# Selection management
+# TO DO: allow multiple selected entries
+
+def select(w, selection): # Public function to set the item selection
+	d = w.begindrawing()
+	hidesel(w, d)
+	w.selection = selection
+	showsel(w, d)
+	if w.selshown: lastselection = selection
+
+def hidesel(w, d): # Hide the selection, if shown
+	if w.selshown: invertsel(w, d)
+
+def showsel(w, d): # Show the selection, if hidden
+	if not w.selshown: invertsel(w, d)
+
+def invertsel(w, d): # Invert the selection, if valid
+	icol, irow = w.selection
+	if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
+		left = w.colstarts[icol]
+		right = w.colstarts[icol+1]
+		top = irow * w.lineheight
+		bottom = (irow+1) * w.lineheight
+		d.invert((left, top), (right, bottom))
+		w.selshown = (not w.selshown)
+
+
+# Demonstration
+
+def demo_action(w, string, (icol, irow), detail): # Action function for demo
+	select(w, (irow, icol))
+
+def demo(): # Demonstration
+	da = demo_action # shorthand
+	col0 = [('a1', da), ('bbb1', da), ('c1', da)]
+	col1 = [('a2', da), ('bbb2', da)]
+	col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)]
+	col3 = []
+	for i in range(1, 31): col3.append('xxx' + `i`, da)
+	data = [col0, col1, col2, col3]
+	w = open('tablewin.demo', data)
+	gwin.mainloop()
+	return w
diff --git a/Lib/lib-stdwin/textwin.py b/Lib/lib-stdwin/textwin.py
new file mode 100644
index 0000000..2631ca4
--- /dev/null
+++ b/Lib/lib-stdwin/textwin.py
@@ -0,0 +1,119 @@
+# Module 'textwin'
+
+# Text windows, a subclass of gwin
+
+import stdwin
+import stdwinsupport
+import gwin
+
+S = stdwinsupport			# Shorthand
+
+
+def fixsize(w):
+	docwidth, docheight = w.text.getrect()[1]
+	winheight = w.getwinsize()[1]
+	if winheight > docheight: docheight = winheight
+	w.setdocsize(0, docheight)
+	fixeditmenu(w)
+
+def cut(w, m, id):
+	s = w.text.getfocustext()
+	if s:
+		stdwin.setcutbuffer(s)
+		w.text.replace('')
+		fixsize(w)
+
+def copy(w, m, id):
+	s = w.text.getfocustext()
+	if s:
+		stdwin.setcutbuffer(s)
+		fixeditmenu(w)
+
+def paste(w, m, id):
+	w.text.replace(stdwin.getcutbuffer())
+	fixsize(w)
+
+def addeditmenu(w):
+	m = w.editmenu = w.menucreate('Edit')
+	m.action = []
+	m.additem('Cut', 'X')
+	m.action.append(cut)
+	m.additem('Copy', 'C')
+	m.action.append(copy)
+	m.additem('Paste', 'V')
+	m.action.append(paste)
+
+def fixeditmenu(w):
+	m = w.editmenu
+	f = w.text.getfocus()
+	can_copy = (f[0] < f[1])
+	m.enable(1, can_copy)
+	if not w.readonly:
+		m.enable(0, can_copy)
+		m.enable(2, (stdwin.getcutbuffer() <> ''))
+
+def draw(w, area):			# Draw method
+	w.text.draw(area)
+
+def size(w, newsize):			# Size method
+	w.text.move((0, 0), newsize)
+	fixsize(w)
+
+def close(w):				# Close method
+	del w.text  # Break circular ref
+	gwin.close(w)
+
+def char(w, c):				# Char method
+	w.text.replace(c)
+	fixsize(w)
+
+def backspace(w):			# Backspace method
+	void = w.text.event(S.we_command, w, S.wc_backspace)
+	fixsize(w)
+
+def arrow(w, detail):			# Arrow method
+	w.text.arrow(detail)
+	fixeditmenu(w)
+
+def mdown(w, detail):			# Mouse down method
+	void = w.text.event(S.we_mouse_down, w, detail)
+	fixeditmenu(w)
+
+def mmove(w, detail):			# Mouse move method
+	void = w.text.event(S.we_mouse_move, w, detail)
+
+def mup(w, detail):			# Mouse up method
+	void = w.text.event(S.we_mouse_up, w, detail)
+	fixeditmenu(w)
+
+def activate(w):			# Activate method
+	fixeditmenu(w)
+
+def open(title, str):			# Display a string in a window
+	w = gwin.open(title)
+	w.readonly = 0
+	w.text = w.textcreate((0, 0), w.getwinsize())
+	w.text.replace(str)
+	w.text.setfocus(0, 0)
+	addeditmenu(w)
+	fixsize(w)
+	w.draw = draw
+	w.size = size
+	w.close = close
+	w.mdown = mdown
+	w.mmove = mmove
+	w.mup = mup
+	w.char = char
+	w.backspace = backspace
+	w.arrow = arrow
+	w.activate = activate
+	return w
+
+def open_readonly(title, str):		# Same with char input disabled
+	w = open(title, str)
+	w.readonly = 1
+	w.char = w.backspace = gwin.nop
+	# Disable Cut and Paste menu item; leave Copy alone
+	w.editmenu.enable(0, 0)
+	w.editmenu.enable(2, 0)
+	return w
diff --git a/Lib/plat-irix5/DEVICE.py b/Lib/plat-irix5/DEVICE.py
new file mode 100755
index 0000000..00eddfc
--- /dev/null
+++ b/Lib/plat-irix5/DEVICE.py
@@ -0,0 +1,423 @@
+#/**************************************************************************
+# *									  *
+# * 		 Copyright (C) 1984, Silicon Graphics, Inc.		  *
+# *									  *
+# *  These coded instructions, statements, and computer programs  contain  *
+# *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
+# *  are protected by Federal copyright law.  They  may  not be disclosed  *
+# *  to  third  parties  or copied or duplicated in any form, in whole or  *
+# *  in part, without the prior written consent of Silicon Graphics, Inc.  *
+# *									  *
+# **************************************************************************/
+#/* file with device definitions (see /usr/include/device.h) */
+
+NULLDEV =  0
+BUTOFFSET = 1
+VALOFFSET = 256
+TIMOFFSET = 515
+XKBDOFFSET = 143
+INOFFSET = 1024
+OUTOFFSET = 1033
+BUTCOUNT = 190
+VALCOUNT = 27
+TIMCOUNT = 4
+XKBDCOUNT = 28
+INCOUNT =  8
+OUTCOUNT = 8
+#
+#
+#
+#
+BUT0 =   1	
+BUT1 =   2	
+BUT2 =   3	
+BUT3 =   4	
+BUT4 =   5	
+BUT5 =   6	
+BUT6 =   7	
+BUT7 =   8	
+BUT8 =   9	
+BUT9 =  10	
+BUT10 =  11	
+BUT11 =  12	
+BUT12 =  13	
+BUT13 =  14	
+BUT14 =  15	
+BUT15 =  16	
+BUT16 =  17	
+BUT17 =  18	
+BUT18 =  19	
+BUT19 =  20	
+BUT20 =  21	
+BUT21 =  22	
+BUT22 =  23	
+BUT23 =  24	
+BUT24 =  25	
+BUT25 =  26	
+BUT26 =  27	
+BUT27 =  28	
+BUT28 =  29	
+BUT29 =  30	
+BUT30 =  31	
+BUT31 =  32	
+BUT32 =  33	
+BUT33 =  34	
+BUT34 =  35	
+BUT35 =  36	
+BUT36 =  37	
+BUT37 =  38	
+BUT38 =  39	
+BUT39 =  40	
+BUT40 =  41	
+BUT41 =  42	
+BUT42 =  43	
+BUT43 =  44	
+BUT44 =  45	
+BUT45 =  46	
+BUT46 =  47	
+BUT47 =  48	
+BUT48 =  49	
+BUT49 =  50	
+BUT50 =  51	
+BUT51 =  52	
+BUT52 =  53	
+BUT53 =  54	
+BUT54 =  55	
+BUT55 =  56	
+BUT56 =  57	
+BUT57 =  58	
+BUT58 =  59	
+BUT59 =  60	
+BUT60 =  61	
+BUT61 =  62	
+BUT62 =  63	
+BUT63 =  64	
+BUT64 =  65	
+BUT65 =  66	
+BUT66 =  67	
+BUT67 =  68	
+BUT68 =  69	
+BUT69 =  70	
+BUT70 =  71	
+BUT71 =  72	
+BUT72 =  73	
+BUT73 =  74	
+BUT74 =  75	
+BUT75 =  76	
+BUT76 =  77	
+BUT77 =  78	
+BUT78 =  79	
+BUT79 =  80	
+BUT80 =  81	
+BUT81 =  82	
+BUT82 =  83	
+MAXKBDBUT = 83 
+BUT100 =  101	
+BUT101 =  102	
+BUT102 =  103	
+BUT110 =  111	
+BUT111 =  112	
+BUT112 =  113	
+BUT113 =  114	
+BUT114 =  115	
+BUT115 =  116	
+BUT116 =  117	
+BUT117 =  118	
+BUT118 =  119	
+BUT119 =  120	
+BUT120 =  121	
+BUT121 =  122	
+BUT122 =  123	
+BUT123 =  124	
+BUT124 =  125	
+BUT125 =  126	
+BUT126 =  127	
+BUT127 =  128	
+BUT128 =  129	
+BUT129 =  130	
+BUT130 =  131	
+BUT131 =  132	
+BUT132 =  133	
+BUT133 =  134	
+BUT134 =  135	
+BUT135 =  136	
+BUT136 =  137	
+BUT137 =  138	
+BUT138 =  139	
+BUT139 =  140	
+BUT140 =  141	
+BUT141 =  142	
+BUT142 =  143	
+BUT143 =  144	
+BUT144 =  145	
+BUT145 =  146	
+BUT146 =  147	
+BUT147 =  148	
+BUT148 =  149	
+BUT149 =  150	
+BUT150 =  151	
+BUT151 =  152	
+BUT152 =  153	
+BUT153 =  154	
+BUT154 =  155	
+BUT155 =  156 	
+BUT156 =  157	
+BUT157 =  158	
+BUT158 =  159	
+BUT159 =  160	
+BUT160 =  161	
+BUT161 =  162	
+BUT162 =  163	
+BUT163 =  164	
+BUT164 =  165	
+BUT165 =  166	
+BUT166 =  167	
+BUT167 =  168	
+BUT168 =  169	
+BUT181 =  182	
+BUT182 =  183	
+BUT183 =  184	
+BUT184 =  185	
+BUT185 =  186	
+BUT186 =  187	
+BUT187 =  188	
+BUT188 =  189	
+BUT189 =  190	
+MOUSE1 =  101	
+MOUSE2 =  102	
+MOUSE3 =  103	
+LEFTMOUSE = 103 
+MIDDLEMOUSE = 102 
+RIGHTMOUSE = 101 
+LPENBUT =  104	
+BPAD0 =  105	
+BPAD1 =  106	
+BPAD2 =  107	
+BPAD3 =  108	
+LPENVALID = 109 
+SWBASE =  111	
+SW0 =  111	
+SW1 =  112	
+SW2 =  113	
+SW3 =  114	
+SW4 =  115	
+SW5 =  116	
+SW6 =  117	
+SW7 =  118	
+SW8 =  119	
+SW9 =  120	
+SW10 =  121	
+SW11 =  122	
+SW12 =  123	
+SW13 =  124	
+SW14 =  125	
+SW15 =  126	
+SW16 =  127	
+SW17 =  128	
+SW18 =  129	
+SW19 =  130	
+SW20 =  131	
+SW21 =  132	
+SW22 =  133	
+SW23 =  134	
+SW24 =  135	
+SW25 =  136	
+SW26 =  137	
+SW27 =  138	
+SW28 =  139	
+SW29 =  140	
+SW30 =  141	
+SW31 =  142	
+SBBASE =  182	
+SBPICK =  182	
+SBBUT1 =  183	
+SBBUT2 =  184	
+SBBUT3 =  185	
+SBBUT4 =  186	
+SBBUT5 =  187	
+SBBUT6 =  188	
+SBBUT7 =  189	
+SBBUT8 =  190	
+AKEY =  11	
+BKEY =  36	
+CKEY =  28	
+DKEY =  18	
+EKEY =  17	
+FKEY =  19	
+GKEY =  26	
+HKEY =  27	
+IKEY =  40	
+JKEY =  34	
+KKEY =  35	
+LKEY =  42	
+MKEY =  44	
+NKEY =  37	
+OKEY =  41	
+PKEY =  48	
+QKEY =  10	
+RKEY =  24	
+SKEY =  12	
+TKEY =  25	
+UKEY =  33	
+VKEY =  29	
+WKEY =  16	
+XKEY =  21	
+YKEY =  32	
+ZKEY =  20	
+ZEROKEY =  46	
+ONEKEY =  8	
+TWOKEY =  14	
+THREEKEY = 15 
+FOURKEY =  22	
+FIVEKEY =  23	
+SIXKEY =  30	
+SEVENKEY = 31 
+EIGHTKEY = 38 
+NINEKEY =  39	
+BREAKKEY = 1 
+SETUPKEY = 2 
+CTRLKEY =  3	
+LEFTCTRLKEY = CTRLKEY 
+CAPSLOCKKEY = 4 
+RIGHTSHIFTKEY = 5 
+LEFTSHIFTKEY = 6 
+NOSCRLKEY = 13 
+ESCKEY =  7	
+TABKEY =  9	
+RETKEY =  51	
+SPACEKEY = 83 
+LINEFEEDKEY = 60 
+BACKSPACEKEY = 61 
+DELKEY =  62	
+SEMICOLONKEY = 43 
+PERIODKEY = 52 
+COMMAKEY = 45 
+QUOTEKEY = 50 
+ACCENTGRAVEKEY = 55 
+MINUSKEY = 47 
+VIRGULEKEY = 53 
+BACKSLASHKEY = 57 
+EQUALKEY = 54 
+LEFTBRACKETKEY = 49 
+RIGHTBRACKETKEY = 56 
+LEFTARROWKEY = 73 
+DOWNARROWKEY = 74 
+RIGHTARROWKEY = 80 
+UPARROWKEY = 81 
+PAD0 =  59	
+PAD1 =  58	
+PAD2 =  64	
+PAD3 =  65	
+PAD4 =  63	
+PAD5 =  69	
+PAD6 =  70	
+PAD7 =  67	
+PAD8 =  68	
+PAD9 =  75	
+PADPF1 =  72	
+PADPF2 =  71	
+PADPF3 =  79	
+PADPF4 =  78	
+PADPERIOD = 66 
+PADMINUS = 76 
+PADCOMMA = 77 
+PADENTER = 82 
+LEFTALTKEY  = 143
+RIGHTALTKEY  = 144
+RIGHTCTRLKEY  = 145
+F1KEY  =  146
+F2KEY  =  147
+F3KEY  =  148
+F4KEY  =  149
+F5KEY  =  150
+F6KEY  =  151
+F7KEY  =  152
+F8KEY  =  153
+F9KEY  =  154
+F10KEY =  155
+F11KEY =  156
+F12KEY =  157
+PRINTSCREENKEY = 158
+SCROLLLOCKKEY = 159
+PAUSEKEY = 160
+INSERTKEY = 161
+HOMEKEY  = 162
+PAGEUPKEY  = 163
+ENDKEY =  164
+PAGEDOWNKEY = 165
+NUMLOCKKEY = 166
+PADVIRGULEKEY  = 167
+PADASTERKEY  = 168
+PADPLUSKEY  = 169
+SGIRESERVED = 256 
+DIAL0 =  257	
+DIAL1 =  258	
+DIAL2 =  259	
+DIAL3 =  260	
+DIAL4 =  261	
+DIAL5 =  262	
+DIAL6 =  263	
+DIAL7 =  264	
+DIAL8 =  265	
+MOUSEX =  266	
+MOUSEY =  267	
+LPENX =  268	
+LPENY =  269	
+BPADX =  270	
+BPADY =  271	
+CURSORX =  272	
+CURSORY =  273	
+GHOSTX =  274	
+GHOSTY =  275	
+SBTX =  276	
+SBTY  =  277	
+SBTZ =  278	
+SBRX =   279	
+SBRY =  280	
+SBRZ  =  281	
+SBPERIOD = 282 
+TIMER0 =  515	
+TIMER1 =  516	
+TIMER2 =  517	
+TIMER3 =  518	
+KEYBD =  513	
+RAWKEYBD = 514 
+VALMARK =  523	
+GERROR =  524	
+REDRAW =  528	
+WMSEND =  529	
+WMREPLY =  530	
+WMGFCLOSE = 531 
+WMTXCLOSE = 532 
+MODECHANGE = 533 
+INPUTCHANGE = 534 
+QFULL =  535	
+PIECECHANGE = 536 
+WINCLOSE = 537 
+QREADERROR = 538 
+WINFREEZE = 539 
+WINTHAW =  540	
+REDRAWICONIC = 541 
+WINQUIT =  542	
+DEPTHCHANGE = 543 
+KEYBDFNAMES = 544 
+KEYBDFSTRINGS = 545 
+WINSHUT =  546	
+INPUT0 =  1024	
+INPUT1 =  1025
+INPUT2 =  1026
+INPUT3 =  1027
+INPUT4 =  1028
+INPUT5 =  1029
+INPUT6 =  1030
+INPUT7 =  1032
+OUTPUT0 =  1033	
+OUTPUT1 =  1034
+OUTPUT2 =  1035
+OUTPUT3 =  1036
+OUTPUT4 =  1037
+OUTPUT5 =  1038
+OUTPUT6 =  1039
+OUTPUT7 =  1040
+MAXSGIDEVICE = 20000
+MENUBUTTON = RIGHTMOUSE 
diff --git a/Lib/plat-irix5/GL.py b/Lib/plat-irix5/GL.py
new file mode 100755
index 0000000..35487a7
--- /dev/null
+++ b/Lib/plat-irix5/GL.py
@@ -0,0 +1,365 @@
+# Constants defined in <gl.h>
+
+#**************************************************************************
+#*									  *
+#* 		 Copyright (C) 1984, Silicon Graphics, Inc.		  *
+#*									  *
+#*  These coded instructions, statements, and computer programs  contain  *
+#*  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
+#*  are protected by Federal copyright law.  They  may  not be disclosed  *
+#*  to  third  parties  or copied or duplicated in any form, in whole or  *
+#*  in part, without the prior written consent of Silicon Graphics, Inc.  *
+#*									  *
+#**************************************************************************
+
+# Graphics Libary constants
+
+# Booleans
+TRUE = 1
+FALSE = 0
+
+# maximum X and Y screen coordinates 
+XMAXSCREEN = 1279
+YMAXSCREEN = 1023
+XMAXMEDIUM = 1023		# max for medium res monitor 
+YMAXMEDIUM = 767
+XMAX170 = 645		# max for RS-170 
+YMAX170 = 484
+XMAXPAL = 779		# max for PAL 
+YMAXPAL = 574
+
+# various hardware/software limits 
+ATTRIBSTACKDEPTH = 10
+VPSTACKDEPTH = 8
+MATRIXSTACKDEPTH = 32
+NAMESTACKDEPTH = 1025
+STARTTAG = -2
+ENDTAG = -3
+CPOSX_INVALID = -(2*XMAXSCREEN)
+
+# names for colors in color map loaded by greset 
+BLACK = 0
+RED = 1
+GREEN = 2
+YELLOW = 3
+BLUE = 4
+MAGENTA = 5
+CYAN = 6
+WHITE = 7
+
+# popup colors 
+PUP_CLEAR = 0
+PUP_COLOR = 1
+PUP_BLACK = 2
+PUP_WHITE = 3
+
+# defines for drawmode 
+NORMALDRAW = 0
+PUPDRAW = 1
+OVERDRAW = 2
+UNDERDRAW = 3
+CURSORDRAW = 4
+
+# defines for defpattern 
+PATTERN_16 = 16
+PATTERN_32 = 32
+PATTERN_64 = 64
+
+PATTERN_16_SIZE = 16
+PATTERN_32_SIZE = 64
+PATTERN_64_SIZE = 256
+
+# defines for readsource 
+SRC_AUTO = 0
+SRC_FRONT = 1
+SRC_BACK = 2
+SRC_ZBUFFER = 3
+SRC_PUP = 4
+SRC_OVER = 5
+SRC_UNDER = 6
+SRC_FRAMEGRABBER = 7
+
+# defines for blendfunction 
+BF_ZERO = 0
+BF_ONE = 1
+BF_DC = 2
+BF_SC = 2
+BF_MDC = 3
+BF_MSC = 3
+BF_SA = 4
+BF_MSA = 5
+BF_DA = 6
+BF_MDA = 7
+
+# defines for zfunction 
+ZF_NEVER = 0
+ZF_LESS = 1
+ZF_EQUAL = 2
+ZF_LEQUAL = 3
+ZF_GREATER = 4
+ZF_NOTEQUAL = 5
+ZF_GEQUAL = 6
+ZF_ALWAYS = 7
+
+# defines for zsource 
+ZSRC_DEPTH = 0
+ZSRC_COLOR = 1
+
+# defines for pntsmooth 
+SMP_OFF = 0
+SMP_ON = 1
+
+# defines for linesmooth 
+SML_OFF = 0
+SML_ON = 1
+
+# defines for setpup 
+PUP_NONE = 0
+PUP_GREY = 1
+
+# defines for glcompat 
+GLC_OLDPOLYGON = 0
+GLC_ZRANGEMAP = 1
+
+# defines for curstype 
+C16X1 = 0
+C16X2 = 1
+C32X1 = 2
+C32X2 = 3
+CCROSS = 4
+
+# defines for shademodel 
+FLAT = 0
+GOURAUD = 1
+
+# defines for logicop 
+### LO_ZERO = 0x0
+### LO_AND = 0x1
+### LO_ANDR = 0x2
+### LO_SRC = 0x3
+### LO_ANDI = 0x4
+### LO_DST = 0x5
+### LO_XOR = 0x6
+### LO_OR = 0x7
+### LO_NOR = 0x8
+### LO_XNOR = 0x9
+### LO_NDST = 0xa
+### LO_ORR = 0xb
+### LO_NSRC = 0xc
+### LO_ORI = 0xd
+### LO_NAND = 0xe
+### LO_ONE = 0xf
+
+
+#
+# START defines for getgdesc 
+#
+
+GD_XPMAX = 0
+GD_YPMAX = 1
+GD_XMMAX = 2
+GD_YMMAX = 3
+GD_ZMIN = 4
+GD_ZMAX = 5
+GD_BITS_NORM_SNG_RED = 6
+GD_BITS_NORM_SNG_GREEN = 7
+GD_BITS_NORM_SNG_BLUE = 8
+GD_BITS_NORM_DBL_RED = 9
+GD_BITS_NORM_DBL_GREEN = 10
+GD_BITS_NORM_DBL_BLUE = 11
+GD_BITS_NORM_SNG_CMODE = 12
+GD_BITS_NORM_DBL_CMODE = 13
+GD_BITS_NORM_SNG_MMAP = 14
+GD_BITS_NORM_DBL_MMAP = 15
+GD_BITS_NORM_ZBUFFER = 16
+GD_BITS_OVER_SNG_CMODE = 17
+GD_BITS_UNDR_SNG_CMODE = 18
+GD_BITS_PUP_SNG_CMODE = 19
+GD_BITS_NORM_SNG_ALPHA = 21 
+GD_BITS_NORM_DBL_ALPHA = 22
+GD_BITS_CURSOR = 23
+GD_OVERUNDER_SHARED = 24
+GD_BLEND = 25
+GD_CIFRACT = 26
+GD_CROSSHAIR_CINDEX = 27
+GD_DITHER = 28
+GD_LINESMOOTH_CMODE = 30
+GD_LINESMOOTH_RGB = 31
+GD_LOGICOP = 33
+GD_NSCRNS = 35
+GD_NURBS_ORDER = 36
+GD_NBLINKS = 37
+GD_NVERTEX_POLY = 39
+GD_PATSIZE_64 = 40
+GD_PNTSMOOTH_CMODE = 41
+GD_PNTSMOOTH_RGB = 42
+GD_PUP_TO_OVERUNDER = 43
+GD_READSOURCE = 44
+GD_READSOURCE_ZBUFFER = 48
+GD_STEREO = 50
+GD_SUBPIXEL_LINE = 51
+GD_SUBPIXEL_PNT = 52
+GD_SUBPIXEL_POLY = 53
+GD_TRIMCURVE_ORDER = 54
+GD_WSYS = 55
+GD_ZDRAW_GEOM = 57
+GD_ZDRAW_PIXELS = 58
+GD_SCRNTYPE = 61
+GD_TEXTPORT = 62
+GD_NMMAPS = 63
+GD_FRAMEGRABBER = 64
+GD_TIMERHZ = 66
+GD_DBBOX = 67
+GD_AFUNCTION = 68
+GD_ALPHA_OVERUNDER = 69
+GD_BITS_ACBUF = 70
+GD_BITS_ACBUF_HW = 71
+GD_BITS_STENCIL = 72
+GD_CLIPPLANES = 73
+GD_FOGVERTEX = 74
+GD_LIGHTING_TWOSIDE = 76
+GD_POLYMODE = 77
+GD_POLYSMOOTH = 78
+GD_SCRBOX = 79
+GD_TEXTURE = 80
+
+# return value for inquiries when there is no limit
+GD_NOLIMIT = 2
+
+# return values for GD_WSYS
+GD_WSYS_NONE = 0
+GD_WSYS_4S = 1
+
+# return values for GD_SCRNTYPE
+GD_SCRNTYPE_WM = 0
+GD_SCRNTYPE_NOWM = 1
+
+# 
+# END defines for getgdesc 
+#
+
+
+# 
+# START NURBS interface definitions 
+#
+
+# NURBS Rendering Properties 
+N_PIXEL_TOLERANCE = 1
+N_CULLING = 2
+N_DISPLAY = 3
+N_ERRORCHECKING = 4
+N_SUBDIVISIONS = 5
+N_S_STEPS = 6
+N_T_STEPS = 7
+N_TILES = 8
+
+N_SHADED = 1.0 	
+
+# ---------------------------------------------------------------------------
+# FLAGS FOR NURBS SURFACES AND CURVES 			
+# 
+# Bit: 9876 5432 1 0 
+#     |tttt|nnnn|f|r| :    r - 1 bit = 1 if rational coordinate exists
+# 	               :    f - 1 bit = 1 if rational coordinate is before rest 
+# 	               :              = 0 if rational coordinate is after rest 
+# 	 	       : nnnn - 4 bits for number of coordinates
+# 		       : tttt - 4 bits for type of data (color, position, etc.)
+# 
+# NURBS data type
+# N_T_ST	 	0	 parametric space data
+# N_T_XYZ		1	 model space data
+# 
+# rational or non-rational data and position in memory 
+# N_NONRATIONAL	0	 non-rational data
+# N_RATAFTER		1	 rational data with rat coord after rest
+# N_RATBEFORE		3	 rational data with rat coord before rest
+# 
+# N_MKFLAG(a,b,c) ((a<<6) | (b<<2) | c)
+# 	
+# ---------------------------------------------------------------------------
+# 
+N_ST = 0x8	# N_MKFLAG( N_T_ST, 2, N_NONRATIONAL ) 
+N_STW = 0xd	# N_MKFLAG( N_T_ST, 3, N_RATAFTER ) 
+N_WST = 0xf	# N_MKFLAG( N_T_ST, 3, N_RATBEFORE ) 
+N_XYZ = 0x4c	# N_MKFLAG( N_T_XYZ, 3, N_NONRATIONAL ) 
+N_XYZW = 0x51	# N_MKFLAG( N_T_XYZ, 4, N_RATAFTER ) 
+N_WXYZ = 0x53	# N_MKFLAG( N_T_XYZ, 4, N_RATBEFORE ) 
+
+# 
+# END NURBS interface definitions 
+# 
+
+
+# 
+# START lighting model defines 
+# 
+
+LMNULL = 0.0
+
+# MATRIX modes	
+MSINGLE = 0
+MPROJECTION = 1
+MVIEWING = 2
+
+# LIGHT constants 
+MAXLIGHTS = 8
+MAXRESTRICTIONS = 4
+
+# MATERIAL properties 
+DEFMATERIAL = 0
+EMISSION = 1
+AMBIENT = 2
+DIFFUSE = 3
+SPECULAR = 4
+SHININESS = 5
+COLORINDEXES = 6
+ALPHA = 7
+
+# LIGHT properties 
+DEFLIGHT = 100
+LCOLOR = 101
+POSITION = 102
+
+# LIGHTINGMODEL properties 
+DEFLMODEL = 200
+LOCALVIEWER = 201
+ATTENUATION = 202
+
+# TARGET constants 
+MATERIAL = 1000
+LIGHT0 = 1100
+LIGHT1 = 1101
+LIGHT2 = 1102
+LIGHT3 = 1103
+LIGHT4 = 1104
+LIGHT5 = 1105
+LIGHT6 = 1106
+LIGHT7 = 1107
+LMODEL = 1200
+
+# lmcolor modes 
+LMC_COLOR = 0
+LMC_EMISSION = 1
+LMC_AMBIENT = 2
+LMC_DIFFUSE = 3
+LMC_SPECULAR = 4
+LMC_AD = 5
+LMC_NULL = 6
+
+# 
+# END lighting model defines 
+# 
+
+
+# 
+# START distributed graphics library defines 
+# 
+
+DGLSINK = 0	# sink connection	
+DGLLOCAL = 1	# local connection	
+DGLTSOCKET = 2	# tcp socket connection
+DGL4DDN = 3	# 4DDN (DECnet)	
+
+# 
+# END distributed graphics library defines 
+# 
diff --git a/Lib/plat-irix5/panel.py b/Lib/plat-irix5/panel.py
new file mode 100755
index 0000000..eb11508
--- /dev/null
+++ b/Lib/plat-irix5/panel.py
@@ -0,0 +1,281 @@
+# Module 'panel'
+#
+# Support for the Panel library.
+# Uses built-in module 'pnl'.
+# Applciations should use 'panel.function' instead of 'pnl.function';
+# most 'pnl' functions are transparently exported by 'panel',
+# but dopanel() is overridden and you have to use this version
+# if you want to use callbacks.
+
+
+import pnl
+
+
+debug = 0
+
+
+# Test if an object is a list.
+#
+def is_list(x):
+	return type(x) = type([])
+
+
+# Reverse a list.
+#
+def reverse(list):
+	res = []
+	for item in list:
+		res.insert(0, item)
+	return res
+
+
+# Get an attribute of a list, which may itself be another list.
+# Don't use 'prop' for name.
+#
+def getattrlist(list, name):
+	for item in list:
+		if item and is_list(item) and item[0] = name:
+			return item[1:]
+	return []
+
+
+# Get a property of a list, which may itself be another list.
+#
+def getproplist(list, name):
+	for item in list:
+		if item and is_list(item) and item[0] = 'prop':
+			if len(item) > 1 and item[1] = name:
+				return item[2:]
+	return []
+
+
+# Test if an actuator description contains the property 'end-of-group'
+#
+def is_endgroup(list):
+	x = getproplist(list, 'end-of-group')
+	return (x and x[0] = '#t')
+
+
+# Neatly display an actuator definition given as S-expression
+# the prefix string is printed before each line.
+#
+def show_actuator(prefix, a):
+	for item in a:
+		if not is_list(item):
+			print prefix, item
+		elif item and item[0] = 'al':
+			print prefix, 'Subactuator list:'
+			for a in item[1:]:
+				show_actuator(prefix + '    ', a)
+		elif len(item) = 2:
+			print prefix, item[0], '=>', item[1]
+		elif len(item) = 3 and item[0] = 'prop':
+			print prefix, 'Prop', item[1], '=>',
+			print item[2]
+		else:
+			print prefix, '?', item
+
+
+# Neatly display a panel.
+#
+def show_panel(prefix, p):
+	for item in p:
+		if not is_list(item):
+			print prefix, item
+		elif item and item[0] = 'al':
+			print prefix, 'Actuator list:'
+			for a in item[1:]:
+				show_actuator(prefix + '    ', a)
+		elif len(item) = 2:
+			print prefix, item[0], '=>', item[1]
+		elif len(item) = 3 and item[0] = 'prop':
+			print prefix, 'Prop', item[1], '=>',
+			print item[2]
+		else:
+			print prefix, '?', item
+
+
+# Exception raised by build_actuator or build_panel.
+#
+panel_error = 'panel error'
+
+
+# Dummy callback used to initialize the callbacks.
+#
+def dummy_callback(arg):
+	pass
+
+
+# Assign attributes to members of the target.
+# Attribute names in exclist are ignored.
+# The member name is the attribute name prefixed with the prefix.
+#
+def assign_members(target, attrlist, exclist, prefix):
+	for item in attrlist:
+		if is_list(item) and len(item) = 2 and item[0] not in exclist:
+			name, value = item[0], item[1]
+			ok = 1
+			if value[0] in '-0123456789':
+				value = eval(value)
+			elif value[0] = '"':
+				value = value[1:-1]
+			elif value = 'move-then-resize':
+				# Strange default set by Panel Editor...
+				ok = 0
+			else:
+				print 'unknown value', value, 'for', name
+				ok = 0
+			if ok:
+				lhs = 'target.' + prefix + name
+				stmt = lhs + '=' + `value`
+				if debug: print 'exec', stmt
+				try:
+					exec(stmt + '\n')
+				except KeyboardInterrupt: # Don't catch this!
+					raise KeyboardInterrupt
+				except:
+					print 'assign failed:', stmt
+
+
+# Build a real actuator from an actuator descriptior.
+# Return a pair (actuator, name).
+#
+def build_actuator(descr):
+	namelist = getattrlist(descr, 'name')
+	if namelist:
+		# Assume it is a string
+		actuatorname = namelist[0][1:-1]
+	else:
+		actuatorname = ''
+	type = descr[0]
+	if type[:4] = 'pnl_': type = type[4:]
+	act = pnl.mkact(type)
+	act.downfunc = act.activefunc = act.upfunc = dummy_callback
+	#
+	assign_members(act, descr[1:], ('al', 'data', 'name'), '')
+	#
+	# Treat actuator-specific data
+	#
+	datalist = getattrlist(descr, 'data')
+	prefix = ''
+	if type[-4:] = 'puck':
+		prefix = 'puck_'
+	elif type = 'mouse':
+		prefix = 'mouse_'
+	assign_members(act, datalist, (), prefix)
+	#
+	return act, actuatorname
+
+
+# Build all sub-actuators and add them to the super-actuator.
+# The super-actuator must already have been added to the panel.
+# Sub-actuators with defined names are added as members to the panel
+# so they can be referenced as p.name.
+#
+# Note: I have no idea how panel.endgroup() works when applied
+# to a sub-actuator.
+#
+def build_subactuators(panel, super_act, al):
+	#
+	# This is nearly the same loop as below in build_panel(),
+	# except a call is made to addsubact() instead of addact().
+	#
+	for a in al:
+		act, name = build_actuator(a)
+		act.addsubact(super_act)
+		if name:
+			stmt = 'panel.' + name + ' = act'
+			if debug: print 'exec', stmt
+			exec(stmt + '\n')
+		if is_endgroup(a):
+			panel.endgroup()
+		sub_al = getattrlist(a, 'al')
+		if sub_al:
+			build_subactuators(panel, act, sub_al)
+	#
+	# Fix the actuator to which whe just added subactuators.
+	# This can't hurt (I hope) and is needed for the scroll actuator.
+	#
+	super_act.fixact()
+
+
+# Build a real panel from a panel definition.
+# Return a panel object p, where for each named actuator a, p.name is a
+# reference to a.
+#
+def build_panel(descr):
+	#
+	# Sanity check
+	#
+	if (not descr) or descr[0] <> 'panel':
+		raise panel_error, 'panel description must start with "panel"'
+	#
+	if debug: show_panel('', descr)
+	#
+	# Create an empty panel
+	#
+	panel = pnl.mkpanel()
+	#
+	# Assign panel attributes
+	#
+	assign_members(panel, descr[1:], ('al'), '')
+	#
+	# Look for actuator list
+	#
+	al = getattrlist(descr, 'al')
+	#
+	# The order in which actuators are created is important
+	# because of the endgroup() operator.
+	# Unfortunately the Panel Editor outputs the actuator list
+	# in reverse order, so we reverse it here.
+	#
+	al = reverse(al)
+	#
+	for a in al:
+		act, name = build_actuator(a)
+		act.addact(panel)
+		if name:
+			stmt = 'panel.' + name + ' = act'
+			exec(stmt + '\n')
+		if is_endgroup(a):
+			panel.endgroup()
+		sub_al = getattrlist(a, 'al')
+		if sub_al:
+			build_subactuators(panel, act, sub_al)
+	#
+	return panel
+
+
+# Wrapper around pnl.dopanel() which calls call-back functions.
+#
+def my_dopanel():
+	# Extract only the first 4 elements to allow for future expansion
+	a, down, active, up = pnl.dopanel()[:4]
+	if down:
+		down.downfunc(down)
+	if active:
+		active.activefunc(active)
+	if up:
+		up.upfunc(up)
+	return a
+
+
+# Create one or more panels from a description file (S-expressions)
+# generated by the Panel Editor.
+# 
+def defpanellist(file):
+	import parser
+	descrlist = parser.parse_file(open(file, 'r'))
+	panellist = []
+	for descr in descrlist:
+		panellist.append(build_panel(descr))
+	return panellist
+
+
+# Import everything from built-in method pnl, so the user can always
+# use panel.foo() instead of pnl.foo().
+# This gives *no* performance penalty once this module is imported.
+#
+from pnl import *			# for export
+
+dopanel = my_dopanel			# override pnl.dopanel
diff --git a/Lib/plat-irix5/panelparser.py b/Lib/plat-irix5/panelparser.py
new file mode 100755
index 0000000..9c9ee02
--- /dev/null
+++ b/Lib/plat-irix5/panelparser.py
@@ -0,0 +1,128 @@
+# Module 'parser'
+#
+# Parse S-expressions output by the Panel Editor
+# (which is written in Scheme so it can't help writing S-expressions).
+#
+# See notes at end of file.
+
+
+whitespace = ' \t\n'
+operators = '()\''
+separators = operators + whitespace + ';' + '"'
+
+
+# Tokenize a string.
+# Return a list of tokens (strings).
+#
+def tokenize_string(s):
+	tokens = []
+	while s:
+		c = s[:1]
+		if c in whitespace:
+			s = s[1:]
+		elif c = ';':
+			s = ''
+		elif c = '"':
+			n = len(s)
+			i = 1
+			while i < n:
+				c = s[i]
+				i = i+1
+				if c = '"': break
+				if c = '\\': i = i+1
+			tokens.append(s[:i])
+			s = s[i:]
+		elif c in operators:
+			tokens.append(c)
+			s = s[1:]
+		else:
+			n = len(s)
+			i = 1
+			while i < n:
+				if s[i] in separators: break
+				i = i+1
+			tokens.append(s[:i])
+			s = s[i:]
+	return tokens
+
+
+# Tokenize a whole file (given as file object, not as file name).
+# Return a list of tokens (strings).
+#
+def tokenize_file(fp):
+	tokens = []
+	while 1:
+		line = fp.readline()
+		if not line: break
+		tokens = tokens + tokenize_string(line)
+	return tokens
+
+
+# Exception raised by parse_exr.
+#
+syntax_error = 'syntax error'
+
+
+# Parse an S-expression.
+# Input is a list of tokens as returned by tokenize_*().
+# Return a pair (expr, tokens)
+# where expr is a list representing the s-expression,
+# and tokens contains the remaining tokens.
+# May raise syntax_error.
+#
+def parse_expr(tokens):
+	if (not tokens) or tokens[0] <> '(':
+		raise syntax_error, 'expected "("'
+	tokens = tokens[1:]
+	expr = []
+	while 1:
+		if not tokens:
+			raise syntax_error, 'missing ")"'
+		if tokens[0] = ')':
+			return expr, tokens[1:]
+		elif tokens[0] = '(':
+			subexpr, tokens = parse_expr(tokens)
+			expr.append(subexpr)
+		else:
+			expr.append(tokens[0])
+			tokens = tokens[1:]
+
+
+# Parse a file (given as file object, not as file name).
+# Return a list of parsed S-expressions found at the top level.
+#
+def parse_file(fp):
+	tokens = tokenize_file(fp)
+	exprlist = []
+	while tokens:
+		expr, tokens = parse_expr(tokens)
+		exprlist.append(expr)
+	return exprlist
+
+
+# EXAMPLE:
+#
+# The input
+#	'(hip (hop hur-ray))'
+#
+# passed to tokenize_string() returns the token list
+#	['(', 'hip', '(', 'hop', 'hur-ray', ')', ')']
+#
+# When this is passed to parse_expr() it returns the expression
+#	['hip', ['hop', 'hur-ray']]
+# plus an empty token list (because there are no tokens left.
+#
+# When a file containing the example is passed to parse_file() it returns
+# a list whose only element is the output of parse_expr() above:
+#	[['hip', ['hop', 'hur-ray']]]
+
+
+# TOKENIZING:
+#
+# Comments start with semicolon (;) and continue till the end of the line.
+#
+# Tokens are separated by whitespace, except the following characters
+# always form a separate token (outside strings):
+#	( ) '
+# Strings are enclosed in double quotes (") and backslash (\) is used
+# as escape character in strings.
diff --git a/Lib/poly.py b/Lib/poly.py
new file mode 100644
index 0000000..abac4c8
--- /dev/null
+++ b/Lib/poly.py
@@ -0,0 +1,55 @@
+# module 'poly' -- Polynomials
+
+# A polynomial is represented by a list of coefficients, e.g.,
+# [1, 10, 5] represents 1*x**0 + 10*x**1 + 5*x**2 (or 1 + 10x + 5x**2).
+# There is no way to suppress internal zeros; trailing zeros are
+# taken out by normalize().
+
+def normalize(p): # Strip unnecessary zero coefficients
+	n = len(p)
+	while p:
+		if p[n-1]: return p[:n]
+		n = n-1
+	return []
+
+def plus(a, b):
+	if len(a) < len(b): a, b = b, a # make sure a is the longest
+	res = a[:] # make a copy
+	for i in range(len(b)):
+		res[i] = res[i] + b[i]
+	return normalize(res)
+
+def minus(a, b):
+	if len(a) < len(b): a, b = b, a # make sure a is the longest
+	res = a[:] # make a copy
+	for i in range(len(b)):
+		res[i] = res[i] - b[i]
+	return normalize(res)
+
+def one(power, coeff): # Representation of coeff * x**power
+	res = []
+	for i in range(power): res.append(0)
+	return res + [coeff]
+
+def times(a, b):
+	res = []
+	for i in range(len(a)):
+		for j in range(len(b)):
+			res = plus(res, one(i+j, a[i]*b[j]))
+	return res
+
+def power(a, n): # Raise polynomial a to the positive integral power n
+	if n = 0: return [1]
+	if n = 1: return a
+	if n/2*2 = n:
+		b = power(a, n/2)
+		return times(b, b)
+	return times(power(a, n-1), a)
+
+def der(a): # First derivative
+	res = a[1:]
+	for i in range(len(res)):
+		res[i] = res[i] * (i+1)
+	return res
+
+# Computing a primitive function would require rational arithmetic...
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
new file mode 100644
index 0000000..e314cb3
--- /dev/null
+++ b/Lib/posixpath.py
@@ -0,0 +1,124 @@
+# Module 'path' -- common operations on POSIX pathnames
+
+import posix
+
+
+# Intelligent pathname concatenation.
+# Inserts a '/' unless the first part is empty or already ends in '/'.
+# Ignores the first part altogether if the second part is absolute
+# (begins with '/').
+#
+def cat(a, b):
+	if b[:1] = '/': return b
+	if a = '' or a[-1:] = '/': return a + b
+	return a + '/' + b
+
+
+# Split a path in head (empty or ending in '/') and tail (no '/').
+# The tail will be empty if the path ends in '/'.
+#
+def split(p):
+	head, tail = '', ''
+	for c in p:
+		tail = tail + c
+		if c = '/':
+			head, tail = head + tail, ''
+	return head, tail
+
+
+# Return the tail (basename) part of a path.
+#
+def basename(p):
+	return split(p)[1]
+
+
+# Return the longest prefix of all list elements.
+#
+def commonprefix(m):
+	if not m: return ''
+	prefix = m[0]
+	for item in m:
+		for i in range(len(prefix)):
+			if prefix[:i+1] <> item[:i+1]:
+				prefix = prefix[:i]
+				if i = 0: return ''
+				break
+	return prefix
+
+
+# Does a file/directory exist?
+#
+def exists(path):
+	try:
+		st = posix.stat(path)
+	except posix.error:
+		return 0
+	return 1
+
+
+# Is a path a posix directory?
+#
+def isdir(path):
+	try:
+		st = posix.stat(path)
+	except posix.error:
+		return 0
+	return st[0] / 4096 = 4 # S_IFDIR
+
+
+# Is a path a symbolic link?
+# This will always return false on systems where posix.lstat doesn't exist.
+#
+def islink(path):
+	try:
+		st = posix.lstat(path)
+	except (posix.error, NameError):
+		return 0
+	return st[0] / 4096 = 10 # S_IFLNK
+
+
+_mounts = []
+
+def _getmounts():
+	import commands, string
+	mounts = []
+	data = commands.getoutput('/etc/mount')
+	lines = string.splitfields(data, '\n')
+	for line in lines:
+		words = string.split(line)
+		if len(words) >= 3 and words[1] = 'on':
+			mounts.append(words[2])
+	return mounts
+
+
+# Is a path a mount point?
+# This only works for normalized, absolute paths,
+# and only if the mount table as printed by /etc/mount is correct.
+# Sorry.
+#
+def ismount(path):
+	if not _mounts:
+		_mounts[:] = _getmounts()
+	return path in _mounts
+
+
+# Directory tree walk.
+# For each directory under top (including top itself),
+# func(arg, dirname, filenames) is called, where dirname
+# is the name of the directory and filenames is the list of
+# files (and subdirectories etc.) in the directory.
+# func may modify the filenames list, to implement a filter,
+# or to impose a different order of visiting.
+#
+def walk(top, func, arg):
+	try:
+		names = posix.listdir(top)
+	except posix.error:
+		return
+	func(arg, top, names)
+	exceptions = ('.', '..')
+	for name in names:
+		if name not in exceptions:
+			name = cat(top, name)
+			if isdir(name):
+				walk(name, func, arg)
diff --git a/Lib/rand.py b/Lib/rand.py
new file mode 100644
index 0000000..0616483
--- /dev/null
+++ b/Lib/rand.py
@@ -0,0 +1,12 @@
+# Module 'rand'
+
+import whrandom
+
+def srand(seed):
+	whrandom.seed(seed%256, seed/256%256, seed/65536%256)
+
+def rand():
+	return int(whrandom.random() * 32768.0) % 32768
+
+def choice(seq):
+	return seq[rand() % len(seq)]
diff --git a/Lib/shutil.py b/Lib/shutil.py
new file mode 100644
index 0000000..cf63396
--- /dev/null
+++ b/Lib/shutil.py
@@ -0,0 +1,70 @@
+# Module 'shutil' -- utility functions usable in a shell-like program
+
+import posix
+import path
+
+MODEBITS = 010000	# Lower 12 mode bits
+# Change this to 01000 (9 mode bits) to avoid copying setuid etc.
+
+# Copy data from src to dst
+#
+def copyfile(src, dst):
+	fsrc = open(src, 'r')
+	fdst = open(dst, 'w')
+	while 1:
+		buf = fsrc.read(16*1024)
+		if not buf: break
+		fdst.write(buf)
+
+# Copy mode bits from src to dst
+#
+def copymode(src, dst):
+	st = posix.stat(src)
+	mode = divmod(st[0], MODEBITS)[1]
+	posix.chmod(dst, mode)
+
+# Copy all stat info (mode bits, atime and mtime) from src to dst
+#
+def copystat(src, dst):
+	st = posix.stat(src)
+	mode = divmod(st[0], MODEBITS)[1]
+	posix.chmod(dst, mode)
+	posix.utimes(dst, st[7:9])
+
+# Copy data and mode bits ("cp src dst")
+#
+def copy(src, dst):
+	copyfile(src, dst)
+	copymode(src, dst)
+
+# Copy data and all stat info ("cp -p src dst")
+#
+def copy2(src, dst):
+	copyfile(src, dst)
+	copystat(src, dst)
+
+# Recursively copy a directory tree.
+# The destination must not already exist.
+#
+def copytree(src, dst):
+	names = posix.listdir(src)
+	posix.mkdir(dst, 0777)
+	dot_dotdot = '.', '..'
+	for name in names:
+		if name not in dot_dotdot:
+			srcname = path.cat(src, name)
+			dstname = path.cat(dst, name)
+			#print 'Copying', srcname, 'to', dstname
+			try:
+				#if path.islink(srcname):
+				#	linkto = posix.readlink(srcname)
+				#	posix.symlink(linkto, dstname)
+				#elif path.isdir(srcname):
+				if path.isdir(srcname):
+					copytree(srcname, dstname)
+				else:
+					copy2(srcname, dstname)
+				# XXX What about devices, sockets etc.?
+			except posix.error, why:
+				print 'Could not copy', srcname, 'to', dstname,
+				print '(', why[1], ')'
diff --git a/Lib/statcache.py b/Lib/statcache.py
new file mode 100644
index 0000000..eeb0ca4
--- /dev/null
+++ b/Lib/statcache.py
@@ -0,0 +1,90 @@
+# Module 'statcache'
+#
+# Maintain a cache of file stats.
+# There are functions to reset the cache or to selectively remove items.
+
+import posix
+
+
+# The cache.
+# Keys are pathnames, values are `posix.stat' outcomes.
+#
+cache = {}
+
+
+# Stat a file, possibly out of the cache.
+#
+def stat(path):
+	try:
+		return cache[path]
+	except RuntimeError:
+		pass
+	cache[path] = ret = posix.stat(path)
+	return ret
+
+
+# Reset the cache completely.
+# Hack: to reset a global variable, we import this module.
+#
+def reset():
+	import statcache
+	# Check that we really imported the same module
+	if cache is not statcache.cache:
+		raise 'sorry, statcache identity crisis'
+	statcache.cache = {}
+
+
+# Remove a given item from the cache, if it exists.
+#
+def forget(path):
+	try:
+		del cache[path]
+	except RuntimeError:
+		pass
+
+
+# Remove all pathnames with a given prefix.
+#
+def forget_prefix(prefix):
+	n = len(prefix)
+	for path in cache.keys():
+		if path[:n] = prefix:
+			del cache[path]
+
+
+# Forget about a directory and all entries in it, but not about
+# entries in subdirectories.
+#
+def forget_dir(prefix):
+	if prefix[-1:] = '/' and prefix <> '/':
+		prefix = prefix[:-1]
+	forget(prefix)
+	if prefix[-1:] <> '/':
+		prefix = prefix + '/'
+	n = len(prefix)
+	for path in cache.keys():
+		if path[:n] = prefix:
+			rest = path[n:]
+			if rest[-1:] = '/': rest = rest[:-1]
+			if '/' not in rest:
+				del cache[path]
+
+
+# Remove all pathnames except with a given prefix.
+# Normally used with prefix = '/' after a chdir().
+#
+def forget_except_prefix(prefix):
+	n = len(prefix)
+	for path in cache.keys():
+		if path[:n] <> prefix:
+			del cache[path]
+
+
+# Check for directory.
+#
+def isdir(path):
+	try:
+		# mode is st[0]; type is mode/4096; S_IFDIR is 4
+		return stat(path)[0] / 4096 = 4
+	except RuntimeError:
+		return 0
diff --git a/Lib/stdwin/anywin.py b/Lib/stdwin/anywin.py
new file mode 100755
index 0000000..bb7e865
--- /dev/null
+++ b/Lib/stdwin/anywin.py
@@ -0,0 +1,14 @@
+# Module 'anywin'
+# Open a file or directory in a window
+
+import dirwin
+import filewin
+import path
+
+def open(name):
+	print 'opening', name, '...'
+	if path.isdir(name):
+		w = dirwin.open(name)
+	else:
+		w = filewin.open(name)
+	return w
diff --git a/Lib/stdwin/dirwin.py b/Lib/stdwin/dirwin.py
new file mode 100755
index 0000000..5df85e7
--- /dev/null
+++ b/Lib/stdwin/dirwin.py
@@ -0,0 +1,28 @@
+# Module 'dirwin'
+
+# Directory windows, a subclass of listwin
+
+import gwin
+import listwin
+import anywin
+import path
+import dircache
+
+def action(w, string, i, detail):
+	(h, v), clicks, button, mask = detail
+	if clicks = 2:
+		name = path.cat(w.name, string)
+		try:
+			w = anywin.open(name)
+		except posix.error, why:
+			stdwin.message('Can\'t open ' + name + ': ' + why[1])
+
+def open(name):
+	name = path.cat(name, '')
+	list = dircache.opendir(name)[:]
+	list.sort()
+	dircache.annotate(name, list)
+	w = listwin.open(name, list)
+	w.name = name
+	w.action = action
+	return w
diff --git a/Lib/stdwin/filewin.py b/Lib/stdwin/filewin.py
new file mode 100755
index 0000000..1beb0b6
--- /dev/null
+++ b/Lib/stdwin/filewin.py
@@ -0,0 +1,31 @@
+# Module 'filewin'
+# File windows, a subclass of textwin (which is a subclass of gwin)
+
+import stdwin
+import textwin
+import path
+
+builtin_open = open
+
+def readfile(fn): # Return a string containing the file's contents
+	fp = builtin_open(fn, 'r')
+	a = ''
+	n = 8096
+	while 1:
+		b = fp.read(n)
+		if not b: break
+		a = a + b
+	return a
+
+
+# FILE WINDOW
+
+def open_readonly(fn): # Open a file window
+	w = textwin.open_readonly(fn, readfile(fn))
+	w.fn = fn
+	return w
+
+def open(fn): # Open a file window
+	w = textwin.open(fn, readfile(fn))
+	w.fn = fn
+	return w
diff --git a/Lib/stdwin/gwin.py b/Lib/stdwin/gwin.py
new file mode 100755
index 0000000..15aa432
--- /dev/null
+++ b/Lib/stdwin/gwin.py
@@ -0,0 +1,118 @@
+# Module 'gwin'
+# Generic stdwin windows
+
+# This is used as a base class from which to derive other window types.
+# The mainloop() function here is an event dispatcher for all window types.
+
+import stdwin
+import stdwinsupport
+
+S = stdwinsupport			# Shorthand
+
+windows = []				# List of open windows
+
+
+# Open a window
+
+def open(title):			# Open a generic window
+	w = stdwin.open(title)
+	stdwin.setdefwinsize(0, 0)
+	# Set default event handlers
+	w.draw = nop
+	w.char = nop
+	w.mdown = nop
+	w.mmove = nop
+	w.mup = nop
+	w.m2down = m2down
+	w.m2up = m2up
+	w.size = nop
+	w.move = nop
+	w.activate = w.deactivate = nop
+	w.timer = nop
+	# default command handlers
+	w.close = close
+	w.tab = tab
+	w.enter = enter
+	w.backspace = backspace
+	w.arrow = arrow
+	w.kleft = w.kup = w.kright = w.kdown = nop
+	windows.append(w)
+	return w
+
+
+# Generic event dispatching
+
+def mainloop():				# Handle events until no windows left
+	while windows:
+		treatevent(stdwin.getevent())
+
+def treatevent(e):			# Handle a stdwin event
+	type, w, detail = e
+	if type = S.we_draw:
+		w.draw(w, detail)
+	elif type = S.we_menu:
+		m, item = detail
+		m.action[item](w, m, item)
+	elif type = S.we_command:
+		treatcommand(w, detail)
+	elif type = S.we_char:
+		w.char(w, detail)
+	elif type = S.we_mouse_down:
+		if detail[1] > 1: w.m2down(w, detail)
+		else: w.mdown(w, detail)
+	elif type = S.we_mouse_move:
+		w.mmove(w, detail)
+	elif type = S.we_mouse_up:
+		if detail[1] > 1: w.m2up(w, detail)
+		else: w.mup(w, detail)
+	elif type = S.we_size:
+		w.size(w, w.getwinsize())
+	elif type = S.we_activate:
+		w.activate(w)
+	elif type = S.we_deactivate:
+		w.deactivate(w)
+	elif type = S.we_move:
+		w.move(w)
+	elif type = S.we_timer:
+		w.timer(w)
+
+def treatcommand(w, type):		# Handle a we_command event
+	if type = S.wc_close:
+		w.close(w)
+	elif type = S.wc_return:
+		w.enter(w)
+	elif type = S.wc_tab:
+		w.tab(w)
+	elif type = S.wc_backspace:
+		w.backspace(w)
+	elif type in (S.wc_left, S.wc_up, S.wc_right, S.wc_down):
+		w.arrow(w, type)
+
+
+# Methods
+
+def close(w):				# Close method
+	for i in range(len(windows)):
+		if windows[i] is w:
+			del windows[i]
+			break
+
+def arrow(w, detail):			# Arrow key method
+	if detail = S.wc_left:
+		w.kleft(w)
+	elif detail = S.wc_up:
+		w.kup(w)
+	elif detail = S.wc_right:
+		w.kright(w)
+	elif detail = S.wc_down:
+		w.kdown(w)
+
+
+# Trivial methods
+
+def tab(w): w.char(w, '\t')
+def enter(w): w.char(w, '\n')		# 'return' is a Python reserved word
+def backspace(w): w.char(w, '\b')
+def m2down(w, detail): w.mdown(w, detail)
+def m2up(w, detail): w.mup(w, detail)
+def nop(args): pass
diff --git a/Lib/stdwin/listwin.py b/Lib/stdwin/listwin.py
new file mode 100755
index 0000000..9480a81
--- /dev/null
+++ b/Lib/stdwin/listwin.py
@@ -0,0 +1,47 @@
+# Module 'listwin'
+# List windows, a subclass of gwin
+
+import gwin
+import stdwin
+
+def maxlinewidth(a): # Compute maximum textwidth of lines in a sequence
+	max = 0
+	for line in a:
+		width = stdwin.textwidth(line)
+		if width > max: max = width
+	return max
+
+def action(w, string, i, detail): # Default item selection method
+	pass
+
+def mup(w, detail): # Mouse up method
+	(h, v), clicks, button, mask = detail
+	i = divmod(v, w.lineheight)[0]
+	if 0 <= i < len(w.data):
+		w.action(w, w.data[i], i, detail)
+
+def draw(w, ((left, top), (right, bottom))): # Text window draw method
+	data = w.data
+	d = w.begindrawing()
+	lh = w.lineheight
+	itop = top/lh
+	ibot = (bottom-1)/lh + 1
+	if itop < 0: itop = 0
+	if ibot > len(data): ibot = len(data)
+	for i in range(itop, ibot): d.text((0, i*lh), data[i])
+
+def open(title, data): # Display a list of texts in a window
+	lineheight = stdwin.lineheight()
+	h, v = maxlinewidth(data), len(data)*lineheight
+	h0, v0 = h + stdwin.textwidth(' '), v + lineheight
+	if h0 > stdwin.textwidth(' ')*80: h0 = 0
+	if v0 > stdwin.lineheight()*24: v0 = 0
+	stdwin.setdefwinsize(h0, v0)
+	w = gwin.open(title)
+	w.setdocsize(h, v)
+	w.lineheight = lineheight
+	w.data = data
+	w.draw = draw
+	w.action = action
+	w.mup = mup
+	return w
diff --git a/Lib/stdwin/rect.py b/Lib/stdwin/rect.py
new file mode 100755
index 0000000..c044b9f
--- /dev/null
+++ b/Lib/stdwin/rect.py
@@ -0,0 +1,87 @@
+# Module 'rect'.
+#
+# Operations on rectangles.
+# There is some normalization: all results return the object 'empty'
+# if their result would contain no points.
+
+
+# Exception.
+#
+error = 'rect.error'
+
+
+# The empty rectangle.
+#
+empty = (0, 0), (0, 0)
+
+
+# Check if a rectangle is empty.
+#
+def is_empty((left, top), (right, bottom)):
+	return left >= right or top >= bottom
+
+
+# Compute the intersection or two or more rectangles.
+# This works with a list or tuple argument.
+#
+def intersect(list):
+	if not list: raise error, 'intersect called with empty list'
+	if is_empty(list[0]): return empty
+	(left, top), (right, bottom) = list[0]
+	for rect in list[1:]:
+		if not is_empty(rect):
+			(l, t), (r, b) = rect
+			if left < l: left = l
+			if top < t: top = t
+			if right > r: right = r
+			if bottom > b: bottom = b
+			if is_empty((left, top), (right, bottom)):
+				return empty
+	return (left, top), (right, bottom)
+
+
+# Compute the smallest rectangle containing all given rectangles.
+# This works with a list or tuple argument.
+#
+def union(list):
+	(left, top), (right, bottom) = empty
+	for (l, t), (r, b) in list[1:]:
+		if not is_empty((l, t), (r, b)):
+			if l < left: left = l
+			if t < top: top = t
+			if r > right: right = r
+			if b > bottom: bottom = b
+	res = (left, top), (right, bottom)
+	if is_empty(res):
+		return empty
+	return res
+
+
+# Check if a point is in a rectangle.
+#
+def pointinrect((h, v), ((left, top), (right, bottom))):
+	return left <= h < right and top <= v < bottom
+
+
+# Return a rectangle that is dh, dv inside another
+#
+def inset(((left, top), (right, bottom)), (dh, dv)):
+	left = left + dh
+	top = top + dv
+	right = right - dh
+	bottom = bottom - dv
+	r = (left, top), (right, bottom)
+	if is_empty(r):
+		return empty
+	else:
+		return r
+
+
+# Conversions between rectangles and 'geometry tuples',
+# given as origin (h, v) and dimensions (width, height).
+#
+def rect2geom((left, top), (right, bottom)):
+	return (left, top), (right-left, bottom-top)
+
+def geom2rect((h, v), (width, height)):
+	return (h, v), (h+width, v+height)
diff --git a/Lib/stdwin/stdwinevents.py b/Lib/stdwin/stdwinevents.py
new file mode 100755
index 0000000..889dd95
--- /dev/null
+++ b/Lib/stdwin/stdwinevents.py
@@ -0,0 +1,36 @@
+# Module 'stdwinevents' -- Constants for stdwin event types
+#
+# Suggested usage:
+#	from stdwinevents import *
+
+# The function stdwin.getevent() returns a tuple containing:
+#	(type, window, detail)
+# where detail may be <no value> or a value depending on type, see below:
+
+# Values for type:
+
+WE_NULL       =  0	# not reported -- means 'no event' internally
+WE_ACTIVATE   =  1	# detail is <no object>
+WE_CHAR       =  2	# detail is the character
+WE_COMMAND    =  3	# detail is one of the WC_* constants below
+WE_MOUSE_DOWN =  4	# detail is ((h, v), clicks, button, mask)
+WE_MOUSE_MOVE =  5	# ditto
+WE_MOUSE_UP   =  6	# ditto
+WE_MENU       =  7	# detail is (menu, item)
+WE_SIZE       =  8	# detail is (width, height) [???]
+WE_MOVE       =  9	# not reported -- reserved for future use
+WE_DRAW       = 10	# detail is ((left, top), (right, bottom))
+WE_TIMER      = 11	# detail is <no object>
+WE_DEACTIVATE = 12	# detail is <no object>
+
+# Values for detail when type is WE_COMMAND:
+
+WC_CLOSE      =  1	# user hit close box
+WC_LEFT       =  2	# left arrow key
+WC_RIGHT      =  3	# right arrow key
+WC_UP         =  4	# up arrow key
+WC_DOWN       =  5	# down arrow key
+WC_CANCEL     =  6	# not reported -- turned into KeyboardInterrupt
+WC_BACKSPACE  =  7	# backspace key
+WC_TAB        =  8	# tab key
+WC_RETURN     =  9	# return or enter key
diff --git a/Lib/stdwin/tablewin.py b/Lib/stdwin/tablewin.py
new file mode 100755
index 0000000..05a954e
--- /dev/null
+++ b/Lib/stdwin/tablewin.py
@@ -0,0 +1,237 @@
+# Module 'tablewin'
+
+# Display a table, with per-item actions:
+
+#	   A1   |   A2   |   A3   |  ....  |   AN
+#	   B1   |   B2   |   B3   |  ....  |   BN
+#	   C1   |   C2   |   C3   |  ....  |   CN
+#	   ..   |   ..   |   ..   |  ....  |   ..
+#	   Z1   |   Z2   |   Z3   |  ....  |   ZN
+
+# Not all columns need to have the same length.
+# The data structure is a list of columns;
+# each column is a list of items.
+# Each item is a pair of a string and an action procedure.
+# The first item may be a column title.
+
+import stdwin
+import gwin
+
+def open(title, data): # Public function to open a table window
+	#
+	# Set geometry parameters (one day, these may be changeable)
+	#
+	margin = stdwin.textwidth('  ')
+	lineheight = stdwin.lineheight()
+	#
+	# Geometry calculations
+	#
+	colstarts = [0]
+	totwidth = 0
+	maxrows = 0
+	for coldata in data:
+		# Height calculations
+		rows = len(coldata)
+		if rows > maxrows: maxrows = rows
+		# Width calculations
+		width = colwidth(coldata) + margin
+		totwidth = totwidth + width
+		colstarts.append(totwidth)
+	#
+	# Calculate document and window height
+	#
+	docwidth, docheight = totwidth, maxrows*lineheight
+	winwidth, winheight = docwidth, docheight
+	if winwidth > stdwin.textwidth('n')*100: winwidth = 0
+	if winheight > stdwin.lineheight()*30: winheight = 0
+	#
+	# Create the window
+	#
+	stdwin.setdefwinsize(winwidth, winheight)
+	w = gwin.open(title)
+	#
+	# Set properties and override methods
+	#
+	w.data = data
+	w.margin = margin
+	w.lineheight = lineheight
+	w.colstarts = colstarts
+	w.totwidth = totwidth
+	w.maxrows = maxrows
+	w.selection = (-1, -1)
+	w.lastselection = (-1, -1)
+	w.selshown = 0
+	w.setdocsize(docwidth, docheight)
+	w.draw = draw
+	w.mup = mup
+	w.arrow = arrow
+	#
+	# Return
+	#
+	return w
+
+def update(w, data): # Change the data
+	#
+	# Hide selection
+	#
+	hidesel(w, w.begindrawing())
+	#
+	# Get old geometry parameters
+	#
+	margin = w.margin
+	lineheight = w.lineheight
+	#
+	# Geometry calculations
+	#
+	colstarts = [0]
+	totwidth = 0
+	maxrows = 0
+	for coldata in data:
+		# Height calculations
+		rows = len(coldata)
+		if rows > maxrows: maxrows = rows
+		# Width calculations
+		width = colwidth(coldata) + margin
+		totwidth = totwidth + width
+		colstarts.append(totwidth)
+	#
+	# Calculate document and window height
+	#
+	docwidth, docheight = totwidth, maxrows*lineheight
+	#
+	# Set changed properties and change window size
+	#
+	w.data = data
+	w.colstarts = colstarts
+	w.totwidth = totwidth
+	w.maxrows = maxrows
+	w.change((0, 0), (10000, 10000))
+	w.setdocsize(docwidth, docheight)
+	w.change((0, 0), (docwidth, docheight))
+	#
+	# Show selection, or forget it if out of range
+	#
+	showsel(w, w.begindrawing())
+	if not w.selshown: w.selection = (-1, -1)
+
+def colwidth(coldata): # Subroutine to calculate column width
+	maxwidth = 0
+	for string, action in coldata:
+		width = stdwin.textwidth(string)
+		if width > maxwidth: maxwidth = width
+	return maxwidth
+
+def draw(w, ((left, top), (right, bottom))): # Draw method
+	ileft = whichcol(w, left)
+	iright = whichcol(w, right-1) + 1
+	if iright > len(w.data): iright = len(w.data)
+	itop = divmod(top, w.lineheight)[0]
+	if itop < 0: itop = 0
+	ibottom, remainder = divmod(bottom, w.lineheight)
+	if remainder: ibottom = ibottom + 1
+	d = w.begindrawing()
+	if ileft <= w.selection[0] < iright:
+		if itop <= w.selection[1] < ibottom:
+			hidesel(w, d)
+	d.erase((left, top), (right, bottom))
+	for i in range(ileft, iright):
+		col = w.data[i]
+		jbottom = len(col)
+		if ibottom < jbottom: jbottom = ibottom
+		h = w.colstarts[i]
+		v = itop * w.lineheight
+		for j in range(itop, jbottom):
+			string, action = col[j]
+			d.text((h, v), string)
+			v = v + w.lineheight
+	showsel(w, d)
+
+def mup(w, detail): # Mouse up method
+	(h, v), nclicks, button, mask = detail
+	icol = whichcol(w, h)
+	if 0 <= icol < len(w.data):
+		irow = divmod(v, w.lineheight)[0]
+		col = w.data[icol]
+		if 0 <= irow < len(col):
+			string, action = col[irow]
+			action(w, string, (icol, irow), detail)
+
+def whichcol(w, h): # Return column number (may be >= len(w.data))
+	for icol in range(0, len(w.data)):
+		if h < w.colstarts[icol+1]:
+			return icol
+	return len(w.data)
+
+def arrow(w, type):
+	import stdwinsupport
+	S = stdwinsupport
+	if type = S.wc_left:
+		incr = -1, 0
+	elif type = S.wc_up:
+		incr = 0, -1
+	elif type = S.wc_right:
+		incr = 1, 0
+	elif type = S.wc_down:
+		incr = 0, 1
+	else:
+		return
+	icol, irow = w.lastselection
+	icol = icol + incr[0]
+	if icol < 0: icol = len(w.data)-1
+	if icol >= len(w.data): icol = 0
+	if 0 <= icol < len(w.data):
+		irow = irow + incr[1]
+		if irow < 0: irow = len(w.data[icol]) - 1
+		if irow >= len(w.data[icol]): irow = 0
+	else:
+		irow = 0
+	if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
+		w.lastselection = icol, irow
+		string, action = w.data[icol][irow]
+		detail = (0, 0), 1, 1, 1
+		action(w, string, (icol, irow), detail)
+
+
+# Selection management
+# TO DO: allow multiple selected entries
+
+def select(w, selection): # Public function to set the item selection
+	d = w.begindrawing()
+	hidesel(w, d)
+	w.selection = selection
+	showsel(w, d)
+	if w.selshown: lastselection = selection
+
+def hidesel(w, d): # Hide the selection, if shown
+	if w.selshown: invertsel(w, d)
+
+def showsel(w, d): # Show the selection, if hidden
+	if not w.selshown: invertsel(w, d)
+
+def invertsel(w, d): # Invert the selection, if valid
+	icol, irow = w.selection
+	if 0 <= icol < len(w.data) and 0 <= irow < len(w.data[icol]):
+		left = w.colstarts[icol]
+		right = w.colstarts[icol+1]
+		top = irow * w.lineheight
+		bottom = (irow+1) * w.lineheight
+		d.invert((left, top), (right, bottom))
+		w.selshown = (not w.selshown)
+
+
+# Demonstration
+
+def demo_action(w, string, (icol, irow), detail): # Action function for demo
+	select(w, (irow, icol))
+
+def demo(): # Demonstration
+	da = demo_action # shorthand
+	col0 = [('a1', da), ('bbb1', da), ('c1', da)]
+	col1 = [('a2', da), ('bbb2', da)]
+	col2 = [('a3', da), ('b3', da), ('c3', da), ('d4', da), ('d5', da)]
+	col3 = []
+	for i in range(1, 31): col3.append('xxx' + `i`, da)
+	data = [col0, col1, col2, col3]
+	w = open('tablewin.demo', data)
+	gwin.mainloop()
+	return w
diff --git a/Lib/stdwin/textwin.py b/Lib/stdwin/textwin.py
new file mode 100755
index 0000000..2631ca4
--- /dev/null
+++ b/Lib/stdwin/textwin.py
@@ -0,0 +1,119 @@
+# Module 'textwin'
+
+# Text windows, a subclass of gwin
+
+import stdwin
+import stdwinsupport
+import gwin
+
+S = stdwinsupport			# Shorthand
+
+
+def fixsize(w):
+	docwidth, docheight = w.text.getrect()[1]
+	winheight = w.getwinsize()[1]
+	if winheight > docheight: docheight = winheight
+	w.setdocsize(0, docheight)
+	fixeditmenu(w)
+
+def cut(w, m, id):
+	s = w.text.getfocustext()
+	if s:
+		stdwin.setcutbuffer(s)
+		w.text.replace('')
+		fixsize(w)
+
+def copy(w, m, id):
+	s = w.text.getfocustext()
+	if s:
+		stdwin.setcutbuffer(s)
+		fixeditmenu(w)
+
+def paste(w, m, id):
+	w.text.replace(stdwin.getcutbuffer())
+	fixsize(w)
+
+def addeditmenu(w):
+	m = w.editmenu = w.menucreate('Edit')
+	m.action = []
+	m.additem('Cut', 'X')
+	m.action.append(cut)
+	m.additem('Copy', 'C')
+	m.action.append(copy)
+	m.additem('Paste', 'V')
+	m.action.append(paste)
+
+def fixeditmenu(w):
+	m = w.editmenu
+	f = w.text.getfocus()
+	can_copy = (f[0] < f[1])
+	m.enable(1, can_copy)
+	if not w.readonly:
+		m.enable(0, can_copy)
+		m.enable(2, (stdwin.getcutbuffer() <> ''))
+
+def draw(w, area):			# Draw method
+	w.text.draw(area)
+
+def size(w, newsize):			# Size method
+	w.text.move((0, 0), newsize)
+	fixsize(w)
+
+def close(w):				# Close method
+	del w.text  # Break circular ref
+	gwin.close(w)
+
+def char(w, c):				# Char method
+	w.text.replace(c)
+	fixsize(w)
+
+def backspace(w):			# Backspace method
+	void = w.text.event(S.we_command, w, S.wc_backspace)
+	fixsize(w)
+
+def arrow(w, detail):			# Arrow method
+	w.text.arrow(detail)
+	fixeditmenu(w)
+
+def mdown(w, detail):			# Mouse down method
+	void = w.text.event(S.we_mouse_down, w, detail)
+	fixeditmenu(w)
+
+def mmove(w, detail):			# Mouse move method
+	void = w.text.event(S.we_mouse_move, w, detail)
+
+def mup(w, detail):			# Mouse up method
+	void = w.text.event(S.we_mouse_up, w, detail)
+	fixeditmenu(w)
+
+def activate(w):			# Activate method
+	fixeditmenu(w)
+
+def open(title, str):			# Display a string in a window
+	w = gwin.open(title)
+	w.readonly = 0
+	w.text = w.textcreate((0, 0), w.getwinsize())
+	w.text.replace(str)
+	w.text.setfocus(0, 0)
+	addeditmenu(w)
+	fixsize(w)
+	w.draw = draw
+	w.size = size
+	w.close = close
+	w.mdown = mdown
+	w.mmove = mmove
+	w.mup = mup
+	w.char = char
+	w.backspace = backspace
+	w.arrow = arrow
+	w.activate = activate
+	return w
+
+def open_readonly(title, str):		# Same with char input disabled
+	w = open(title, str)
+	w.readonly = 1
+	w.char = w.backspace = gwin.nop
+	# Disable Cut and Paste menu item; leave Copy alone
+	w.editmenu.enable(0, 0)
+	w.editmenu.enable(2, 0)
+	return w
diff --git a/Lib/string.py b/Lib/string.py
new file mode 100644
index 0000000..2a4feae
--- /dev/null
+++ b/Lib/string.py
@@ -0,0 +1,129 @@
+# module 'string' -- A collection of string operations
+
+# XXX Some of these operations are incredibly slow and should be built in
+
+# Some strings for ctype-style character classification
+whitespace = ' \t\n'
+lowercase = 'abcdefghijklmnopqrstuvwxyz'
+uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+letters = lowercase + uppercase
+digits = '0123456789'
+hexdigits = digits + 'abcdef' + 'ABCDEF'
+octdigits = '01234567'
+
+# Case conversion helpers
+_caseswap = {}
+for i in range(26):
+	_caseswap[lowercase[i]] = uppercase[i]
+	_caseswap[uppercase[i]] = lowercase[i]
+del i
+
+# convert UPPER CASE letters to lower case
+def lower(s):
+	res = ''
+	for c in s:
+		if 'A' <= c <= 'Z': c = _caseswap[c]
+		res = res + c
+	return res
+
+# Convert lower case letters to UPPER CASE
+def upper(s):
+	res = ''
+	for c in s:
+		if 'a' <= c <= 'z': c = _caseswap[c]
+		res = res + c
+	return res
+
+# Swap lower case letters and UPPER CASE
+def swapcase(s):
+	res = ''
+	for c in s:
+		if 'a' <= c <= 'z' or 'A' <= c <= 'Z': c = _caseswap[c]
+		res = res + c
+	return res
+
+# Strip leading and trailing tabs and spaces
+def strip(s):
+	i, j = 0, len(s)
+	while i < j and s[i] in whitespace: i = i+1
+	while i < j and s[j-1] in whitespace: j = j-1
+	return s[i:j]
+
+# Split a string into a list of space/tab-separated words
+# NB: split(s) is NOT the same as splitfields(s, ' ')!
+def split(s):
+	res = []
+	i, n = 0, len(s)
+	while i < n:
+		while i < n and s[i] in whitespace: i = i+1
+		if i = n: break
+		j = i
+		while j < n and s[j] not in whitespace: j = j+1
+		res.append(s[i:j])
+		i = j
+	return res
+
+# Split a list into fields separated by a given string
+# NB: splitfields(s, ' ') is NOT the same as split(s)!
+def splitfields(s, sep):
+	res = []
+	ns = len(s)
+	nsep = len(sep)
+	i = j = 0
+	while j+nsep <= ns:
+		if s[j:j+nsep] = sep:
+			res.append(s[i:j])
+			i = j = j + nsep
+		else:
+			j = j + 1
+	res.append(s[i:])
+	return res
+
+# Find substring
+index_error = 'substring not found in string.index'
+def index(s, sub):
+	n = len(sub)
+	for i in range(len(s) - n):
+		if sub = s[i:i+n]: return i
+	raise index_error, (s, sub)
+
+# Convert string to integer
+atoi_error = 'non-numeric argument to string.atoi'
+def atoi(str):
+	s = str
+	if s[:1] in '+-': s = s[1:]
+	if not s: raise atoi_error, str
+	for c in s:
+		if c not in digits: raise atoi_error, str
+	return eval(str)
+
+# Left-justify a string
+def ljust(s, width):
+	n = len(s)
+	if n >= width: return s
+	return s + ' '*(width-n)
+
+# Right-justify a string
+def rjust(s, width):
+	n = len(s)
+	if n >= width: return s
+	return ' '*(width-n) + s
+
+# Center a string
+def center(s, width):
+	n = len(s)
+	if n >= width: return s
+	return ' '*((width-n)/2) +  s + ' '*(width -(width-n)/2)
+
+# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
+# Decadent feature: the argument may be a string or a number
+# (Use of this is deprecated; it should be a string as with ljust c.s.)
+def zfill(x, width):
+	if type(x) = type(''): s = x
+	else: s = `x`
+	n = len(s)
+	if n >= width: return s
+	sign = ''
+	if s[0] = '-':
+		sign, s = '-', s[1:]
+	return sign + '0'*(width-n) + s
diff --git a/Lib/stringold.py b/Lib/stringold.py
new file mode 100644
index 0000000..2a4feae
--- /dev/null
+++ b/Lib/stringold.py
@@ -0,0 +1,129 @@
+# module 'string' -- A collection of string operations
+
+# XXX Some of these operations are incredibly slow and should be built in
+
+# Some strings for ctype-style character classification
+whitespace = ' \t\n'
+lowercase = 'abcdefghijklmnopqrstuvwxyz'
+uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+letters = lowercase + uppercase
+digits = '0123456789'
+hexdigits = digits + 'abcdef' + 'ABCDEF'
+octdigits = '01234567'
+
+# Case conversion helpers
+_caseswap = {}
+for i in range(26):
+	_caseswap[lowercase[i]] = uppercase[i]
+	_caseswap[uppercase[i]] = lowercase[i]
+del i
+
+# convert UPPER CASE letters to lower case
+def lower(s):
+	res = ''
+	for c in s:
+		if 'A' <= c <= 'Z': c = _caseswap[c]
+		res = res + c
+	return res
+
+# Convert lower case letters to UPPER CASE
+def upper(s):
+	res = ''
+	for c in s:
+		if 'a' <= c <= 'z': c = _caseswap[c]
+		res = res + c
+	return res
+
+# Swap lower case letters and UPPER CASE
+def swapcase(s):
+	res = ''
+	for c in s:
+		if 'a' <= c <= 'z' or 'A' <= c <= 'Z': c = _caseswap[c]
+		res = res + c
+	return res
+
+# Strip leading and trailing tabs and spaces
+def strip(s):
+	i, j = 0, len(s)
+	while i < j and s[i] in whitespace: i = i+1
+	while i < j and s[j-1] in whitespace: j = j-1
+	return s[i:j]
+
+# Split a string into a list of space/tab-separated words
+# NB: split(s) is NOT the same as splitfields(s, ' ')!
+def split(s):
+	res = []
+	i, n = 0, len(s)
+	while i < n:
+		while i < n and s[i] in whitespace: i = i+1
+		if i = n: break
+		j = i
+		while j < n and s[j] not in whitespace: j = j+1
+		res.append(s[i:j])
+		i = j
+	return res
+
+# Split a list into fields separated by a given string
+# NB: splitfields(s, ' ') is NOT the same as split(s)!
+def splitfields(s, sep):
+	res = []
+	ns = len(s)
+	nsep = len(sep)
+	i = j = 0
+	while j+nsep <= ns:
+		if s[j:j+nsep] = sep:
+			res.append(s[i:j])
+			i = j = j + nsep
+		else:
+			j = j + 1
+	res.append(s[i:])
+	return res
+
+# Find substring
+index_error = 'substring not found in string.index'
+def index(s, sub):
+	n = len(sub)
+	for i in range(len(s) - n):
+		if sub = s[i:i+n]: return i
+	raise index_error, (s, sub)
+
+# Convert string to integer
+atoi_error = 'non-numeric argument to string.atoi'
+def atoi(str):
+	s = str
+	if s[:1] in '+-': s = s[1:]
+	if not s: raise atoi_error, str
+	for c in s:
+		if c not in digits: raise atoi_error, str
+	return eval(str)
+
+# Left-justify a string
+def ljust(s, width):
+	n = len(s)
+	if n >= width: return s
+	return s + ' '*(width-n)
+
+# Right-justify a string
+def rjust(s, width):
+	n = len(s)
+	if n >= width: return s
+	return ' '*(width-n) + s
+
+# Center a string
+def center(s, width):
+	n = len(s)
+	if n >= width: return s
+	return ' '*((width-n)/2) +  s + ' '*(width -(width-n)/2)
+
+# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
+# Decadent feature: the argument may be a string or a number
+# (Use of this is deprecated; it should be a string as with ljust c.s.)
+def zfill(x, width):
+	if type(x) = type(''): s = x
+	else: s = `x`
+	n = len(s)
+	if n >= width: return s
+	sign = ''
+	if s[0] = '-':
+		sign, s = '-', s[1:]
+	return sign + '0'*(width-n) + s
diff --git a/Lib/util.py b/Lib/util.py
new file mode 100644
index 0000000..dc67686
--- /dev/null
+++ b/Lib/util.py
@@ -0,0 +1,9 @@
+# Module 'util' -- some useful functions that dont fit elsewhere
+
+# Remove an item from a list at most once
+#
+def remove(item, list):
+	for i in range(len(list)):
+		if list[i] = item:
+			del list[i]
+			break
diff --git a/Lib/whrandom.py b/Lib/whrandom.py
new file mode 100644
index 0000000..2ce5f8f
--- /dev/null
+++ b/Lib/whrandom.py
@@ -0,0 +1,74 @@
+#	WICHMANN-HILL RANDOM NUMBER GENERATOR
+#
+#	Wichmann, B. A. & Hill, I. D. (1982)
+#	Algorithm AS 183: 
+#	An efficient and portable pseudo-random number generator
+#	Applied Statistics 31 (1982) 188-190
+#
+#	see also: 
+#		Correction to Algorithm AS 183
+#		Applied Statistics 33 (1984) 123  
+#
+#		McLeod, A. I. (1985)
+#		A remark on Algorithm AS 183 
+#		Applied Statistics 34 (1985),198-200
+#
+#
+#	USE:
+#	whrandom.random()	yields double precision random numbers 
+#				uniformly distributed between 0 and 1.
+#
+#	whrandom.seed()		must be called before whrandom.random()
+#				to seed the generator
+
+
+#	Translated by Guido van Rossum from C source provided by
+#	Adrian Baddeley.
+
+
+# The seed
+#
+_seed = [0, 0, 0]
+
+
+# Set the seed
+#
+def seed(x, y, z):
+	_seed[:] = [x, y, z]
+
+
+# Return the next random number in the range [0.0 .. 1.0)
+#
+def random():
+	from math import floor		# floor() function
+	#
+	[x, y, z] = _seed
+	x = 171 * (x % 177) - 2 * (x/177)
+	y = 172 * (y % 176) - 35 * (y/176)
+	z = 170 * (z % 178) - 63 * (z/178)
+	#
+	if x < 0: x = x + 30269
+	if y < 0: y = y + 30307
+	if z < 0: z = z + 30323
+	#
+	_seed[:] = [x, y, z]
+	#
+	term = float(x)/30269.0 + float(y)/30307.0 + float(z)/30323.0
+	rand = term - floor(term)
+	#
+	if rand >= 1.0: rand = 0.0	# floor() inaccuracy?
+	#
+	return rand
+
+
+# Initialize from the current time
+#
+def init():
+	import time
+	t = time.time()
+	seed(t%256, t/256%256, t/65536%256)
+
+
+# Make sure the generator is preset to a nonzero value
+#
+init()