starting to put in the module loading crap...
diff --git a/doc/build/read_markdown.py b/doc/build/read_markdown.py
index eab5b6f..cbd1a8c 100644
--- a/doc/build/read_markdown.py
+++ b/doc/build/read_markdown.py
@@ -148,11 +148,6 @@
         tag.text = code.text
         code.append(tag)
         code.text = ""
-        #code.tail =None
-        #tag.text = code.text
-        #code_parent = parents[code]
-        #code_parent[reverse_parent(code_parent, code)] = tag
-        
 
 def reverse_parent(parent, item):
     for n, i in enumerate(parent):
diff --git a/lib/mako/lookup.py b/lib/mako/lookup.py
index 53d580a..44cfd2a 100644
--- a/lib/mako/lookup.py
+++ b/lib/mako/lookup.py
@@ -4,11 +4,15 @@
 # This module is part of Mako and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-import posixpath
-import os
-from mako import exceptions
+import os, stat, posixpath, re
+from mako import exceptions, util
 from mako.template import Template
 
+try:
+    import threading
+except:
+    import dummy_threading as threading
+    
 class TemplateCollection(object):
     def has_template(self, uri):
         try:
@@ -20,25 +24,75 @@
         raise NotImplementedError()
         
 class TemplateLookup(TemplateCollection):
-    def __init__(self, directories=None, module_directory=None, filesystem_checks=True, collection_size=-1, format_exceptions=False, error_handler=None, output_encoding=None):
+    def __init__(self, directories=None, module_directory=None, filesystem_checks=False, collection_size=-1, format_exceptions=False, error_handler=None, output_encoding=None):
         self.directories = directories or []
         self.module_directory = module_directory
         self.filesystem_checks = filesystem_checks
         self.collection_size = collection_size
         self.template_args = {'format_exceptions':format_exceptions, 'error_handler':error_handler, 'output_encoding':output_encoding}
-        self._collection = {}
+        if collection_size == -1:
+            self.__collection = {}
+        else:
+            self.__collection = util.LRUCache(collection_size)
+        self._mutex = threading.Lock()
+        
     def get_template(self, uri):
         try:
-            return self._collection[uri]
-        except KeyError:
-            for dir in self.directories:
-                srcfile = posixpath.join(dir, uri)
-                if os.access(srcfile, os.F_OK):
-                    self._collection[uri] = Template(file(srcfile).read(), description=uri, filename=srcfile, lookup=self, **self.template_args)
-                    return self._collection[uri]
+            if self.filesystem_checks:
+                return self.__check(uri, self.__collection[uri])
             else:
-                raise exceptions.TemplateLookupException("Cant locate template for uri '%s'" % uri)
+                return self.__collection[uri]
+        except KeyError:
+            self._mutex.acquire()
+            try:
+                try:
+                    return self.__collection[uri]
+                except KeyError:
+                    for dir in self.directories:
+                        srcfile = posixpath.join(dir, uri)
+                        if os.access(srcfile, os.F_OK):
+                            return self.__load(srcfile, uri)
+                    else:
+                        raise exceptions.TemplateLookupException("Cant locate template for uri '%s'" % uri)
+            finally:
+                self._mutex.release()
+
+    def __ident_from_uri(self, uri):
+        return re.sub(r"\W", "_", uri)
+        
+    def __load(self, filename, uri):
+        try:
+            self.__collection[uri] = Template(file(filename).read(), identifier=self.__ident_from_uri(uri), description=uri, filename=filename, lookup=self, **self.template_args)
+            return self.__collection[uri]
+        except:
+            self.__collection.pop(uri, None)
+            raise
+            
+    def __check(self, uri, template):
+        if template.filename is None:
+            return template
+        if not os.access(template.filename, os.F_OK):
+            self.__collection.pop(uri, None)
+            raise exceptions.TemplateLookupException("Cant locate template for uri '%s'" % uri)
+        elif template.module._modified_time < os.stat(template.filename)[stat.ST_MTIME]:
+            return __load(template.filename, uri)
+        else:
+            return template
+            
     def put_string(self, uri, text):
-        self._collection[uri] = Template(text, lookup=self, description=uri, **self.template_args)
+        lock = sync.NameLock(uri)
+        lock.acquire()
+        try:
+            self.__collection[uri] = Template(text, lookup=self, description=uri, **self.template_args)
+        finally:
+            lock.release()
     def put_template(self, uri, template):
-        self._collection[uri] = template
\ No newline at end of file
+        lock = sync.NameLock(uri)
+        lock.acquire()
+        try:
+            self.__collection[uri] = template
+        finally:
+            lock.release()
+        
+            
+            
\ No newline at end of file
diff --git a/lib/mako/template.py b/lib/mako/template.py
index cb071d0..34e9bcf 100644
--- a/lib/mako/template.py
+++ b/lib/mako/template.py
@@ -11,7 +11,7 @@
 from mako.codegen import Compiler
 from mako import runtime
 from mako import util
-import imp, time, weakref
+import imp, time, weakref, tempfile, shutil
 
 _modules = weakref.WeakValueDictionary()
 _inmemory_templates = weakref.WeakValueDictionary()
@@ -23,14 +23,11 @@
 
 class Template(object):
     """a compiled template"""
-    def __init__(self, text=None, module=None, identifier=None, description=None, filename=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=None):
+    def __init__(self, text=None,identifier=None, description=None, filename=None, format_exceptions=False, error_handler=None, lookup=None, output_encoding=None, module_directory=None):
         """construct a new Template instance using either literal template text, or a previously loaded template module
         
         text - textual template source, or None if a module is to be provided
         
-        module - a Python module, such as loaded via __import__ or similar.  the module should contain at least one
-        function render(context) that renders with the given context.  
-        
         identifier - the "id" of this template.  defaults to the identifier of the given module, or for text
         the hex string of this Template's object id
         
@@ -45,9 +42,21 @@
             _inmemory_templates[module.__name__] = self
             self._code = code
             self._source = text
+        elif filename is not None:
+            if module_directory is not None:
+                path = posixpath.join(module_directory, identifier + ".py")
+                if not os.access(path, os.F_OK):
+                    util.verify_directory(module_directory)
+                    _compile_module(text, identifier, filename, module_directory)
+                module = imp.load_source(self.identifier, path, file(path))
+                del sys.modules[self.identifier]
+            else:
+                (code, module) = _compile_text(file(filename), self.identifier, filename)
+                self._source = None
+                self._code = code
         else:
-            self._source = None
-            self._code = None
+            raise exceptions.RuntimeException("Template requires text or filename")
+
         self.module = module
         self.description = description
         self.filename = filename
@@ -96,40 +105,54 @@
 def _compile_text(text, identifier, filename):
     node = Lexer(text, filename).parse()
     source = Compiler(node, filename).render()
-    if filename is not None:
-        file(filename + ".py", "w").write(source)
-    else:
-        print source
+#    if filename is not None:
+#        file(filename + ".py", "w").write(source)
+#    else:
+#        print source
     cid = identifier
     module = imp.new_module(cid)
     code = compile(source, cid + " " + str(filename), 'exec')
     exec code in module.__dict__, module.__dict__
     return (source, module)
 
+def _compile_module(text, identifier, filename, outputpath):
+    
+    dest = tempfile.NamedTemporaryFile()
+
+    node = Lexer(text, filename).parse()
+    source = Compiler(node, filename).render()
+    dest.write(source)
+    dest.close()
+    shutil.move(dest.name, outputpath)
+
 def _get_template_source(callable_):
     """return the source code for the template that produced the given rendering callable"""
     name = callable_.func_globals['__name__']
     try:
         template = _inmemory_templates[name]
-        return template._source
+        if template._source  is not None:
+            return template._source
     except KeyError:
-        module = _modules[name].module
-        filename = module._template_filename
-        if filename is None:
-            if not filename:
-                raise exceptions.RuntimeException("Cant get source code or template filename for template: %s" % name)
-        return file(filename).read()
+        pass
+    module = _modules[name].module
+    filename = module._template_filename
+    if filename is None:
+        if not filename:
+            raise exceptions.RuntimeException("Cant get source code or template filename for template: %s" % name)
+    return file(filename).read()
 
 def _get_module_source(callable_):
     name = callable_.func_globals['__name__']
     try:
         template = _inmemory_templates[name]
-        return template._code
+        if template._code is not None:
+            return template._code
     except KeyError:
-        module = _modules[name].module
-        filename = module.__file__
-        if filename is None:
-            if not filename:
-                raise exceptions.RuntimeException("Cant get module source code or module filename for template: %s" % name)
-        return file(filename).read()
+        pass
+    module = _modules[name].module
+    filename = module.__file__
+    if filename is None:
+        if not filename:
+            raise exceptions.RuntimeException("Cant get module source code or module filename for template: %s" % name)
+    return file(filename).read()
                 
diff --git a/lib/mako/util.py b/lib/mako/util.py
index 0560d8a..a017830 100644
--- a/lib/mako/util.py
+++ b/lib/mako/util.py
@@ -15,7 +15,26 @@
 except:
    from StringIO import StringIO
 
+import weakref, os
 
+try:
+   import threading
+   import thread
+except ImportError:
+   import dummy_threading as threading
+   import dummy_thread as thread
+
+def verify_directory(dir):
+   """create and/or verify a filesystem directory."""
+   tries = 0
+   while not os.access(dir, os.F_OK):
+       try:
+           tries += 1
+           os.makedirs(dir, 0750)
+       except:
+           if tries > 5:
+               raise
+   
 class FastEncodingBuffer(object):
     """a very rudimentary buffer that is faster than StringIO, but doesnt crash on unicode data like cStringIO."""
     def __init__(self, encoding=None):
@@ -29,3 +48,111 @@
         else:
             return u''.join(self.data)
 
+class ThreadLocalRegistry(object):
+    """a registry that stores instances keyed to the current thread.  if a requested
+    instance does not exist for a particular thread, it is created by a creation function.
+    """
+    def __init__(self, createfunc):
+        self.__createfunc = createfunc
+        self.__scopefunc = thread.get_ident
+        self.__registry = {}
+    def __call__(self):
+        key = self.__scopefunc()
+        try:
+            return self.__registry[key]
+        except KeyError:
+            return self.__registry.setdefault(key, self.__createfunc())
+    def set(self, obj):
+        self.registry[self.__scopefunc()] = obj
+    def clear(self):
+        try:
+            del self.registry[self.__scopefunc()]
+        except KeyError:
+            pass
+
+class LRUCache(dict):
+    """A dictionary-like object that stores only a certain number of items, and
+    discards its least recently used item when full.
+
+    this is Chris Lenz' cleanup of Mike Bayer's version from Myghty.
+    """
+
+    class _Item(object):
+        def __init__(self, key, value):
+            self.previous = self.next = None
+            self.key = key
+            self.value = value
+        def __repr__(self):
+            return repr(self.value)
+
+    def __init__(self, capacity):
+        self._dict = dict()
+        self.capacity = capacity
+        self.head = None
+        self.tail = None
+
+    def __contains__(self, key):
+        return key in self._dict
+
+    def __iter__(self):
+        cur = self.head
+        while cur:
+            yield cur.key
+            cur = cur.next
+
+    def __len__(self):
+        return len(self._dict)
+
+    def __getitem__(self, key):
+        item = self._dict[key]
+        self._update_item(item)
+        return item.value
+
+    def __setitem__(self, key, value):
+        item = self._dict.get(key)
+        if item is None:
+            item = self._Item(key, value)
+            self._dict[key] = item
+            self._insert_item(item)
+        else:
+            item.value = value
+            self._update_item(item)
+            self._manage_size()
+
+    def __repr__(self):
+        return repr(self._dict)
+
+    def _insert_item(self, item):
+        item.previous = None
+        item.next = self.head
+        if self.head is not None:
+            self.head.previous = item
+        else:
+            self.tail = item
+        self.head = item
+        self._manage_size()
+
+    def _manage_size(self):
+        while len(self._dict) > self.capacity:
+            olditem = self._dict[self.tail.key]
+            del self._dict[self.tail.key]
+            if self.tail != self.head:
+                self.tail = self.tail.previous
+                self.tail.next = None
+            else:
+                self.head = self.tail = None
+
+    def _update_item(self, item):
+        if self.head == item:
+            return
+
+        previous = item.previous
+        previous.next = item.next
+        if item.next is not None:
+            item.next.previous = previous
+        else:
+            self.tail = previous
+
+        item.previous = None
+        item.next = self.head
+        self.head.previous = self.head = item