Initial revision
diff --git a/Lib/idlelib/loader.py b/Lib/idlelib/loader.py
new file mode 100644
index 0000000..6a438c3
--- /dev/null
+++ b/Lib/idlelib/loader.py
@@ -0,0 +1,64 @@
+# Everything is done inside the loader function so that no other names
+# are placed in the global namespace.  Before user code is executed,
+# even this name is unbound.
+def loader():
+    import sys, os, protocol, threading, time
+    import Remote
+
+##  Use to debug the loading process itself:
+##    sys.stdout = open('c:\\windows\\desktop\\stdout.txt','a')
+##    sys.stderr = open('c:\\windows\\desktop\\stderr.txt','a')
+
+    # Ensure that there is absolutely no pollution of the global
+    # namespace by deleting the global name of this function.
+    global loader
+    del loader
+
+    # Connect to IDLE
+    try:
+        client = protocol.Client()
+    except protocol.connectionLost, cL:
+        print 'loader: Unable to connect to IDLE', cL
+        return
+
+    # Connect to an ExecBinding object that needs our help.  If
+    # the user is starting multiple programs right now, we might get a
+    # different one than the one that started us.  Proving that's okay is
+    # left as an exercise to the reader.  (HINT:  Twelve, by the pigeonhole
+    # principle)
+    ExecBinding = client.getobject('ExecBinding')
+    if not ExecBinding:
+        print "loader: IDLE does not need me."
+        return
+
+    # All of our input and output goes through ExecBinding.
+    sys.stdin  = Remote.pseudoIn( ExecBinding.readline )
+    sys.stdout = Remote.pseudoOut( ExecBinding.write.void, tag="stdout" )
+    sys.stderr = Remote.pseudoOut( ExecBinding.write.void, tag="stderr" )
+
+    # Create a Remote object and start it running.
+    remote = Remote.Remote(globals(), ExecBinding)
+    rthread = threading.Thread(target=remote.mainloop)
+    rthread.setDaemon(1)
+    rthread.start()
+
+    # Block until either the client or the user program stops
+    user = rthread.isAlive
+    while user and client.isAlive():
+        time.sleep(0.025)
+
+        if not user():
+          user = hasattr(sys, "ready_to_exit") and sys.ready_to_exit
+          for t in threading.enumerate():
+            if not t.isDaemon() and t.isAlive() and t!=threading.currentThread():
+              user = t.isAlive
+              break
+
+    # We need to make sure we actually exit, so that the user doesn't get
+    #   stuck with an invisible process.  We want to finalize C modules, so
+    #   we don't use os._exit(), but we don't call sys.exitfunc, which might
+    #   block forever.
+    del sys.exitfunc
+    sys.exit()
+
+loader()