Fuck.  For PC support, this must be in the distribution.
diff --git a/Lib/dos-8x3/bastion.py b/Lib/dos-8x3/bastion.py
new file mode 100755
index 0000000..7ddd93e
--- /dev/null
+++ b/Lib/dos-8x3/bastion.py
@@ -0,0 +1,162 @@
+"""Bastionification utility.
+
+A bastion (for another object -- the 'original') is an object that has
+the same methods as the original but does not give access to its
+instance variables.  Bastions have a number of uses, but the most
+obvious one is to provide code executing in restricted mode with a
+safe interface to an object implemented in unrestricted mode.
+
+The bastionification routine has an optional second argument which is
+a filter function.  Only those methods for which the filter method
+(called with the method name as argument) returns true are accessible.
+The default filter method returns true unless the method name begins
+with an underscore.
+
+There are a number of possible implementations of bastions.  We use a
+'lazy' approach where the bastion's __getattr__() discipline does all
+the work for a particular method the first time it is used.  This is
+usually fastest, especially if the user doesn't call all available
+methods.  The retrieved methods are stored as instance variables of
+the bastion, so the overhead is only occurred on the first use of each
+method.
+
+Detail: the bastion class has a __repr__() discipline which includes
+the repr() of the original object.  This is precomputed when the
+bastion is created.
+
+"""
+
+__version__ = '$Revision$'
+# $Source$
+
+
+from types import MethodType
+
+
+class BastionClass:
+
+    """Helper class used by the Bastion() function.
+
+    You could subclass this and pass the subclass as the bastionclass
+    argument to the Bastion() function, as long as the constructor has
+    the same signature (a get() function and a name for the object).
+
+    """
+
+    def __init__(self, get, name):
+	"""Constructor.
+
+	Arguments:
+
+	get - a function that gets the attribute value (by name)
+	name - a human-readable name for the original object
+	       (suggestion: use repr(object))
+
+	"""
+	self._get_ = get
+	self._name_ = name
+
+    def __repr__(self):
+	"""Return a representation string.
+
+	This includes the name passed in to the constructor, so that
+	if you print the bastion during debugging, at least you have
+	some idea of what it is.
+
+	"""
+	return "<Bastion for %s>" % self._name_
+
+    def __getattr__(self, name):
+	"""Get an as-yet undefined attribute value.
+
+	This calls the get() function that was passed to the
+	constructor.  The result is stored as an instance variable so
+	that the next time the same attribute is requested,
+	__getattr__() won't be invoked.
+
+	If the get() function raises an exception, this is simply
+	passed on -- exceptions are not cached.
+
+	"""
+	attribute = self._get_(name)
+	self.__dict__[name] = attribute
+	return attribute
+
+
+def Bastion(object, filter = lambda name: name[:1] != '_',
+	    name=None, bastionclass=BastionClass):
+    """Create a bastion for an object, using an optional filter.
+
+    See the Bastion module's documentation for background.
+
+    Arguments:
+
+    object - the original object
+    filter - a predicate that decides whether a function name is OK;
+             by default all names are OK that don't start with '_'
+    name - the name of the object; default repr(object)
+    bastionclass - class used to create the bastion; default BastionClass
+
+    """
+
+    # Note: we define *two* ad-hoc functions here, get1 and get2.
+    # Both are intended to be called in the same way: get(name).
+    # It is clear that the real work (getting the attribute
+    # from the object and calling the filter) is done in get1.
+    # Why can't we pass get1 to the bastion?  Because the user
+    # would be able to override the filter argument!  With get2,
+    # overriding the default argument is no security loophole:
+    # all it does is call it.
+    # Also notice that we can't place the object and filter as
+    # instance variables on the bastion object itself, since
+    # the user has full access to all instance variables!
+
+    def get1(name, object=object, filter=filter):
+	"""Internal function for Bastion().  See source comments."""
+	if filter(name):
+	    attribute = getattr(object, name)
+	    if type(attribute) == MethodType:
+		return attribute
+	raise AttributeError, name
+
+    def get2(name, get1=get1):
+	"""Internal function for Bastion().  See source comments."""
+	return get1(name)
+
+    if name is None:
+	name = `object`
+    return bastionclass(get2, name)
+
+
+def _test():
+    """Test the Bastion() function."""
+    class Original:
+	def __init__(self):
+	    self.sum = 0
+	def add(self, n):
+	    self._add(n)
+	def _add(self, n):
+	    self.sum = self.sum + n
+	def total(self):
+	    return self.sum
+    o = Original()
+    b = Bastion(o)
+    b.add(81)
+    b.add(18)
+    print "b.total() =", b.total()
+    try:
+	print "b.sum =", b.sum,
+    except:
+	print "inaccessible"
+    else:
+	print "accessible"
+    try:
+	print "b._add =", b._add,
+    except:
+	print "inaccessible"
+    else:
+	print "accessible"
+
+
+if __name__ == '__main__':
+    _test()