Add back files that were accidentally deleted on the trunk rather than
on the idlefork-merge-branch as intended.
diff --git a/Tools/idle/AutoIndent.py b/Tools/idle/AutoIndent.py
new file mode 100644
index 0000000..7bc195b
--- /dev/null
+++ b/Tools/idle/AutoIndent.py
@@ -0,0 +1,551 @@
+#from Tkinter import TclError
+#import tkMessageBox
+#import tkSimpleDialog
+
+###$ event <<newline-and-indent>>
+###$ win <Key-Return>
+###$ win <KP_Enter>
+###$ unix <Key-Return>
+###$ unix <KP_Enter>
+
+###$ event <<indent-region>>
+###$ win <Control-bracketright>
+###$ unix <Alt-bracketright>
+###$ unix <Control-bracketright>
+
+###$ event <<dedent-region>>
+###$ win <Control-bracketleft>
+###$ unix <Alt-bracketleft>
+###$ unix <Control-bracketleft>
+
+###$ event <<comment-region>>
+###$ win <Alt-Key-3>
+###$ unix <Alt-Key-3>
+
+###$ event <<uncomment-region>>
+###$ win <Alt-Key-4>
+###$ unix <Alt-Key-4>
+
+###$ event <<tabify-region>>
+###$ win <Alt-Key-5>
+###$ unix <Alt-Key-5>
+
+###$ event <<untabify-region>>
+###$ win <Alt-Key-6>
+###$ unix <Alt-Key-6>
+
+import PyParse
+
+class AutoIndent:
+
+    menudefs = [
+        ('edit', [
+            None,
+            ('_Indent region', '<<indent-region>>'),
+            ('_Dedent region', '<<dedent-region>>'),
+            ('Comment _out region', '<<comment-region>>'),
+            ('U_ncomment region', '<<uncomment-region>>'),
+            ('Tabify region', '<<tabify-region>>'),
+            ('Untabify region', '<<untabify-region>>'),
+            ('Toggle tabs', '<<toggle-tabs>>'),
+            ('New indent width', '<<change-indentwidth>>'),
+        ]),
+    ]
+
+    keydefs = {
+        '<<smart-backspace>>': ['<Key-BackSpace>'],
+        '<<newline-and-indent>>': ['<Key-Return>', '<KP_Enter>'],
+        '<<smart-indent>>': ['<Key-Tab>']
+    }
+
+    windows_keydefs = {
+        '<<indent-region>>': ['<Control-bracketright>'],
+        '<<dedent-region>>': ['<Control-bracketleft>'],
+        '<<comment-region>>': ['<Alt-Key-3>'],
+        '<<uncomment-region>>': ['<Alt-Key-4>'],
+        '<<tabify-region>>': ['<Alt-Key-5>'],
+        '<<untabify-region>>': ['<Alt-Key-6>'],
+        '<<toggle-tabs>>': ['<Alt-Key-t>'],
+        '<<change-indentwidth>>': ['<Alt-Key-u>'],
+    }
+
+    unix_keydefs = {
+        '<<indent-region>>': ['<Alt-bracketright>',
+                              '<Meta-bracketright>',
+                              '<Control-bracketright>'],
+        '<<dedent-region>>': ['<Alt-bracketleft>',
+                              '<Meta-bracketleft>',
+                              '<Control-bracketleft>'],
+        '<<comment-region>>': ['<Alt-Key-3>', '<Meta-Key-3>'],
+        '<<uncomment-region>>': ['<Alt-Key-4>', '<Meta-Key-4>'],
+        '<<tabify-region>>': ['<Alt-Key-5>', '<Meta-Key-5>'],
+        '<<untabify-region>>': ['<Alt-Key-6>', '<Meta-Key-6>'],
+        '<<toggle-tabs>>': ['<Alt-Key-t>'],
+        '<<change-indentwidth>>': ['<Alt-Key-u>'],
+    }
+
+    # usetabs true  -> literal tab characters are used by indent and
+    #                  dedent cmds, possibly mixed with spaces if
+    #                  indentwidth is not a multiple of tabwidth
+    #         false -> tab characters are converted to spaces by indent
+    #                  and dedent cmds, and ditto TAB keystrokes
+    # indentwidth is the number of characters per logical indent level.
+    # tabwidth is the display width of a literal tab character.
+    # CAUTION:  telling Tk to use anything other than its default
+    # tab setting causes it to use an entirely different tabbing algorithm,
+    # treating tab stops as fixed distances from the left margin.
+    # Nobody expects this, so for now tabwidth should never be changed.
+    usetabs = 1
+    indentwidth = 4
+    tabwidth = 8    # for IDLE use, must remain 8 until Tk is fixed
+
+    # If context_use_ps1 is true, parsing searches back for a ps1 line;
+    # else searches for a popular (if, def, ...) Python stmt.
+    context_use_ps1 = 0
+
+    # When searching backwards for a reliable place to begin parsing,
+    # first start num_context_lines[0] lines back, then
+    # num_context_lines[1] lines back if that didn't work, and so on.
+    # The last value should be huge (larger than the # of lines in a
+    # conceivable file).
+    # Making the initial values larger slows things down more often.
+    num_context_lines = 50, 500, 5000000
+
+    def __init__(self, editwin):
+        self.editwin = editwin
+        self.text = editwin.text
+
+    def config(self, **options):
+        for key, value in options.items():
+            if key == 'usetabs':
+                self.usetabs = value
+            elif key == 'indentwidth':
+                self.indentwidth = value
+            elif key == 'tabwidth':
+                self.tabwidth = value
+            elif key == 'context_use_ps1':
+                self.context_use_ps1 = value
+            else:
+                raise KeyError, "bad option name: %s" % `key`
+
+    # If ispythonsource and guess are true, guess a good value for
+    # indentwidth based on file content (if possible), and if
+    # indentwidth != tabwidth set usetabs false.
+    # In any case, adjust the Text widget's view of what a tab
+    # character means.
+
+    def set_indentation_params(self, ispythonsource, guess=1):
+        if guess and ispythonsource:
+            i = self.guess_indent()
+            if 2 <= i <= 8:
+                self.indentwidth = i
+            if self.indentwidth != self.tabwidth:
+                self.usetabs = 0
+
+        self.editwin.set_tabwidth(self.tabwidth)
+
+    def smart_backspace_event(self, event):
+        text = self.text
+        first, last = self.editwin.get_selection_indices()
+        if first and last:
+            text.delete(first, last)
+            text.mark_set("insert", first)
+            return "break"
+        # Delete whitespace left, until hitting a real char or closest
+        # preceding virtual tab stop.
+        chars = text.get("insert linestart", "insert")
+        if chars == '':
+            if text.compare("insert", ">", "1.0"):
+                # easy: delete preceding newline
+                text.delete("insert-1c")
+            else:
+                text.bell()     # at start of buffer
+            return "break"
+        if  chars[-1] not in " \t":
+            # easy: delete preceding real char
+            text.delete("insert-1c")
+            return "break"
+        # Ick.  It may require *inserting* spaces if we back up over a
+        # tab character!  This is written to be clear, not fast.
+        tabwidth = self.tabwidth
+        have = len(chars.expandtabs(tabwidth))
+        assert have > 0
+        want = ((have - 1) // self.indentwidth) * self.indentwidth
+        ncharsdeleted = 0
+        while 1:
+            chars = chars[:-1]
+            ncharsdeleted = ncharsdeleted + 1
+            have = len(chars.expandtabs(tabwidth))
+            if have <= want or chars[-1] not in " \t":
+                break
+        text.undo_block_start()
+        text.delete("insert-%dc" % ncharsdeleted, "insert")
+        if have < want:
+            text.insert("insert", ' ' * (want - have))
+        text.undo_block_stop()
+        return "break"
+
+    def smart_indent_event(self, event):
+        # if intraline selection:
+        #     delete it
+        # elif multiline selection:
+        #     do indent-region & return
+        # indent one level
+        text = self.text
+        first, last = self.editwin.get_selection_indices()
+        text.undo_block_start()
+        try:
+            if first and last:
+                if index2line(first) != index2line(last):
+                    return self.indent_region_event(event)
+                text.delete(first, last)
+                text.mark_set("insert", first)
+            prefix = text.get("insert linestart", "insert")
+            raw, effective = classifyws(prefix, self.tabwidth)
+            if raw == len(prefix):
+                # only whitespace to the left
+                self.reindent_to(effective + self.indentwidth)
+            else:
+                if self.usetabs:
+                    pad = '\t'
+                else:
+                    effective = len(prefix.expandtabs(self.tabwidth))
+                    n = self.indentwidth
+                    pad = ' ' * (n - effective % n)
+                text.insert("insert", pad)
+            text.see("insert")
+            return "break"
+        finally:
+            text.undo_block_stop()
+
+    def newline_and_indent_event(self, event):
+        text = self.text
+        first, last = self.editwin.get_selection_indices()
+        text.undo_block_start()
+        try:
+            if first and last:
+                text.delete(first, last)
+                text.mark_set("insert", first)
+            line = text.get("insert linestart", "insert")
+            i, n = 0, len(line)
+            while i < n and line[i] in " \t":
+                i = i+1
+            if i == n:
+                # the cursor is in or at leading indentation; just inject
+                # an empty line at the start
+                text.insert("insert linestart", '\n')
+                return "break"
+            indent = line[:i]
+            # strip whitespace before insert point
+            i = 0
+            while line and line[-1] in " \t":
+                line = line[:-1]
+                i = i+1
+            if i:
+                text.delete("insert - %d chars" % i, "insert")
+            # strip whitespace after insert point
+            while text.get("insert") in " \t":
+                text.delete("insert")
+            # start new line
+            text.insert("insert", '\n')
+
+            # adjust indentation for continuations and block
+            # open/close first need to find the last stmt
+            lno = index2line(text.index('insert'))
+            y = PyParse.Parser(self.indentwidth, self.tabwidth)
+            for context in self.num_context_lines:
+                startat = max(lno - context, 1)
+                startatindex = `startat` + ".0"
+                rawtext = text.get(startatindex, "insert")
+                y.set_str(rawtext)
+                bod = y.find_good_parse_start(
+                          self.context_use_ps1,
+                          self._build_char_in_string_func(startatindex))
+                if bod is not None or startat == 1:
+                    break
+            y.set_lo(bod or 0)
+            c = y.get_continuation_type()
+            if c != PyParse.C_NONE:
+                # The current stmt hasn't ended yet.
+                if c == PyParse.C_STRING:
+                    # inside a string; just mimic the current indent
+                    text.insert("insert", indent)
+                elif c == PyParse.C_BRACKET:
+                    # line up with the first (if any) element of the
+                    # last open bracket structure; else indent one
+                    # level beyond the indent of the line with the
+                    # last open bracket
+                    self.reindent_to(y.compute_bracket_indent())
+                elif c == PyParse.C_BACKSLASH:
+                    # if more than one line in this stmt already, just
+                    # mimic the current indent; else if initial line
+                    # has a start on an assignment stmt, indent to
+                    # beyond leftmost =; else to beyond first chunk of
+                    # non-whitespace on initial line
+                    if y.get_num_lines_in_stmt() > 1:
+                        text.insert("insert", indent)
+                    else:
+                        self.reindent_to(y.compute_backslash_indent())
+                else:
+                    assert 0, "bogus continuation type " + `c`
+                return "break"
+
+            # This line starts a brand new stmt; indent relative to
+            # indentation of initial line of closest preceding
+            # interesting stmt.
+            indent = y.get_base_indent_string()
+            text.insert("insert", indent)
+            if y.is_block_opener():
+                self.smart_indent_event(event)
+            elif indent and y.is_block_closer():
+                self.smart_backspace_event(event)
+            return "break"
+        finally:
+            text.see("insert")
+            text.undo_block_stop()
+
+    auto_indent = newline_and_indent_event
+
+    # Our editwin provides a is_char_in_string function that works
+    # with a Tk text index, but PyParse only knows about offsets into
+    # a string. This builds a function for PyParse that accepts an
+    # offset.
+
+    def _build_char_in_string_func(self, startindex):
+        def inner(offset, _startindex=startindex,
+                  _icis=self.editwin.is_char_in_string):
+            return _icis(_startindex + "+%dc" % offset)
+        return inner
+
+    def indent_region_event(self, event):
+        head, tail, chars, lines = self.get_region()
+        for pos in range(len(lines)):
+            line = lines[pos]
+            if line:
+                raw, effective = classifyws(line, self.tabwidth)
+                effective = effective + self.indentwidth
+                lines[pos] = self._make_blanks(effective) + line[raw:]
+        self.set_region(head, tail, chars, lines)
+        return "break"
+
+    def dedent_region_event(self, event):
+        head, tail, chars, lines = self.get_region()
+        for pos in range(len(lines)):
+            line = lines[pos]
+            if line:
+                raw, effective = classifyws(line, self.tabwidth)
+                effective = max(effective - self.indentwidth, 0)
+                lines[pos] = self._make_blanks(effective) + line[raw:]
+        self.set_region(head, tail, chars, lines)
+        return "break"
+
+    def comment_region_event(self, event):
+        head, tail, chars, lines = self.get_region()
+        for pos in range(len(lines) - 1):
+            line = lines[pos]
+            lines[pos] = '##' + line
+        self.set_region(head, tail, chars, lines)
+
+    def uncomment_region_event(self, event):
+        head, tail, chars, lines = self.get_region()
+        for pos in range(len(lines)):
+            line = lines[pos]
+            if not line:
+                continue
+            if line[:2] == '##':
+                line = line[2:]
+            elif line[:1] == '#':
+                line = line[1:]
+            lines[pos] = line
+        self.set_region(head, tail, chars, lines)
+
+    def tabify_region_event(self, event):
+        head, tail, chars, lines = self.get_region()
+        tabwidth = self._asktabwidth()
+        for pos in range(len(lines)):
+            line = lines[pos]
+            if line:
+                raw, effective = classifyws(line, tabwidth)
+                ntabs, nspaces = divmod(effective, tabwidth)
+                lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
+        self.set_region(head, tail, chars, lines)
+
+    def untabify_region_event(self, event):
+        head, tail, chars, lines = self.get_region()
+        tabwidth = self._asktabwidth()
+        for pos in range(len(lines)):
+            lines[pos] = lines[pos].expandtabs(tabwidth)
+        self.set_region(head, tail, chars, lines)
+
+    def toggle_tabs_event(self, event):
+        if self.editwin.askyesno(
+              "Toggle tabs",
+              "Turn tabs " + ("on", "off")[self.usetabs] + "?",
+              parent=self.text):
+            self.usetabs = not self.usetabs
+        return "break"
+
+    # XXX this isn't bound to anything -- see class tabwidth comments
+    def change_tabwidth_event(self, event):
+        new = self._asktabwidth()
+        if new != self.tabwidth:
+            self.tabwidth = new
+            self.set_indentation_params(0, guess=0)
+        return "break"
+
+    def change_indentwidth_event(self, event):
+        new = self.editwin.askinteger(
+                  "Indent width",
+                  "New indent width (1-16)",
+                  parent=self.text,
+                  initialvalue=self.indentwidth,
+                  minvalue=1,
+                  maxvalue=16)
+        if new and new != self.indentwidth:
+            self.indentwidth = new
+        return "break"
+
+    def get_region(self):
+        text = self.text
+        first, last = self.editwin.get_selection_indices()
+        if first and last:
+            head = text.index(first + " linestart")
+            tail = text.index(last + "-1c lineend +1c")
+        else:
+            head = text.index("insert linestart")
+            tail = text.index("insert lineend +1c")
+        chars = text.get(head, tail)
+        lines = chars.split("\n")
+        return head, tail, chars, lines
+
+    def set_region(self, head, tail, chars, lines):
+        text = self.text
+        newchars = "\n".join(lines)
+        if newchars == chars:
+            text.bell()
+            return
+        text.tag_remove("sel", "1.0", "end")
+        text.mark_set("insert", head)
+        text.undo_block_start()
+        text.delete(head, tail)
+        text.insert(head, newchars)
+        text.undo_block_stop()
+        text.tag_add("sel", head, "insert")
+
+    # Make string that displays as n leading blanks.
+
+    def _make_blanks(self, n):
+        if self.usetabs:
+            ntabs, nspaces = divmod(n, self.tabwidth)
+            return '\t' * ntabs + ' ' * nspaces
+        else:
+            return ' ' * n
+
+    # Delete from beginning of line to insert point, then reinsert
+    # column logical (meaning use tabs if appropriate) spaces.
+
+    def reindent_to(self, column):
+        text = self.text
+        text.undo_block_start()
+        if text.compare("insert linestart", "!=", "insert"):
+            text.delete("insert linestart", "insert")
+        if column:
+            text.insert("insert", self._make_blanks(column))
+        text.undo_block_stop()
+
+    def _asktabwidth(self):
+        return self.editwin.askinteger(
+            "Tab width",
+            "Spaces per tab?",
+            parent=self.text,
+            initialvalue=self.tabwidth,
+            minvalue=1,
+            maxvalue=16) or self.tabwidth
+
+    # Guess indentwidth from text content.
+    # Return guessed indentwidth.  This should not be believed unless
+    # it's in a reasonable range (e.g., it will be 0 if no indented
+    # blocks are found).
+
+    def guess_indent(self):
+        opener, indented = IndentSearcher(self.text, self.tabwidth).run()
+        if opener and indented:
+            raw, indentsmall = classifyws(opener, self.tabwidth)
+            raw, indentlarge = classifyws(indented, self.tabwidth)
+        else:
+            indentsmall = indentlarge = 0
+        return indentlarge - indentsmall
+
+# "line.col" -> line, as an int
+def index2line(index):
+    return int(float(index))
+
+# Look at the leading whitespace in s.
+# Return pair (# of leading ws characters,
+#              effective # of leading blanks after expanding
+#              tabs to width tabwidth)
+
+def classifyws(s, tabwidth):
+    raw = effective = 0
+    for ch in s:
+        if ch == ' ':
+            raw = raw + 1
+            effective = effective + 1
+        elif ch == '\t':
+            raw = raw + 1
+            effective = (effective // tabwidth + 1) * tabwidth
+        else:
+            break
+    return raw, effective
+
+import tokenize
+_tokenize = tokenize
+del tokenize
+
+class IndentSearcher:
+
+    # .run() chews over the Text widget, looking for a block opener
+    # and the stmt following it.  Returns a pair,
+    #     (line containing block opener, line containing stmt)
+    # Either or both may be None.
+
+    def __init__(self, text, tabwidth):
+        self.text = text
+        self.tabwidth = tabwidth
+        self.i = self.finished = 0
+        self.blkopenline = self.indentedline = None
+
+    def readline(self):
+        if self.finished:
+            return ""
+        i = self.i = self.i + 1
+        mark = `i` + ".0"
+        if self.text.compare(mark, ">=", "end"):
+            return ""
+        return self.text.get(mark, mark + " lineend+1c")
+
+    def tokeneater(self, type, token, start, end, line,
+                   INDENT=_tokenize.INDENT,
+                   NAME=_tokenize.NAME,
+                   OPENERS=('class', 'def', 'for', 'if', 'try', 'while')):
+        if self.finished:
+            pass
+        elif type == NAME and token in OPENERS:
+            self.blkopenline = line
+        elif type == INDENT and self.blkopenline:
+            self.indentedline = line
+            self.finished = 1
+
+    def run(self):
+        save_tabsize = _tokenize.tabsize
+        _tokenize.tabsize = self.tabwidth
+        try:
+            try:
+                _tokenize.tokenize(self.readline, self.tokeneater)
+            except _tokenize.TokenError:
+                # since we cut off the tokenizer early, we can trigger
+                # spurious errors
+                pass
+        finally:
+            _tokenize.tabsize = save_tabsize
+        return self.blkopenline, self.indentedline
diff --git a/Tools/idle/FrameViewer.py b/Tools/idle/FrameViewer.py
new file mode 100644
index 0000000..2ce0935
--- /dev/null
+++ b/Tools/idle/FrameViewer.py
@@ -0,0 +1,38 @@
+from repr import Repr
+from Tkinter import *
+
+class FrameViewer:
+
+    def __init__(self, root, frame):
+        self.root = root
+        self.frame = frame
+        self.top = Toplevel(self.root)
+        self.repr = Repr()
+        self.repr.maxstring = 60
+        self.load_variables()
+
+    def load_variables(self):
+        row = 0
+        if self.frame.f_locals is not self.frame.f_globals:
+            l = Label(self.top, text="Local Variables",
+                      borderwidth=2, relief="raised")
+            l.grid(row=row, column=0, columnspan=2, sticky="ew")
+            row = self.load_names(self.frame.f_locals, row+1)
+        l = Label(self.top, text="Global Variables",
+                  borderwidth=2, relief="raised")
+        l.grid(row=row, column=0, columnspan=2, sticky="ew")
+        row = self.load_names(self.frame.f_globals, row+1)
+
+    def load_names(self, dict, row):
+        names = dict.keys()
+        names.sort()
+        for name in names:
+            value = dict[name]
+            svalue = self.repr.repr(value)
+            l = Label(self.top, text=name)
+            l.grid(row=row, column=0, sticky="w")
+            l = Entry(self.top, width=60, borderwidth=0)
+            l.insert(0, svalue)
+            l.grid(row=row, column=1, sticky="w")
+            row = row+1
+        return row
diff --git a/Tools/idle/IdleConf.py b/Tools/idle/IdleConf.py
new file mode 100644
index 0000000..8eaa8e0
--- /dev/null
+++ b/Tools/idle/IdleConf.py
@@ -0,0 +1,113 @@
+"""Provides access to configuration information"""
+
+import os
+import sys
+from ConfigParser import ConfigParser, NoOptionError, NoSectionError
+
+class IdleConfParser(ConfigParser):
+
+    # these conf sections do not define extensions!
+    builtin_sections = {}
+    for section in ('EditorWindow', 'Colors'):
+        builtin_sections[section] = section
+
+    def getcolor(self, sec, name):
+        """Return a dictionary with foreground and background colors
+
+        The return value is appropriate for passing to Tkinter in, e.g.,
+        a tag_config call.
+        """
+        fore = self.getdef(sec, name + "-foreground")
+        back = self.getdef(sec, name + "-background")
+        return {"foreground": fore,
+                "background": back}
+
+    def getdef(self, sec, options, raw=0, vars=None, default=None):
+        """Get an option value for given section or return default"""
+        try:
+            return self.get(sec, options, raw, vars)
+        except (NoSectionError, NoOptionError):
+            return default
+
+    def getsection(self, section):
+        """Return a SectionConfigParser object"""
+        return SectionConfigParser(section, self)
+
+    def getextensions(self):
+        exts = []
+        for sec in self.sections():
+            if self.builtin_sections.has_key(sec):
+                continue
+            # enable is a bool, but it may not be defined
+            if self.getdef(sec, 'enable') != '0':
+                exts.append(sec)
+        return exts
+
+    def reload(self):
+        global idleconf
+        idleconf = IdleConfParser()
+        load(_dir) # _dir is a global holding the last directory loaded
+
+class SectionConfigParser:
+    """A ConfigParser object specialized for one section
+
+    This class has all the get methods that a regular ConfigParser does,
+    but without requiring a section argument.
+    """
+    def __init__(self, section, config):
+        self.section = section
+        self.config = config
+
+    def options(self):
+        return self.config.options(self.section)
+
+    def get(self, options, raw=0, vars=None):
+        return self.config.get(self.section, options, raw, vars)
+
+    def getdef(self, options, raw=0, vars=None, default=None):
+        return self.config.getdef(self.section, options, raw, vars, default)
+
+    def getint(self, option):
+        return self.config.getint(self.section, option)
+
+    def getfloat(self, option):
+        return self.config.getint(self.section, option)
+
+    def getboolean(self, option):
+        return self.config.getint(self.section, option)
+
+    def getcolor(self, option):
+        return self.config.getcolor(self.section, option)
+
+def load(dir):
+    """Load IDLE configuration files based on IDLE install in dir
+
+    Attempts to load two config files:
+    dir/config.txt
+    dir/config-[win/mac/unix].txt
+    dir/config-%(sys.platform)s.txt
+    ~/.idle
+    """
+    global _dir
+    _dir = dir
+
+    if sys.platform[:3] == 'win':
+        genplatfile = os.path.join(dir, "config-win.txt")
+    # XXX don't know what the platform string is on a Mac
+    elif sys.platform[:3] == 'mac':
+        genplatfile = os.path.join(dir, "config-mac.txt")
+    else:
+        genplatfile = os.path.join(dir, "config-unix.txt")
+
+    platfile = os.path.join(dir, "config-%s.txt" % sys.platform)
+
+    try:
+        homedir = os.environ['HOME']
+    except KeyError:
+        homedir = os.getcwd()
+
+    idleconf.read((os.path.join(dir, "config.txt"), genplatfile, platfile,
+                   os.path.join(homedir, ".idle")))
+
+idleconf = IdleConfParser()
+load(os.path.dirname(__file__))
diff --git a/Tools/idle/MultiScrolledLists.py b/Tools/idle/MultiScrolledLists.py
new file mode 100644
index 0000000..6398b86
--- /dev/null
+++ b/Tools/idle/MultiScrolledLists.py
@@ -0,0 +1,137 @@
+# One or more ScrolledLists with HSeparators between them.
+# There is a hierarchical relationship between them:
+# the right list displays the substructure of the selected item
+# in the left list.
+
+from Tkinter import *
+from WindowList import ListedToplevel
+from Separator import HSeparator
+from ScrolledList import ScrolledList
+
+class MultiScrolledLists:
+
+    def __init__(self, root, nlists=2):
+        assert nlists >= 1
+        self.root = root
+        self.nlists = nlists
+        self.path = []
+        # create top
+        self.top = top = ListedToplevel(root)
+        top.protocol("WM_DELETE_WINDOW", self.close)
+        top.bind("<Escape>", self.close)
+        self.settitle()
+        # create frames and separators in between
+        self.frames = []
+        self.separators = []
+        last = top
+        for i in range(nlists-1):
+            sepa = HSeparator(last)
+            self.separators.append(sepa)
+            frame, last = sepa.parts()
+            self.frames.append(frame)
+        self.frames.append(last)
+        # create labels and lists
+        self.labels = []
+        self.lists = []
+        for i in range(nlists):
+            frame = self.frames[i]
+            label = Label(frame, text=self.subtitle(i),
+                relief="groove", borderwidth=2)
+            label.pack(fill="x")
+            self.labels.append(label)
+            list = ScrolledList(frame, width=self.width(i),
+                height=self.height(i))
+            self.lists.append(list)
+            list.on_select = \
+                lambda index, i=i, self=self: self.on_select(index, i)
+            list.on_double = \
+                lambda index, i=i, self=self: self.on_double(index, i)
+        # fill leftmost list (rest get filled on demand)
+        self.fill(0)
+        # XXX one after_idle isn't enough; two are...
+        top.after_idle(self.call_pack_propagate_1)
+
+    def call_pack_propagate_1(self):
+        self.top.after_idle(self.call_pack_propagate)
+
+    def call_pack_propagate(self):
+        for frame in self.frames:
+            frame.pack_propagate(0)
+
+    def close(self, event=None):
+        self.top.destroy()
+
+    def settitle(self):
+        short = self.shorttitle()
+        long = self.longtitle()
+        if short and long:
+            title = short + " - " + long
+        elif short:
+            title = short
+        elif long:
+            title = long
+        else:
+            title = "Untitled"
+        icon = short or long or title
+        self.top.wm_title(title)
+        self.top.wm_iconname(icon)
+
+    def longtitle(self):
+        # override this
+        return "Multi Scrolled Lists"
+
+    def shorttitle(self):
+        # override this
+        return None
+
+    def width(self, i):
+        # override this
+        return 20
+
+    def height(self, i):
+        # override this
+        return 10
+
+    def subtitle(self, i):
+        # override this
+        return "Column %d" % i
+
+    def fill(self, i):
+        for k in range(i, self.nlists):
+            self.lists[k].clear()
+            self.labels[k].configure(text=self.subtitle(k))
+        list = self.lists[i]
+        l = self.items(i)
+        for s in l:
+            list.append(s)
+
+    def on_select(self, index, i):
+        item = self.lists[i].get(index)
+        del self.path[i:]
+        self.path.append(item)
+        if i+1 < self.nlists:
+            self.fill(i+1)
+
+    def items(self, i):
+        # override this
+        l = []
+        for k in range(10):
+            s = str(k)
+            if i > 0:
+                s = self.path[i-1] + "." + s
+            l.append(s)
+        return l
+
+    def on_double(self, index, i):
+        pass
+
+
+def main():
+    root = Tk()
+    quit = Button(root, text="Exit", command=root.destroy)
+    quit.pack()
+    MultiScrolledLists(root, 4)
+    root.mainloop()
+
+if __name__ == "__main__":
+    main()
diff --git a/Tools/idle/OldStackViewer.py b/Tools/idle/OldStackViewer.py
new file mode 100644
index 0000000..4f295e8
--- /dev/null
+++ b/Tools/idle/OldStackViewer.py
@@ -0,0 +1,275 @@
+import sys
+import os
+from Tkinter import *
+import linecache
+from repr import Repr
+from WindowList import ListedToplevel
+
+from ScrolledList import ScrolledList
+
+
+class StackBrowser:
+
+    def __init__(self, root, flist, stack=None):
+        self.top = top = ListedToplevel(root)
+        top.protocol("WM_DELETE_WINDOW", self.close)
+        top.bind("<Key-Escape>", self.close)
+        top.wm_title("Stack viewer")
+        top.wm_iconname("Stack")
+        # Create help label
+        self.helplabel = Label(top,
+            text="Click once to view variables; twice for source",
+            borderwidth=2, relief="groove")
+        self.helplabel.pack(fill="x")
+        #
+        self.sv = StackViewer(top, flist, self)
+        if stack is None:
+            stack = get_stack()
+        self.sv.load_stack(stack)
+
+    def close(self, event=None):
+        self.top.destroy()
+
+    localsframe = None
+    localsviewer = None
+    localsdict = None
+    globalsframe = None
+    globalsviewer = None
+    globalsdict = None
+    curframe = None
+
+    def show_frame(self, (frame, lineno)):
+        if frame is self.curframe:
+            return
+        self.curframe = None
+        if frame.f_globals is not self.globalsdict:
+            self.show_globals(frame)
+        self.show_locals(frame)
+        self.curframe = frame
+
+    def show_globals(self, frame):
+        title = "Global Variables"
+        if frame.f_globals.has_key("__name__"):
+            try:
+                name = str(frame.f_globals["__name__"]) + ""
+            except:
+                name = ""
+            if name:
+                title = title + " in module " + name
+        self.globalsdict = None
+        if self.globalsviewer:
+            self.globalsviewer.close()
+        self.globalsviewer = None
+        if not self.globalsframe:
+            self.globalsframe = Frame(self.top)
+        self.globalsdict = frame.f_globals
+        self.globalsviewer = NamespaceViewer(
+            self.globalsframe,
+            title,
+            self.globalsdict)
+        self.globalsframe.pack(fill="both", side="bottom")
+
+    def show_locals(self, frame):
+        self.localsdict = None
+        if self.localsviewer:
+            self.localsviewer.close()
+        self.localsviewer = None
+        if frame.f_locals is not frame.f_globals:
+            title = "Local Variables"
+            code = frame.f_code
+            funcname = code.co_name
+            if funcname not in ("?", "", None):
+                title = title + " in " + funcname
+            if not self.localsframe:
+                self.localsframe = Frame(self.top)
+            self.localsdict = frame.f_locals
+            self.localsviewer = NamespaceViewer(
+                self.localsframe,
+                title,
+                self.localsdict)
+            self.localsframe.pack(fill="both", side="top")
+        else:
+            if self.localsframe:
+                self.localsframe.forget()
+
+
+class StackViewer(ScrolledList):
+
+    def __init__(self, master, flist, browser):
+        ScrolledList.__init__(self, master, width=80)
+        self.flist = flist
+        self.browser = browser
+        self.stack = []
+
+    def load_stack(self, stack, index=None):
+        self.stack = stack
+        self.clear()
+##        if len(stack) > 10:
+##            l["height"] = 10
+##            self.topframe.pack(expand=1)
+##        else:
+##            l["height"] = len(stack)
+##            self.topframe.pack(expand=0)
+        for i in range(len(stack)):
+            frame, lineno = stack[i]
+            try:
+                modname = frame.f_globals["__name__"]
+            except:
+                modname = "?"
+            code = frame.f_code
+            filename = code.co_filename
+            funcname = code.co_name
+            sourceline = linecache.getline(filename, lineno)
+            sourceline = sourceline.strip()
+            if funcname in ("?", "", None):
+                item = "%s, line %d: %s" % (modname, lineno, sourceline)
+            else:
+                item = "%s.%s(), line %d: %s" % (modname, funcname,
+                                                 lineno, sourceline)
+            if i == index:
+                item = "> " + item
+            self.append(item)
+        if index is not None:
+            self.select(index)
+
+    def popup_event(self, event):
+        if self.stack:
+            return ScrolledList.popup_event(self, event)
+
+    def fill_menu(self):
+        menu = self.menu
+        menu.add_command(label="Go to source line",
+                         command=self.goto_source_line)
+        menu.add_command(label="Show stack frame",
+                         command=self.show_stack_frame)
+
+    def on_select(self, index):
+        if 0 <= index < len(self.stack):
+            self.browser.show_frame(self.stack[index])
+
+    def on_double(self, index):
+        self.show_source(index)
+
+    def goto_source_line(self):
+        index = self.listbox.index("active")
+        self.show_source(index)
+
+    def show_stack_frame(self):
+        index = self.listbox.index("active")
+        if 0 <= index < len(self.stack):
+            self.browser.show_frame(self.stack[index])
+
+    def show_source(self, index):
+        if not (0 <= index < len(self.stack)):
+            return
+        frame, lineno = self.stack[index]
+        code = frame.f_code
+        filename = code.co_filename
+        if os.path.isfile(filename):
+            edit = self.flist.open(filename)
+            if edit:
+                edit.gotoline(lineno)
+
+
+def get_stack(t=None, f=None):
+    if t is None:
+        t = sys.last_traceback
+    stack = []
+    if t and t.tb_frame is f:
+        t = t.tb_next
+    while f is not None:
+        stack.append((f, f.f_lineno))
+        if f is self.botframe:
+            break
+        f = f.f_back
+    stack.reverse()
+    while t is not None:
+        stack.append((t.tb_frame, t.tb_lineno))
+        t = t.tb_next
+    return stack
+
+
+def getexception(type=None, value=None):
+    if type is None:
+        type = sys.last_type
+        value = sys.last_value
+    if hasattr(type, "__name__"):
+        type = type.__name__
+    s = str(type)
+    if value is not None:
+        s = s + ": " + str(value)
+    return s
+
+
+class NamespaceViewer:
+
+    def __init__(self, master, title, dict=None):
+        width = 0
+        height = 40
+        if dict:
+            height = 20*len(dict) # XXX 20 == observed height of Entry widget
+        self.master = master
+        self.title = title
+        self.repr = Repr()
+        self.repr.maxstring = 60
+        self.repr.maxother = 60
+        self.frame = frame = Frame(master)
+        self.frame.pack(expand=1, fill="both")
+        self.label = Label(frame, text=title, borderwidth=2, relief="groove")
+        self.label.pack(fill="x")
+        self.vbar = vbar = Scrollbar(frame, name="vbar")
+        vbar.pack(side="right", fill="y")
+        self.canvas = canvas = Canvas(frame,
+                                      height=min(300, max(40, height)),
+                                      scrollregion=(0, 0, width, height))
+        canvas.pack(side="left", fill="both", expand=1)
+        vbar["command"] = canvas.yview
+        canvas["yscrollcommand"] = vbar.set
+        self.subframe = subframe = Frame(canvas)
+        self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
+        self.load_dict(dict)
+
+    dict = -1
+
+    def load_dict(self, dict, force=0):
+        if dict is self.dict and not force:
+            return
+        subframe = self.subframe
+        frame = self.frame
+        for c in subframe.children.values():
+            c.destroy()
+        self.dict = None
+        if not dict:
+            l = Label(subframe, text="None")
+            l.grid(row=0, column=0)
+        else:
+            names = dict.keys()
+            names.sort()
+            row = 0
+            for name in names:
+                value = dict[name]
+                svalue = self.repr.repr(value) # repr(value)
+                l = Label(subframe, text=name)
+                l.grid(row=row, column=0, sticky="nw")
+    ##            l = Label(subframe, text=svalue, justify="l", wraplength=300)
+                l = Entry(subframe, width=0, borderwidth=0)
+                l.insert(0, svalue)
+    ##            l["state"] = "disabled"
+                l.grid(row=row, column=1, sticky="nw")
+                row = row+1
+        self.dict = dict
+        # XXX Could we use a <Configure> callback for the following?
+        subframe.update_idletasks() # Alas!
+        width = subframe.winfo_reqwidth()
+        height = subframe.winfo_reqheight()
+        canvas = self.canvas
+        self.canvas["scrollregion"] = (0, 0, width, height)
+        if height > 300:
+            canvas["height"] = 300
+            frame.pack(expand=1)
+        else:
+            canvas["height"] = height
+            frame.pack(expand=0)
+
+    def close(self):
+        self.frame.destroy()
diff --git a/Tools/idle/RemoteInterp.py b/Tools/idle/RemoteInterp.py
new file mode 100644
index 0000000..e6f7671
--- /dev/null
+++ b/Tools/idle/RemoteInterp.py
@@ -0,0 +1,341 @@
+import select
+import socket
+import struct
+import sys
+import types
+
+VERBOSE = None
+
+class SocketProtocol:
+    """A simple protocol for sending strings across a socket"""
+    BUF_SIZE = 8192
+
+    def __init__(self, sock):
+        self.sock = sock
+        self._buffer = ''
+        self._closed = 0
+
+    def close(self):
+        self._closed = 1
+        self.sock.close()
+
+    def send(self, buf):
+        """Encode buf and write it on the socket"""
+        if VERBOSE:
+            VERBOSE.write('send %d:%s\n' % (len(buf), `buf`))
+        self.sock.send('%d:%s' % (len(buf), buf))
+
+    def receive(self, timeout=0):
+        """Get next complete string from socket or return None
+
+        Raise EOFError on EOF
+        """
+        buf = self._read_from_buffer()
+        if buf is not None:
+            return buf
+        recvbuf = self._read_from_socket(timeout)
+        if recvbuf is None:
+            return None
+        if recvbuf == '' and self._buffer == '':
+            raise EOFError
+        if VERBOSE:
+            VERBOSE.write('recv %s\n' % `recvbuf`)
+        self._buffer = self._buffer + recvbuf
+        r = self._read_from_buffer()
+        return r
+
+    def _read_from_socket(self, timeout):
+        """Does not block"""
+        if self._closed:
+            return ''
+        if timeout is not None:
+            r, w, x = select.select([self.sock], [], [], timeout)
+        if timeout is None or r:
+            return self.sock.recv(self.BUF_SIZE)
+        else:
+            return None
+
+    def _read_from_buffer(self):
+        buf = self._buffer
+        i = buf.find(':')
+        if i == -1:
+            return None
+        buflen = int(buf[:i])
+        enclen = i + 1 + buflen
+        if len(buf) >= enclen:
+            s = buf[i+1:enclen]
+            self._buffer = buf[enclen:]
+            return s
+        else:
+            self._buffer = buf
+        return None
+
+# helpers for registerHandler method below
+
+def get_methods(obj):
+    methods = []
+    for name in dir(obj):
+        attr = getattr(obj, name)
+        if callable(attr):
+            methods.append(name)
+    if type(obj) == types.InstanceType:
+        methods = methods + get_methods(obj.__class__)
+    if type(obj) == types.ClassType:
+        for super in obj.__bases__:
+            methods = methods + get_methods(super)
+    return methods
+
+class CommandProtocol:
+    def __init__(self, sockp):
+        self.sockp = sockp
+        self.seqno = 0
+        self.handlers = {}
+
+    def close(self):
+        self.sockp.close()
+        self.handlers.clear()
+
+    def registerHandler(self, handler):
+        """A Handler is an object with handle_XXX methods"""
+        for methname in get_methods(handler):
+            if methname[:7] == "handle_":
+                name = methname[7:]
+                self.handlers[name] = getattr(handler, methname)
+
+    def send(self, cmd, arg='', seqno=None):
+        if arg:
+            msg = "%s %s" % (cmd, arg)
+        else:
+            msg = cmd
+        if seqno is None:
+            seqno = self.get_seqno()
+        msgbuf = self.encode_seqno(seqno) + msg
+        self.sockp.send(msgbuf)
+        if cmd == "reply":
+            return
+        reply = self.sockp.receive(timeout=None)
+        r_cmd, r_arg, r_seqno = self._decode_msg(reply)
+        assert r_seqno == seqno and r_cmd == "reply", "bad reply"
+        return r_arg
+
+    def _decode_msg(self, msg):
+        seqno = self.decode_seqno(msg[:self.SEQNO_ENC_LEN])
+        msg = msg[self.SEQNO_ENC_LEN:]
+        parts = msg.split(" ", 2)
+        if len(parts) == 1:
+            cmd = msg
+            arg = ''
+        else:
+            cmd = parts[0]
+            arg = parts[1]
+        return cmd, arg, seqno
+
+    def dispatch(self):
+        msg = self.sockp.receive()
+        if msg is None:
+            return
+        cmd, arg, seqno = self._decode_msg(msg)
+        self._current_reply = seqno
+        h = self.handlers.get(cmd, self.default_handler)
+        try:
+            r = h(arg)
+        except TypeError, msg:
+            raise TypeError, "handle_%s: %s" % (cmd, msg)
+        if self._current_reply is None:
+            if r is not None:
+                sys.stderr.write("ignoring %s return value type %s\n" % \
+                                 (cmd, type(r).__name__))
+            return
+        if r is None:
+            r = ''
+        if type(r) != types.StringType:
+            raise ValueError, "invalid return type for %s" % cmd
+        self.send("reply", r, seqno=seqno)
+
+    def reply(self, arg=''):
+        """Send a reply immediately
+
+        otherwise reply will be sent when handler returns
+        """
+        self.send("reply", arg, self._current_reply)
+        self._current_reply = None
+
+    def default_handler(self, arg):
+        sys.stderr.write("WARNING: unhandled message %s\n" % arg)
+        return ''
+
+    SEQNO_ENC_LEN = 4
+
+    def get_seqno(self):
+        seqno = self.seqno
+        self.seqno = seqno + 1
+        return seqno
+
+    def encode_seqno(self, seqno):
+        return struct.pack("I", seqno)
+
+    def decode_seqno(self, buf):
+        return struct.unpack("I", buf)[0]
+
+
+class StdioRedirector:
+    """Redirect sys.std{in,out,err} to a set of file-like objects"""
+
+    def __init__(self, stdin, stdout, stderr):
+        self.stdin = stdin
+        self.stdout = stdout
+        self.stderr = stderr
+
+    def redirect(self):
+        self.save()
+        sys.stdin = self.stdin
+        sys.stdout = self.stdout
+        sys.stderr = self.stderr
+
+    def save(self):
+        self._stdin = sys.stdin
+        self._stdout = sys.stdout
+        self._stderr = sys.stderr
+
+    def restore(self):
+        sys.stdin = self._stdin
+        sys.stdout = self._stdout
+        sys.stderr = self._stderr
+
+class IOWrapper:
+    """Send output from a file-like object across a SocketProtocol
+
+    XXX Should this be more tightly integrated with the CommandProtocol?
+    """
+
+    def __init__(self, name, cmdp):
+        self.name = name
+        self.cmdp = cmdp
+        self.buffer = []
+
+class InputWrapper(IOWrapper):
+    def write(self, buf):
+        # XXX what should this do on Windows?
+        raise IOError, (9, '[Errno 9] Bad file descriptor')
+
+    def read(self, arg=None):
+        if arg is not None:
+            if arg <= 0:
+                return ''
+        else:
+            arg = 0
+        return self.cmdp.send(self.name, "read,%s" % arg)
+
+    def readline(self):
+        return self.cmdp.send(self.name, "readline")
+
+class OutputWrapper(IOWrapper):
+    def write(self, buf):
+        self.cmdp.send(self.name, buf)
+
+    def read(self, arg=None):
+        return ''
+
+class RemoteInterp:
+    def __init__(self, sock):
+        self._sock = SocketProtocol(sock)
+        self._cmd = CommandProtocol(self._sock)
+        self._cmd.registerHandler(self)
+
+    def run(self):
+        try:
+            while 1:
+                self._cmd.dispatch()
+        except EOFError:
+            pass
+
+    def handle_execfile(self, arg):
+        self._cmd.reply()
+        io = StdioRedirector(InputWrapper("stdin", self._cmd),
+                             OutputWrapper("stdout", self._cmd),
+                             OutputWrapper("stderr", self._cmd))
+        io.redirect()
+        execfile(arg, {'__name__':'__main__'})
+        io.restore()
+        self._cmd.send("terminated")
+
+    def handle_quit(self, arg):
+        self._cmd.reply()
+        self._cmd.close()
+
+def startRemoteInterp(id):
+    import os
+    # UNIX domain sockets are simpler for starters
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    sock.bind("/var/tmp/ri.%s" % id)
+    try:
+        sock.listen(1)
+        cli, addr = sock.accept()
+        rinterp = RemoteInterp(cli)
+        rinterp.run()
+    finally:
+        os.unlink("/var/tmp/ri.%s" % id)
+
+class RIClient:
+    """Client of the remote interpreter"""
+    def __init__(self, sock):
+        self._sock = SocketProtocol(sock)
+        self._cmd = CommandProtocol(self._sock)
+        self._cmd.registerHandler(self)
+
+    def execfile(self, file):
+        self._cmd.send("execfile", file)
+
+    def run(self):
+        try:
+            while 1:
+                self._cmd.dispatch()
+        except EOFError:
+            pass
+
+    def handle_stdout(self, buf):
+        sys.stdout.write(buf)
+##        sys.stdout.flush()
+
+    def handle_stderr(self, buf):
+        sys.stderr.write(buf)
+
+    def handle_stdin(self, arg):
+        if arg == "readline":
+            return sys.stdin.readline()
+        i = arg.find(",") + 1
+        bytes = int(arg[i:])
+        if bytes == 0:
+            return sys.stdin.read()
+        else:
+            return sys.stdin.read(bytes)
+
+    def handle_terminated(self, arg):
+        self._cmd.reply()
+        self._cmd.send("quit")
+        self._cmd.close()
+
+def riExec(id, file):
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    sock.connect("/var/tmp/ri.%s" % id)
+    cli = RIClient(sock)
+    cli.execfile(file)
+    cli.run()
+
+if __name__ == "__main__":
+    import getopt
+
+    SERVER = 1
+    opts, args = getopt.getopt(sys.argv[1:], 'cv')
+    for o, v in opts:
+        if o == '-c':
+            SERVER = 0
+        elif o == '-v':
+            VERBOSE = sys.stderr
+    id = args[0]
+
+    if SERVER:
+        startRemoteInterp(id)
+    else:
+        file = args[1]
+        riExec(id, file)
diff --git a/Tools/idle/SearchBinding.py b/Tools/idle/SearchBinding.py
new file mode 100644
index 0000000..5943e3b
--- /dev/null
+++ b/Tools/idle/SearchBinding.py
@@ -0,0 +1,97 @@
+import tkSimpleDialog
+
+###$ event <<find>>
+###$ win <Control-f>
+###$ unix <Control-u><Control-u><Control-s>
+
+###$ event <<find-again>>
+###$ win <Control-g>
+###$ win <F3>
+###$ unix <Control-u><Control-s>
+
+###$ event <<find-selection>>
+###$ win <Control-F3>
+###$ unix <Control-s>
+
+###$ event <<find-in-files>>
+###$ win <Alt-F3>
+
+###$ event <<replace>>
+###$ win <Control-h>
+
+###$ event <<goto-line>>
+###$ win <Alt-g>
+###$ unix <Alt-g>
+
+class SearchBinding:
+
+    windows_keydefs = {
+        '<<find-again>>': ['<Control-g>', '<F3>'],
+        '<<find-in-files>>': ['<Alt-F3>'],
+        '<<find-selection>>': ['<Control-F3>'],
+        '<<find>>': ['<Control-f>'],
+        '<<replace>>': ['<Control-h>'],
+        '<<goto-line>>': ['<Alt-g>'],
+    }
+
+    unix_keydefs = {
+        '<<find-again>>': ['<Control-u><Control-s>'],
+        '<<find-in-files>>': ['<Alt-s>', '<Meta-s>'],
+        '<<find-selection>>': ['<Control-s>'],
+        '<<find>>': ['<Control-u><Control-u><Control-s>'],
+        '<<replace>>': ['<Control-r>'],
+        '<<goto-line>>': ['<Alt-g>', '<Meta-g>'],
+    }
+
+    menudefs = [
+        ('edit', [
+            None,
+            ('_Find...', '<<find>>'),
+            ('Find a_gain', '<<find-again>>'),
+            ('Find _selection', '<<find-selection>>'),
+            ('Find in Files...', '<<find-in-files>>'),
+            ('R_eplace...', '<<replace>>'),
+            ('Go to _line', '<<goto-line>>'),
+         ]),
+    ]
+
+    def __init__(self, editwin):
+        self.editwin = editwin
+
+    def find_event(self, event):
+        import SearchDialog
+        SearchDialog.find(self.editwin.text)
+        return "break"
+
+    def find_again_event(self, event):
+        import SearchDialog
+        SearchDialog.find_again(self.editwin.text)
+        return "break"
+
+    def find_selection_event(self, event):
+        import SearchDialog
+        SearchDialog.find_selection(self.editwin.text)
+        return "break"
+
+    def find_in_files_event(self, event):
+        import GrepDialog
+        GrepDialog.grep(self.editwin.text, self.editwin.io, self.editwin.flist)
+        return "break"
+
+    def replace_event(self, event):
+        import ReplaceDialog
+        ReplaceDialog.replace(self.editwin.text)
+        return "break"
+
+    def goto_line_event(self, event):
+        text = self.editwin.text
+        lineno = tkSimpleDialog.askinteger("Goto",
+                                           "Go to line number:",
+                                           parent=text)
+        if lineno is None:
+            return "break"
+        if lineno <= 0:
+            text.bell()
+            return "break"
+        text.mark_set("insert", "%d.0" % lineno)
+        text.see("insert")
diff --git a/Tools/idle/Separator.py b/Tools/idle/Separator.py
new file mode 100644
index 0000000..7145559
--- /dev/null
+++ b/Tools/idle/Separator.py
@@ -0,0 +1,92 @@
+from Tkinter import *
+
+class Separator:
+
+    def __init__(self, master, orient, min=10, thickness=5, bg=None):
+        self.min = max(1, min)
+        self.thickness = max(1, thickness)
+        if orient in ("h", "horizontal"):
+            self.side = "left"
+            self.dim = "width"
+            self.dir = "x"
+            self.cursor = "sb_h_double_arrow"
+        elif orient in ("v", "vertical"):
+            self.side = "top"
+            self.dim = "height"
+            self.dir = "y"
+            self.cursor = "sb_v_double_arrow"
+        else:
+            raise ValueError, "Separator: orient should be h or v"
+        self.winfo_dim = "winfo_" + self.dim
+        self.master = master = Frame(master)
+        master.pack(expand=1, fill="both")
+        self.f1 = Frame(master)
+        self.f1.pack(expand=1, fill="both", side=self.side)
+        self.div = Frame(master, cursor=self.cursor)
+        self.div[self.dim] = self.thickness
+        self.div.pack(fill="both", side=self.side)
+        self.f2 = Frame(master)
+        self.f2.pack(expand=1, fill="both", side=self.side)
+        self.div.bind("<ButtonPress-1>", self.divider_press)
+        if bg:
+            ##self.f1["bg"] = bg
+            ##self.f2["bg"] = bg
+            self.div["bg"] = bg
+
+    def parts(self):
+        return self.f1, self.f2
+
+    def divider_press(self, event):
+        self.press_event = event
+        self.f1.pack_propagate(0)
+        self.f2.pack_propagate(0)
+        for f in self.f1, self.f2:
+            for dim in "width", "height":
+                f[dim] = getattr(f, "winfo_"+dim)()
+        self.div.bind("<Motion>", self.div_motion)
+        self.div.bind("<ButtonRelease-1>", self.div_release)
+        self.div.grab_set()
+
+    def div_motion(self, event):
+        delta = getattr(event, self.dir) - getattr(self.press_event, self.dir)
+        if delta:
+            dim1 = getattr(self.f1, self.winfo_dim)()
+            dim2 = getattr(self.f2, self.winfo_dim)()
+            delta = max(delta, self.min-dim1)
+            delta = min(delta, dim2-self.min)
+            dim1 = dim1 + delta
+            dim2 = dim2 - delta
+            self.f1[self.dim] = dim1
+            self.f2[self.dim] = dim2
+
+    def div_release(self, event):
+        self.div_motion(event)
+        self.div.unbind("<Motion>")
+        self.div.grab_release()
+
+class VSeparator(Separator):
+
+    def __init__(self, master, min=10, thickness=5, bg=None):
+        Separator.__init__(self, master, "v", min, thickness, bg)
+
+class HSeparator(Separator):
+
+    def __init__(self, master, min=10, thickness=5, bg=None):
+        Separator.__init__(self, master, "h", min, thickness, bg)
+
+def main():
+    root = Tk()
+    tlist = []
+    outer = HSeparator(root, bg="red")
+    for part in outer.parts():
+        inner = VSeparator(part, bg="blue")
+        for f in inner.parts():
+            t = Text(f, width=40, height=10, borderwidth=0)
+            t.pack(fill="both", expand=1)
+            tlist.append(t)
+    tlist[0].insert("1.0", "Make your own Mondrian!")
+    tlist[1].insert("1.0", "Move the colored dividers...")
+    root.mainloop()
+
+if __name__ == '__main__':
+    main()
diff --git a/Tools/idle/config-mac.txt b/Tools/idle/config-mac.txt
new file mode 100644
index 0000000..ee36e13
--- /dev/null
+++ b/Tools/idle/config-mac.txt
@@ -0,0 +1,3 @@
+[EditorWindow]
+font-name= monaco
+font-size= 9
diff --git a/Tools/idle/config-unix.txt b/Tools/idle/config-unix.txt
new file mode 100644
index 0000000..782965f
--- /dev/null
+++ b/Tools/idle/config-unix.txt
@@ -0,0 +1,4 @@
+[EditorWindow]
+font-name= courier
+font-size= 10
+print-command=lpr %s
diff --git a/Tools/idle/config-win.txt b/Tools/idle/config-win.txt
new file mode 100644
index 0000000..aeb6ab9
--- /dev/null
+++ b/Tools/idle/config-win.txt
@@ -0,0 +1,4 @@
+[EditorWindow]
+font-name: courier new
+font-size: 10
+print-command=start /min notepad /p %s
diff --git a/Tools/idle/config.txt b/Tools/idle/config.txt
new file mode 100644
index 0000000..6f98a3e
--- /dev/null
+++ b/Tools/idle/config.txt
@@ -0,0 +1,64 @@
+# IDLE reads several config files to determine user preferences.  This 
+# file is the default config file.  When IDLE starts, it will look in
+# the following four files in order:
+#     config.txt                      the default config file
+#     config-[win/unix/mac].txt       the generic platform config file
+#     config-[sys.platform].txt       the specific platform config file
+#     ~/.idle                         the user config file
+# XXX what about Windows?
+#
+# The last definition of each option is used.  For example, you can
+# override the default window size (80x24) by defining width and
+# height options in the EditorWindow section of your ~/.idle file
+#
+# IDLE extensions can be enabled and disabled by adding them to one of
+# the config files.  To enable an extension, create a section with the
+# same name as the extension, e.g. the [ParenMatch] section below.  To
+# disable an extension, either remove the section or add the 'enable'
+# option with the value 0.  
+
+[EditorWindow]
+width= 80
+height= 24
+# fonts defined in config-[win/unix].txt
+
+[Colors]
+normal-foreground= black
+normal-background= white
+# These color types are not explicitly defined= sync, todo, stdin
+keyword-foreground= #ff7700
+comment-foreground= #dd0000
+string-foreground= #00aa00
+definition-foreground= #0000ff
+hilite-foreground= #000068
+hilite-background= #006868
+break-foreground= #ff7777
+hit-foreground= #ffffff
+hit-background= #000000
+stdout-foreground= blue
+stderr-foreground= red
+console-foreground= #770000
+error-background= #ff7777
+cursor-background= black
+
+[SearchBinding]
+
+[AutoIndent]
+
+[AutoExpand]
+
+[FormatParagraph]
+
+[ZoomHeight]
+
+[ScriptBinding]
+
+[CallTips]
+
+[ParenMatch]
+enable= 0
+style= expression
+flash-delay= 500
+bell= 1
+hilite-foreground= black
+hilite-background= #43cd80
diff --git a/Tools/idle/eventparse.py b/Tools/idle/eventparse.py
new file mode 100644
index 0000000..f253b2a
--- /dev/null
+++ b/Tools/idle/eventparse.py
@@ -0,0 +1,89 @@
+#! /usr/bin/env python
+
+"""Parse event definitions out of comments in source files."""
+
+import sys
+import glob
+import fileinput
+import pprint
+
+def main():
+    hits = []
+    sublist = []
+    args = sys.argv[1:]
+    if not args:
+        args = filter(lambda s: 'A' <= s[0] <= 'Z', glob.glob("*.py"))
+        if not args:
+            print "No arguments, no [A-Z]*.py files."
+            return 1
+    for line in fileinput.input(args):
+        if line[:2] == '#$':
+            if not sublist:
+                sublist.append('file %s' % fileinput.filename())
+                sublist.append('line %d' % fileinput.lineno())
+            sublist.append(line[2:-1].strip())
+        else:
+            if sublist:
+                hits.append(sublist)
+                sublist = []
+    if sublist:
+        hits.append(sublist)
+        sublist = []
+    dd = {}
+    for sublist in hits:
+        d = {}
+        for line in sublist:
+            words = line.split(None, 1)
+            if len(words) != 2:
+                continue
+            tag = words[0]
+            l = d.get(tag, [])
+            l.append(words[1])
+            d[tag] = l
+        if d.has_key('event'):
+            keys = d['event']
+            if len(keys) != 1:
+                print "Multiple event keys in", d
+                print 'File "%s", line %d' % (d['file'], d['line'])
+            key = keys[0]
+            if dd.has_key(key):
+                print "Duplicate event in", d
+                print 'File "%s", line %d' % (d['file'], d['line'])
+                return
+            dd[key] = d
+        else:
+            print "No event key in", d
+            print 'File "%s", line %d' % (d['file'], d['line'])
+    winevents = getevents(dd, "win")
+    unixevents = getevents(dd, "unix")
+    save = sys.stdout
+    f = open("keydefs.py", "w")
+    try:
+        sys.stdout = f
+        print "windows_keydefs = \\"
+        pprint.pprint(winevents)
+        print
+        print "unix_keydefs = \\"
+        pprint.pprint(unixevents)
+    finally:
+        sys.stdout = save
+    f.close()
+
+def getevents(dd, key):
+    res = {}
+    events = dd.keys()
+    events.sort()
+    for e in events:
+        d = dd[e]
+        if d.has_key(key) or d.has_key("all"):
+            list = []
+            for x in d.get(key, []) + d.get("all", []):
+                list.append(x)
+                if key == "unix" and x[:5] == "<Alt-":
+                    x = "<Meta-" + x[5:]
+                    list.append(x)
+            res[e] = list
+    return res
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/Tools/idle/keydefs.py b/Tools/idle/keydefs.py
new file mode 100644
index 0000000..9761258
--- /dev/null
+++ b/Tools/idle/keydefs.py
@@ -0,0 +1,57 @@
+windows_keydefs = \
+{'<<Copy>>': ['<Control-c>', '<Control-C>'],
+ '<<Cut>>': ['<Control-x>', '<Control-X>'],
+ '<<Paste>>': ['<Control-v>', '<Control-V>'],
+ '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
+ '<<center-insert>>': ['<Control-l>'],
+ '<<close-all-windows>>': ['<Control-q>'],
+ '<<close-window>>': ['<Alt-F4>'],
+ '<<dump-undo-state>>': ['<Control-backslash>'],
+ '<<end-of-file>>': ['<Control-d>'],
+ '<<help>>': ['<F1>'],
+ '<<history-next>>': ['<Alt-n>'],
+ '<<history-previous>>': ['<Alt-p>'],
+ '<<interrupt-execution>>': ['<Control-c>'],
+ '<<open-class-browser>>': ['<Alt-c>'],
+ '<<open-module>>': ['<Alt-m>'],
+ '<<open-new-window>>': ['<Control-n>'],
+ '<<open-window-from-file>>': ['<Control-o>'],
+ '<<plain-newline-and-indent>>': ['<Control-j>'],
+ '<<print-window>>': ['<Control-p>'],
+ '<<redo>>': ['<Control-y>'],
+ '<<remove-selection>>': ['<Escape>'],
+ '<<save-copy-of-window-as-file>>': ['<Alt-Shift-s>'],
+ '<<save-window-as-file>>': ['<Alt-s>'],
+ '<<save-window>>': ['<Control-s>'],
+ '<<select-all>>': ['<Control-a>'],
+ '<<toggle-auto-coloring>>': ['<Control-slash>'],
+ '<<undo>>': ['<Control-z>']}
+
+unix_keydefs = \
+{'<<Copy>>': ['<Alt-w>', '<Meta-w>'],
+ '<<Cut>>': ['<Control-w>'],
+ '<<Paste>>': ['<Control-y>'],
+ '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
+ '<<center-insert>>': ['<Control-l>'],
+ '<<close-all-windows>>': ['<Control-x><Control-c>'],
+ '<<close-window>>': ['<Control-x><Control-0>', '<Control-x><Key-0>'],
+ '<<do-nothing>>': ['<Control-x>'],
+ '<<dump-undo-state>>': ['<Control-backslash>'],
+ '<<end-of-file>>': ['<Control-d>'],
+ '<<help>>': ['<F1>'],
+ '<<history-next>>': ['<Alt-n>', '<Meta-n>'],
+ '<<history-previous>>': ['<Alt-p>', '<Meta-p>'],
+ '<<interrupt-execution>>': ['<Control-c>'],
+ '<<open-class-browser>>': ['<Control-x><Control-b>'],
+ '<<open-module>>': ['<Control-x><Control-m>'],
+ '<<open-new-window>>': ['<Control-x><Control-n>'],
+ '<<open-window-from-file>>': ['<Control-x><Control-f>'],
+ '<<plain-newline-and-indent>>': ['<Control-j>'],
+ '<<print-window>>': ['<Control-x><Control-p>'],
+ '<<redo>>': ['<Alt-z>', '<Meta-z>'],
+ '<<save-copy-of-window-as-file>>': ['<Control-x><w>'],
+ '<<save-window-as-file>>': ['<Control-x><Control-w>'],
+ '<<save-window>>': ['<Control-x><Control-s>'],
+ '<<select-all>>': ['<Alt-a>', '<Meta-a>'],
+ '<<toggle-auto-coloring>>': ['<Control-slash>'],
+ '<<undo>>': ['<Control-z>']}