Index: django/core/template_loader.py
===================================================================
--- django/core/template_loader.py	(revision 781)
+++ django/core/template_loader.py	(working copy)
@@ -1,7 +1,8 @@
 "Wrapper for loading templates from storage of some sort (e.g. files or db)"
-import template
-from template_file import load_template_source
 
+from django.core import template
+from django.core.template.loaders.filesystem import load_template_source
+
 class ExtendsError(Exception):
     pass
 
@@ -24,7 +25,7 @@
     Loads the given template_name and renders it with the given dictionary as
     context. The template_name may be a string to load a single template using
     get_template, or it may be a tuple to use select_template to find one of
-    the templates in the list.  Returns a string. 
+    the templates in the list.  Returns a string.
     """
     dictionary = dictionary or {}
     if isinstance(template_name, (list, tuple)):
Index: django/core/defaulttags.py
===================================================================
--- django/core/defaulttags.py	(revision 772)
+++ django/core/defaulttags.py	(working copy)
@@ -1,770 +0,0 @@
-"Default tags used by the template system, available to all templates."
-
-import sys
-import template
-
-class CommentNode(template.Node):
-    def render(self, context):
-        return ''
-
-class CycleNode(template.Node):
-    def __init__(self, cyclevars):
-        self.cyclevars = cyclevars
-        self.cyclevars_len = len(cyclevars)
-        self.counter = -1
-
-    def render(self, context):
-        self.counter += 1
-        return self.cyclevars[self.counter % self.cyclevars_len]
-
-class DebugNode(template.Node):
-    def render(self, context):
-        from pprint import pformat
-        output = [pformat(val) for val in context]
-        output.append('\n\n')
-        output.append(pformat(sys.modules))
-        return ''.join(output)
-
-class FilterNode(template.Node):
-    def __init__(self, filters, nodelist):
-        self.filters, self.nodelist = filters, nodelist
-
-    def render(self, context):
-        output = self.nodelist.render(context)
-        # apply filters
-        for f in self.filters:
-            output = template.registered_filters[f[0]][0](output, f[1])
-        return output
-
-class FirstOfNode(template.Node):
-    def __init__(self, vars):
-        self.vars = vars
-
-    def render(self, context):
-        for var in self.vars:
-            value = template.resolve_variable(var, context)
-            if value:
-                return str(value)
-        return ''
-
-class ForNode(template.Node):
-    def __init__(self, loopvar, sequence, reversed, nodelist_loop):
-        self.loopvar, self.sequence = loopvar, sequence
-        self.reversed = reversed
-        self.nodelist_loop = nodelist_loop
-
-    def __repr__(self):
-        if self.reversed:
-            reversed = ' reversed'
-        else:
-            reversed = ''
-        return "<For Node: for %s in %s, tail_len: %d%s>" % \
-            (self.loopvar, self.sequence, len(self.nodelist_loop), reversed)
-
-    def __iter__(self):
-        for node in self.nodelist_loop:
-            yield node
-
-    def get_nodes_by_type(self, nodetype):
-        nodes = []
-        if isinstance(self, nodetype):
-            nodes.append(self)
-        nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype))
-        return nodes
-
-    def render(self, context):
-        nodelist = template.NodeList()
-        if context.has_key('forloop'):
-            parentloop = context['forloop']
-        else:
-            parentloop = {}
-        context.push()
-        try:
-            values = template.resolve_variable_with_filters(self.sequence, context)
-        except template.VariableDoesNotExist:
-            values = []
-        if values is None:
-            values = []
-        len_values = len(values)
-        if self.reversed:
-            # From http://www.python.org/doc/current/tut/node11.html
-            def reverse(data):
-                for index in range(len(data)-1, -1, -1):
-                    yield data[index]
-            values = reverse(values)
-        for i, item in enumerate(values):
-            context['forloop'] = {
-                # shortcuts for current loop iteration number
-                'counter0': i,
-                'counter': i+1,
-                # reverse counter iteration numbers
-                'revcounter': len_values - i,
-                'revcounter0': len_values - i - 1,
-                # boolean values designating first and last times through loop
-                'first': (i == 0),
-                'last': (i == len_values - 1),
-                'parentloop': parentloop,
-            }
-            context[self.loopvar] = item
-            for node in self.nodelist_loop:
-                nodelist.append(node.render(context))
-        context.pop()
-        return nodelist.render(context)
-
-class IfChangedNode(template.Node):
-    def __init__(self, nodelist):
-        self.nodelist = nodelist
-        self._last_seen = None
-
-    def render(self, context):
-        content = self.nodelist.render(context)
-        if content != self._last_seen:
-            firstloop = (self._last_seen == None)
-            self._last_seen = content
-            context.push()
-            context['ifchanged'] = {'firstloop': firstloop}
-            content = self.nodelist.render(context)
-            context.pop()
-            return content
-        else:
-            return ''
-
-class IfEqualNode(template.Node):
-    def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
-        self.var1, self.var2 = var1, var2
-        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
-        self.negate = negate
-
-    def __repr__(self):
-        return "<IfEqualNode>"
-
-    def render(self, context):
-        val1 = template.resolve_variable(self.var1, context)
-        val2 = template.resolve_variable(self.var2, context)
-        if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
-            return self.nodelist_true.render(context)
-        return self.nodelist_false.render(context)
-
-class IfNode(template.Node):
-    def __init__(self, boolvars, nodelist_true, nodelist_false):
-        self.boolvars = boolvars
-        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
-
-    def __repr__(self):
-        return "<If node>"
-
-    def __iter__(self):
-        for node in self.nodelist_true:
-            yield node
-        for node in self.nodelist_false:
-            yield node
-
-    def get_nodes_by_type(self, nodetype):
-        nodes = []
-        if isinstance(self, nodetype):
-            nodes.append(self)
-        nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
-        nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
-        return nodes
-
-    def render(self, context):
-        for ifnot, boolvar in self.boolvars:
-            try:
-                value = template.resolve_variable_with_filters(boolvar, context)
-            except template.VariableDoesNotExist:
-                value = None
-            if (value and not ifnot) or (ifnot and not value):
-                return self.nodelist_true.render(context)
-        return self.nodelist_false.render(context)
-
-class RegroupNode(template.Node):
-    def __init__(self, target_var, expression, var_name):
-        self.target_var, self.expression = target_var, expression
-        self.var_name = var_name
-
-    def render(self, context):
-        obj_list = template.resolve_variable_with_filters(self.target_var, context)
-        if obj_list == '': # target_var wasn't found in context; fail silently
-            context[self.var_name] = []
-            return ''
-        output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
-        for obj in obj_list:
-            grouper = template.resolve_variable_with_filters('var.%s' % self.expression, \
-                template.Context({'var': obj}))
-            if output and repr(output[-1]['grouper']) == repr(grouper):
-                output[-1]['list'].append(obj)
-            else:
-                output.append({'grouper': grouper, 'list': [obj]})
-        context[self.var_name] = output
-        return ''
-
-def include_is_allowed(filepath):
-    from django.conf.settings import ALLOWED_INCLUDE_ROOTS
-    for root in ALLOWED_INCLUDE_ROOTS:
-        if filepath.startswith(root):
-            return True
-    return False
-
-class SsiNode(template.Node):
-    def __init__(self, filepath, parsed):
-        self.filepath, self.parsed = filepath, parsed
-
-    def render(self, context):
-        if not include_is_allowed(self.filepath):
-            return '' # Fail silently for invalid includes.
-        try:
-            fp = open(self.filepath, 'r')
-            output = fp.read()
-            fp.close()
-        except IOError:
-            output = ''
-        if self.parsed:
-            try:
-                t = template.Template(output)
-                return t.render(context)
-            except template.TemplateSyntaxError:
-                return '' # Fail silently for invalid included templates.
-        return output
-
-class LoadNode(template.Node):
-    def __init__(self, taglib):
-        self.taglib = taglib
-
-    def load_taglib(taglib):
-        mod = __import__("django.templatetags.%s" % taglib.split('.')[-1], '', '', [''])
-        reload(mod)
-        return mod
-    load_taglib = staticmethod(load_taglib)
-
-    def render(self, context):
-        "Import the relevant module"
-        try:
-            self.__class__.load_taglib(self.taglib)
-        except ImportError:
-            pass # Fail silently for invalid loads.
-        return ''
-
-class NowNode(template.Node):
-    def __init__(self, format_string):
-        self.format_string = format_string
-
-    def render(self, context):
-        from datetime import datetime
-        from django.utils.dateformat import DateFormat
-        df = DateFormat(datetime.now())
-        return df.format(self.format_string)
-
-class TemplateTagNode(template.Node):
-    mapping = {'openblock': template.BLOCK_TAG_START,
-               'closeblock': template.BLOCK_TAG_END,
-               'openvariable': template.VARIABLE_TAG_START,
-               'closevariable': template.VARIABLE_TAG_END}
-
-    def __init__(self, tagtype):
-        self.tagtype = tagtype
-
-    def render(self, context):
-        return self.mapping.get(self.tagtype, '')
-
-class WidthRatioNode(template.Node):
-    def __init__(self, val_var, max_var, max_width):
-        self.val_var = val_var
-        self.max_var = max_var
-        self.max_width = max_width
-
-    def render(self, context):
-        try:
-            value = template.resolve_variable_with_filters(self.val_var, context)
-            maxvalue = template.resolve_variable_with_filters(self.max_var, context)
-        except template.VariableDoesNotExist:
-            return ''
-        try:
-            value = float(value)
-            maxvalue = float(maxvalue)
-            ratio = (value / maxvalue) * int(self.max_width)
-        except (ValueError, ZeroDivisionError):
-            return ''
-        return str(int(round(ratio)))
-
-def do_comment(parser, token):
-    """
-    Ignore everything between ``{% comment %}`` and ``{% endcomment %}``
-    """
-    nodelist = parser.parse(('endcomment',))
-    parser.delete_first_token()
-    return CommentNode()
-
-def do_cycle(parser, token):
-    """
-    Cycle among the given strings each time this tag is encountered
-
-    Within a loop, cycles among the given strings each time through
-    the loop::
-
-        {% for o in some_list %}
-            <tr class="{% cycle row1,row2 %}">
-                ...
-            </tr>
-        {% endfor %}
-
-    Outside of a loop, give the values a unique name the first time you call
-    it, then use that name each sucessive time through::
-
-            <tr class="{% cycle row1,row2,row3 as rowcolors %}">...</tr>
-            <tr class="{% cycle rowcolors %}">...</tr>
-            <tr class="{% cycle rowcolors %}">...</tr>
-
-    You can use any number of values, seperated by commas. Make sure not to
-    put spaces between the values -- only commas.
-    """
-
-    # Note: This returns the exact same node on each {% cycle name %} call; that
-    # is, the node object returned from {% cycle a,b,c as name %} and the one
-    # returned from {% cycle name %} are the exact same object.  This shouldn't
-    # cause problems (heh), but if it does, now you know.
-    #
-    # Ugly hack warning: this stuffs the named template dict into parser so
-    # that names are only unique within each template (as opposed to using
-    # a global variable, which would make cycle names have to be unique across
-    # *all* templates.
-
-    args = token.contents.split()
-    if len(args) < 2:
-        raise template.TemplateSyntaxError("'Cycle' statement requires at least two arguments")
-
-    elif len(args) == 2 and "," in args[1]:
-        # {% cycle a,b,c %}
-        cyclevars = [v for v in args[1].split(",") if v]    # split and kill blanks
-        return CycleNode(cyclevars)
-        # {% cycle name %}
-
-    elif len(args) == 2:
-        name = args[1]
-        if not parser._namedCycleNodes.has_key(name):
-            raise template.TemplateSyntaxError("Named cycle '%s' does not exist" % name)
-        return parser._namedCycleNodes[name]
-
-    elif len(args) == 4:
-        # {% cycle a,b,c as name %}
-        if args[2] != 'as':
-            raise template.TemplateSyntaxError("Second 'cycle' argument must be 'as'")
-        cyclevars = [v for v in args[1].split(",") if v]    # split and kill blanks
-        name = args[3]
-        node = CycleNode(cyclevars)
-
-        if not hasattr(parser, '_namedCycleNodes'):
-            parser._namedCycleNodes = {}
-
-        parser._namedCycleNodes[name] = node
-        return node
-
-    else:
-        raise template.TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
-
-def do_debug(parser, token):
-    "Print a whole load of debugging information, including the context and imported modules"
-    return DebugNode()
-
-def do_filter(parser, token):
-    """
-    Filter the contents of the blog through variable filters.
-
-    Filters can also be piped through each other, and they can have
-    arguments -- just like in variable syntax.
-
-    Sample usage::
-
-        {% filter escape|lower %}
-            This text will be HTML-escaped, and will appear in lowercase.
-        {% endfilter %}
-    """
-    _, rest = token.contents.split(None, 1)
-    _, filters = template.get_filters_from_token('var|%s' % rest)
-    nodelist = parser.parse(('endfilter',))
-    parser.delete_first_token()
-    return FilterNode(filters, nodelist)
-
-def do_firstof(parser, token):
-    """
-    Outputs the first variable passed that is not False.
-
-    Outputs nothing if all the passed variables are False.
-
-    Sample usage::
-
-        {% firstof var1 var2 var3 %}
-
-    This is equivalent to::
-
-        {% if var1 %}
-            {{ var1 }}
-        {% else %}{% if var2 %}
-            {{ var2 }}
-        {% else %}{% if var3 %}
-            {{ var3 }}
-        {% endif %}{% endif %}{% endif %}
-
-    but obviously much cleaner!
-    """
-    bits = token.contents.split()[1:]
-    if len(bits) < 1:
-        raise template.TemplateSyntaxError, "'firstof' statement requires at least one argument"
-    return FirstOfNode(bits)
-
-
-def do_for(parser, token):
-    """
-    Loop over each item in an array.
-
-    For example, to display a list of athletes given ``athlete_list``::
-
-        <ul>
-        {% for athlete in athlete_list %}
-            <li>{{ athlete.name }}</li>
-        {% endfor %}
-        </ul>
-
-    You can also loop over a list in reverse by using
-    ``{% for obj in list reversed %}``.
-
-    The for loop sets a number of variables available within the loop:
-
-        ==========================  ================================================
-        Variable                    Description
-        ==========================  ================================================
-        ``forloop.counter``         The current iteration of the loop (1-indexed)
-        ``forloop.counter0``        The current iteration of the loop (0-indexed)
-        ``forloop.revcounter``      The number of iterations from the end of the 
-                                    loop (1-indexed)
-        ``forloop.revcounter0``     The number of iterations from the end of the 
-                                    loop (0-indexed)
-        ``forloop.first``           True if this is the first time through the loop
-        ``forloop.last``            True if this is the last time through the loop
-        ``forloop.parentloop``      For nested loops, this is the loop "above" the
-                                    current one
-        ==========================  ================================================
-
-    """
-    bits = token.contents.split()
-    if len(bits) == 5 and bits[4] != 'reversed':
-        raise template.TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
-    if len(bits) not in (4, 5):
-        raise template.TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
-    if bits[2] != 'in':
-        raise template.TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
-    loopvar = bits[1]
-    sequence = bits[3]
-    reversed = (len(bits) == 5)
-    nodelist_loop = parser.parse(('endfor',))
-    parser.delete_first_token()
-    return ForNode(loopvar, sequence, reversed, nodelist_loop)
-
-def do_ifequal(parser, token, negate):
-    """
-    Output the contents of the block if the two arguments equal/don't equal each other.
-
-    Examples::
-
-        {% ifequal user.id comment.user_id %}
-            ...
-        {% endifequal %}
-
-        {% ifnotequal user.id comment.user_id %}
-            ...
-        {% else %}
-            ...
-        {% endifnotequal %}
-    """
-    bits = token.contents.split()
-    if len(bits) != 3:
-        raise template.TemplateSyntaxError, "%r takes two arguments" % bits[0]
-    end_tag = 'end' + bits[0]
-    nodelist_true = parser.parse(('else', end_tag))
-    token = parser.next_token()
-    if token.contents == 'else':
-        nodelist_false = parser.parse((end_tag,))
-        parser.delete_first_token()
-    else:
-        nodelist_false = template.NodeList()
-    return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
-
-def do_if(parser, token):
-    """
-    The ``{% if %}`` tag evaluates a variable, and if that variable is "true"
-    (i.e. exists, is not empty, and is not a false boolean value) the contents
-    of the block are output:
-
-    ::
-
-        {% if althlete_list %}
-            Number of athletes: {{ althete_list|count }}
-        {% else %}
-            No athletes.
-        {% endif %}
-
-    In the above, if ``athlete_list`` is not empty, the number of athletes will
-    be displayed by the ``{{ athlete_list|count }}`` variable.
-
-    As you can see, the ``if`` tag can take an option ``{% else %}`` clause that
-    will be displayed if the test fails.
-
-    ``if`` tags may use ``or`` or ``not`` to test a number of variables or to
-    negate a given variable::
-
-        {% if not athlete_list %}
-            There are no athletes.
-        {% endif %}
-
-        {% if athlete_list or coach_list %}
-            There are some athletes or some coaches.
-        {% endif %}
-
-        {% if not athlete_list or coach_list %}
-            There are no athletes or there are some coaches (OK, so
-            writing English translations of boolean logic sounds
-            stupid; it's not my fault).
-        {% endif %}
-
-    For simplicity, ``if`` tags do not allow ``and`` clauses; use nested ``if``
-    tags instead::
-
-        {% if athlete_list %}
-            {% if coach_list %}
-                Number of athletes: {{ athlete_list|count }}.
-                Number of coaches: {{ coach_list|count }}.
-            {% endif %}
-        {% endif %}
-    """
-    bits = token.contents.split()
-    del bits[0]
-    if not bits:
-        raise template.TemplateSyntaxError, "'if' statement requires at least one argument"
-    # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
-    boolpairs = ' '.join(bits).split(' or ')
-    boolvars = []
-    for boolpair in boolpairs:
-        if ' ' in boolpair:
-            not_, boolvar = boolpair.split()
-            if not_ != 'not':
-                raise template.TemplateSyntaxError, "Expected 'not' in if statement"
-            boolvars.append((True, boolvar))
-        else:
-            boolvars.append((False, boolpair))
-    nodelist_true = parser.parse(('else', 'endif'))
-    token = parser.next_token()
-    if token.contents == 'else':
-        nodelist_false = parser.parse(('endif',))
-        parser.delete_first_token()
-    else:
-        nodelist_false = template.NodeList()
-    return IfNode(boolvars, nodelist_true, nodelist_false)
-
-def do_ifchanged(parser, token):
-    """
-    Check if a value has changed from the last iteration of a loop.
-
-    The 'ifchanged' block tag is used within a loop. It checks its own rendered
-    contents against its previous state and only displays its content if the
-    value has changed::
-
-        <h1>Archive for {{ year }}</h1>
-
-        {% for date in days %}
-        {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %}
-        <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>
-        {% endfor %}
-    """
-    bits = token.contents.split()
-    if len(bits) != 1:
-        raise template.TemplateSyntaxError, "'ifchanged' tag takes no arguments"
-    nodelist = parser.parse(('endifchanged',))
-    parser.delete_first_token()
-    return IfChangedNode(nodelist)
-
-def do_ssi(parser, token):
-    """
-    Output the contents of a given file into the page.
-
-    Like a simple "include" tag, the ``ssi`` tag includes the contents
-    of another file -- which must be specified using an absolute page --
-    in the current page::
-
-        {% ssi /home/html/ljworld.com/includes/right_generic.html %}
-
-    If the optional "parsed" parameter is given, the contents of the included
-    file are evaluated as template code, with the current context::
-
-        {% ssi /home/html/ljworld.com/includes/right_generic.html parsed %}
-    """
-    bits = token.contents.split()
-    parsed = False
-    if len(bits) not in (2, 3):
-        raise template.TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included"
-    if len(bits) == 3:
-        if bits[2] == 'parsed':
-            parsed = True
-        else:
-            raise template.TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0]
-    return SsiNode(bits[1], parsed)
-
-def do_load(parser, token):
-    """
-    Load a custom template tag set.
-
-    For example, to load the template tags in ``django/templatetags/news/photos.py``::
-
-        {% load news.photos %}
-    """
-    bits = token.contents.split()
-    if len(bits) != 2:
-        raise template.TemplateSyntaxError, "'load' statement takes one argument"
-    taglib = bits[1]
-    # check at compile time that the module can be imported
-    try:
-        LoadNode.load_taglib(taglib)
-    except ImportError:
-        raise template.TemplateSyntaxError, "'%s' is not a valid tag library" % taglib
-    return LoadNode(taglib)
-
-def do_now(parser, token):
-    """
-    Display the date, formatted according to the given string.
-
-    Uses the same format as PHP's ``date()`` function; see http://php.net/date
-    for all the possible values.
-
-    Sample usage::
-
-        It is {% now "jS F Y H:i" %}
-    """
-    bits = token.contents.split('"')
-    if len(bits) != 3:
-        raise template.TemplateSyntaxError, "'now' statement takes one argument"
-    format_string = bits[1]
-    return NowNode(format_string)
-
-def do_regroup(parser, token):
-    """
-    Regroup a list of alike objects by a common attribute.
-
-    This complex tag is best illustrated by use of an example:  say that
-    ``people`` is a list of ``Person`` objects that have ``first_name``,
-    ``last_name``, and ``gender`` attributes, and you'd like to display a list
-    that looks like:
-
-        * Male:
-            * George Bush
-            * Bill Clinton
-        * Female:
-            * Margaret Thatcher
-            * Colendeeza Rice
-        * Unknown:
-            * Pat Smith
-
-    The following snippet of template code would accomplish this dubious task::
-
-        {% regroup people by gender as grouped %}
-        <ul>
-        {% for group in grouped %}
-            <li>{{ group.grouper }}
-            <ul>
-                {% for item in group.list %}
-                <li>{{ item }}</li>
-                {% endfor %}
-            </ul>
-        {% endfor %}
-        </ul>
-
-    As you can see, ``{% regroup %}`` populates a variable with a list of
-    objects with ``grouper`` and ``list`` attributes.  ``grouper`` contains the
-    item that was grouped by; ``list`` contains the list of objects that share
-    that ``grouper``.  In this case, ``grouper`` would be ``Male``, ``Female``
-    and ``Unknown``, and ``list`` is the list of people with those genders.
-
-    Note that `{% regroup %}`` does not work when the list to be grouped is not
-    sorted by the key you are grouping by!  This means that if your list of
-    people was not sorted by gender, you'd need to make sure it is sorted before
-    using it, i.e.::
-
-        {% regroup people|dictsort:"gender" by gender as grouped %}
-
-    """
-    firstbits = token.contents.split(None, 3)
-    if len(firstbits) != 4:
-        raise template.TemplateSyntaxError, "'regroup' tag takes five arguments"
-    target_var = firstbits[1]
-    if firstbits[2] != 'by':
-        raise template.TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'"
-    lastbits_reversed = firstbits[3][::-1].split(None, 2)
-    if lastbits_reversed[1][::-1] != 'as':
-        raise template.TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'"
-    expression = lastbits_reversed[2][::-1]
-    var_name = lastbits_reversed[0][::-1]
-    return RegroupNode(target_var, expression, var_name)
-
-def do_templatetag(parser, token):
-    """
-    Output one of the bits used to compose template tags.
-
-    Since the template system has no concept of "escaping", to display one of
-    the bits used in template tags, you must use the ``{% templatetag %}`` tag.
-
-    The argument tells which template bit to output:
-
-        ==================  =======
-        Argument            Outputs
-        ==================  =======
-        ``openblock``       ``{%``
-        ``closeblock``      ``%}``
-        ``openvariable``    ``{{``
-        ``closevariable``   ``}}``
-        ==================  =======
-    """
-    bits = token.contents.split()
-    if len(bits) != 2:
-        raise template.TemplateSyntaxError, "'templatetag' statement takes one argument"
-    tag = bits[1]
-    if not TemplateTagNode.mapping.has_key(tag):
-        raise template.TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \
-            (tag, TemplateTagNode.mapping.keys())
-    return TemplateTagNode(tag)
-
-def do_widthratio(parser, token):
-    """
-    For creating bar charts and such, this tag calculates the ratio of a given
-    value to a maximum value, and then applies that ratio to a constant.
-
-    For example::
-
-        <img src='bar.gif' height='10' width='{% widthratio this_value max_value 100 %}' />
-
-    Above, if ``this_value`` is 175 and ``max_value`` is 200, the the image in
-    the above example will be 88 pixels wide (because 175/200 = .875; .875 *
-    100 = 87.5 which is rounded up to 88).
-    """
-    bits = token.contents.split()
-    if len(bits) != 4:
-        raise template.TemplateSyntaxError("widthratio takes three arguments")
-    tag, this_value_var, max_value_var, max_width = bits
-    try:
-        max_width = int(max_width)
-    except ValueError:
-        raise template.TemplateSyntaxError("widthratio final argument must be an integer")
-    return WidthRatioNode(this_value_var, max_value_var, max_width)
-
-template.register_tag('comment', do_comment)
-template.register_tag('cycle', do_cycle)
-template.register_tag('debug', do_debug)
-template.register_tag('filter', do_filter)
-template.register_tag('firstof', do_firstof)
-template.register_tag('for', do_for)
-template.register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
-template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
-template.register_tag('if', do_if)
-template.register_tag('ifchanged', do_ifchanged)
-template.register_tag('regroup', do_regroup)
-template.register_tag('ssi', do_ssi)
-template.register_tag('load', do_load)
-template.register_tag('now', do_now)
-template.register_tag('templatetag', do_templatetag)
-template.register_tag('widthratio', do_widthratio)
Index: django/core/template_file.py
===================================================================
--- django/core/template_file.py	(revision 772)
+++ django/core/template_file.py	(working copy)
@@ -1,21 +0,0 @@
-# Wrapper for loading templates from files
-
-from django.conf.settings import TEMPLATE_DIRS, TEMPLATE_FILE_EXTENSION
-from django.core.template import TemplateDoesNotExist
-import os
-
-def load_template_source(template_name, template_dirs=None):
-    if not template_dirs:
-        template_dirs = TEMPLATE_DIRS
-    tried = []
-    for template_dir in template_dirs:
-        filepath = os.path.join(template_dir, template_name) + TEMPLATE_FILE_EXTENSION
-        try:
-            return open(filepath).read()
-        except IOError:
-            tried.append(filepath)
-    if template_dirs:
-        error_msg = "Tried %s" % tried
-    else:
-        error_msg = "Your TEMPLATE_DIRS settings is empty. Change it to point to at least one template directory."
-    raise TemplateDoesNotExist, error_msg
Index: django/core/template.py
===================================================================
--- django/core/template.py	(revision 772)
+++ django/core/template.py	(working copy)
@@ -1,494 +0,0 @@
-"""
-This is the Django template system.
-
-How it works:
-
-The tokenize() function converts a template string (i.e., a string containing
-markup with custom template tags) to tokens, which can be either plain text
-(TOKEN_TEXT), variables (TOKEN_VAR) or block statements (TOKEN_BLOCK).
-
-The Parser() class takes a list of tokens in its constructor, and its parse()
-method returns a compiled template -- which is, under the hood, a list of
-Node objects.
-
-Each Node is responsible for creating some sort of output -- e.g. simple text
-(TextNode), variable values in a given context (VariableNode), results of basic
-logic (IfNode), results of looping (ForNode), or anything else. The core Node
-types are TextNode, VariableNode, IfNode and ForNode, but plugin modules can
-define their own custom node types.
-
-Each Node has a render() method, which takes a Context and returns a string of
-the rendered node. For example, the render() method of a Variable Node returns
-the variable's value as a string. The render() method of an IfNode returns the
-rendered output of whatever was inside the loop, recursively.
-
-The Template class is a convenient wrapper that takes care of template
-compilation and rendering.
-
-Usage:
-
-The only thing you should ever use directly in this file is the Template class.
-Create a compiled template object with a template_string, then call render()
-with a context. In the compilation stage, the TemplateSyntaxError exception
-will be raised if the template doesn't have proper syntax.
-
-Sample code:
-
->>> import template
->>> s = '''
-... <html>
-... {% if test %}
-...     <h1>{{ varvalue }}</h1>
-... {% endif %}
-... </html>
-... '''
->>> t = template.Template(s)
-
-(t is now a compiled template, and its render() method can be called multiple
-times with multiple contexts)
-
->>> c = template.Context({'test':True, 'varvalue': 'Hello'})
->>> t.render(c)
-'\n<html>\n\n    <h1>Hello</h1>\n\n</html>\n'
->>> c = template.Context({'test':False, 'varvalue': 'Hello'})
->>> t.render(c)
-'\n<html>\n\n</html>\n'
-"""
-import re
-from django.conf.settings import DEFAULT_CHARSET
-
-__all__ = ('Template','Context','compile_string')
-
-TOKEN_TEXT = 0
-TOKEN_VAR = 1
-TOKEN_BLOCK = 2
-
-# template syntax constants
-FILTER_SEPARATOR = '|'
-FILTER_ARGUMENT_SEPARATOR = ':'
-VARIABLE_ATTRIBUTE_SEPARATOR = '.'
-BLOCK_TAG_START = '{%'
-BLOCK_TAG_END = '%}'
-VARIABLE_TAG_START = '{{'
-VARIABLE_TAG_END = '}}'
-
-ALLOWED_VARIABLE_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'
-
-# match a variable or block tag and capture the entire tag, including start/end delimiters
-tag_re = re.compile('(%s.*?%s|%s.*?%s)' % (re.escape(BLOCK_TAG_START), re.escape(BLOCK_TAG_END),
-                                          re.escape(VARIABLE_TAG_START), re.escape(VARIABLE_TAG_END)))
-
-# global dict used by register_tag; maps custom tags to callback functions
-registered_tags = {}
-
-# global dict used by register_filter; maps custom filters to callback functions
-registered_filters = {}
-
-class TemplateSyntaxError(Exception):
-    pass
-
-class ContextPopException(Exception):
-    "pop() has been called more times than push()"
-    pass
-
-class TemplateDoesNotExist(Exception):
-    pass
-
-class VariableDoesNotExist(Exception):
-    pass
-
-class SilentVariableFailure(Exception):
-    "Any function raising this exception will be ignored by resolve_variable"
-    pass
-
-class Template:
-    def __init__(self, template_string):
-        "Compilation stage"
-        self.nodelist = compile_string(template_string)
-
-    def __iter__(self):
-        for node in self.nodelist:
-            for subnode in node:
-                yield subnode
-
-    def render(self, context):
-        "Display stage -- can be called many times"
-        return self.nodelist.render(context)
-
-def compile_string(template_string):
-    "Compiles template_string into NodeList ready for rendering"
-    tokens = tokenize(template_string)
-    parser = Parser(tokens)
-    return parser.parse()
-
-class Context:
-    "A stack container for variable context"
-    def __init__(self, dict=None):
-        dict = dict or {}
-        self.dicts = [dict]
-
-    def __repr__(self):
-        return repr(self.dicts)
-
-    def __iter__(self):
-        for d in self.dicts:
-            yield d
-
-    def push(self):
-        self.dicts = [{}] + self.dicts
-
-    def pop(self):
-        if len(self.dicts) == 1:
-            raise ContextPopException
-        del self.dicts[0]
-
-    def __setitem__(self, key, value):
-        "Set a variable in the current context"
-        self.dicts[0][key] = value
-
-    def __getitem__(self, key):
-        "Get a variable's value, starting at the current context and going upward"
-        for dict in self.dicts:
-            if dict.has_key(key):
-                return dict[key]
-        return ''
-
-    def __delitem__(self, key):
-        "Delete a variable from the current context"
-        del self.dicts[0][key]
-
-    def has_key(self, key):
-        for dict in self.dicts:
-            if dict.has_key(key):
-                return True
-        return False
-
-    def update(self, other_dict):
-        "Like dict.update(). Pushes an entire dictionary's keys and values onto the context."
-        self.dicts = [other_dict] + self.dicts
-
-class Token:
-    def __init__(self, token_type, contents):
-        "The token_type must be TOKEN_TEXT, TOKEN_VAR or TOKEN_BLOCK"
-        self.token_type, self.contents = token_type, contents
-
-    def __str__(self):
-        return '<%s token: "%s...">' % (
-            {TOKEN_TEXT:'Text', TOKEN_VAR:'Var', TOKEN_BLOCK:'Block'}[self.token_type],
-            self.contents[:20].replace('\n', '')
-            )
-
-def tokenize(template_string):
-    "Return a list of tokens from a given template_string"
-    # remove all empty strings, because the regex has a tendency to add them
-    bits = filter(None, tag_re.split(template_string))
-    return map(create_token, bits)
-
-def create_token(token_string):
-    "Convert the given token string into a new Token object and return it"
-    if token_string.startswith(VARIABLE_TAG_START):
-        return Token(TOKEN_VAR, token_string[len(VARIABLE_TAG_START):-len(VARIABLE_TAG_END)].strip())
-    elif token_string.startswith(BLOCK_TAG_START):
-        return Token(TOKEN_BLOCK, token_string[len(BLOCK_TAG_START):-len(BLOCK_TAG_END)].strip())
-    else:
-        return Token(TOKEN_TEXT, token_string)
-
-class Parser:
-    def __init__(self, tokens):
-        self.tokens = tokens
-
-    def parse(self, parse_until=[]):
-        nodelist = NodeList()
-        while self.tokens:
-            token = self.next_token()
-            if token.token_type == TOKEN_TEXT:
-                nodelist.append(TextNode(token.contents))
-            elif token.token_type == TOKEN_VAR:
-                if not token.contents:
-                    raise TemplateSyntaxError, "Empty variable tag"
-                nodelist.append(VariableNode(token.contents))
-            elif token.token_type == TOKEN_BLOCK:
-                if token.contents in parse_until:
-                    # put token back on token list so calling code knows why it terminated
-                    self.prepend_token(token)
-                    return nodelist
-                try:
-                    command = token.contents.split()[0]
-                except IndexError:
-                    raise TemplateSyntaxError, "Empty block tag"
-                try:
-                    # execute callback function for this tag and append resulting node
-                    nodelist.append(registered_tags[command](self, token))
-                except KeyError:
-                    raise TemplateSyntaxError, "Invalid block tag: '%s'" % command
-        if parse_until:
-            raise TemplateSyntaxError, "Unclosed tag(s): '%s'" % ', '.join(parse_until)
-        return nodelist
-
-    def next_token(self):
-        return self.tokens.pop(0)
-
-    def prepend_token(self, token):
-        self.tokens.insert(0, token)
-
-    def delete_first_token(self):
-        del self.tokens[0]
-
-class FilterParser:
-    """Parse a variable token and its optional filters (all as a single string),
-       and return a list of tuples of the filter name and arguments.
-       Sample:
-            >>> token = 'variable|default:"Default value"|date:"Y-m-d"'
-            >>> p = FilterParser(token)
-            >>> p.filters
-            [('default', 'Default value'), ('date', 'Y-m-d')]
-            >>> p.var
-            'variable'
-
-        This class should never be instantiated outside of the
-        get_filters_from_token helper function.
-    """
-    def __init__(self, s):
-        self.s = s
-        self.i = -1
-        self.current = ''
-        self.filters = []
-        self.current_filter_name = None
-        self.current_filter_arg = None
-        # First read the variable part
-        self.var = self.read_alphanumeric_token()
-        if not self.var:
-            raise TemplateSyntaxError, "Could not read variable name: '%s'" % self.s
-        if self.var.find(VARIABLE_ATTRIBUTE_SEPARATOR + '_') > -1 or self.var[0] == '_':
-            raise TemplateSyntaxError, "Variables and attributes may not begin with underscores: '%s'" % self.var
-        # Have we reached the end?
-        if self.current is None:
-            return
-        if self.current != FILTER_SEPARATOR:
-            raise TemplateSyntaxError, "Bad character (expecting '%s') '%s'" % (FILTER_SEPARATOR, self.current)
-        # We have a filter separator; start reading the filters
-        self.read_filters()
-
-    def next_char(self):
-        self.i = self.i + 1
-        try:
-            self.current = self.s[self.i]
-        except IndexError:
-            self.current = None
-
-    def read_alphanumeric_token(self):
-        """Read a variable name or filter name, which are continuous strings of
-        alphanumeric characters + the underscore"""
-        var = ''
-        while 1:
-            self.next_char()
-            if self.current is None:
-                break
-            if self.current not in ALLOWED_VARIABLE_CHARS:
-                break
-            var += self.current
-        return var
-
-    def read_filters(self):
-        while 1:
-            filter_name, arg = self.read_filter()
-            if not registered_filters.has_key(filter_name):
-                raise TemplateSyntaxError, "Invalid filter: '%s'" % filter_name
-            if registered_filters[filter_name][1] == True and arg is None:
-                raise TemplateSyntaxError, "Filter '%s' requires an argument" % filter_name
-            if registered_filters[filter_name][1] == False and arg is not None:
-                raise TemplateSyntaxError, "Filter '%s' should not have an argument (argument is %r)" % (filter_name, arg)
-            self.filters.append((filter_name, arg))
-            if self.current is None:
-                break
-
-    def read_filter(self):
-        self.current_filter_name = self.read_alphanumeric_token()
-        self.current_filter_arg = None
-        # Have we reached the end?
-        if self.current is None:
-            return (self.current_filter_name, None)
-        # Does the filter have an argument?
-        if self.current == FILTER_ARGUMENT_SEPARATOR:
-            self.current_filter_arg = self.read_arg()
-            return (self.current_filter_name, self.current_filter_arg)
-        # Next thing MUST be a pipe
-        if self.current != FILTER_SEPARATOR:
-            raise TemplateSyntaxError, "Bad character (expecting '%s') '%s'" % (FILTER_SEPARATOR, self.current)
-        return (self.current_filter_name, self.current_filter_arg)
-
-    def read_arg(self):
-        # First read a "
-        self.next_char()
-        if self.current != '"':
-            raise TemplateSyntaxError, "Bad character (expecting '\"') '%s'" % self.current
-        self.escaped = False
-        arg = ''
-        while 1:
-            self.next_char()
-            if self.current == '"' and not self.escaped:
-                break
-            if self.current == '\\' and not self.escaped:
-                self.escaped = True
-                continue
-            if self.current == '\\' and self.escaped:
-                arg += '\\'
-                self.escaped = False
-                continue
-            if self.current == '"' and self.escaped:
-                arg += '"'
-                self.escaped = False
-                continue
-            if self.escaped and self.current not in '\\"':
-                raise TemplateSyntaxError, "Unescaped backslash in '%s'" % self.s
-            if self.current is None:
-                raise TemplateSyntaxError, "Unexpected end of argument in '%s'" % self.s
-            arg += self.current
-        # self.current must now be '"'
-        self.next_char()
-        return arg
-
-def get_filters_from_token(token):
-    "Convenient wrapper for FilterParser"
-    p = FilterParser(token)
-    return (p.var, p.filters)
-
-def resolve_variable(path, context):
-    """
-    Returns the resolved variable, which may contain attribute syntax, within
-    the given context. The variable may be a hard-coded string (if it begins
-    and ends with single or double quote marks).
-
-    >>> c = {'article': {'section':'News'}}
-    >>> resolve_variable('article.section', c)
-    'News'
-    >>> resolve_variable('article', c)
-    {'section': 'News'}
-    >>> class AClass: pass
-    >>> c = AClass()
-    >>> c.article = AClass()
-    >>> c.article.section = 'News'
-    >>> resolve_variable('article.section', c)
-    'News'
-
-    (The example assumes VARIABLE_ATTRIBUTE_SEPARATOR is '.')
-    """
-    if path[0] in ('"', "'") and path[0] == path[-1]:
-        current = path[1:-1]
-    else:
-        current = context
-        bits = path.split(VARIABLE_ATTRIBUTE_SEPARATOR)
-        while bits:
-            try: # dictionary lookup
-                current = current[bits[0]]
-            except (TypeError, AttributeError, KeyError):
-                try: # attribute lookup
-                    current = getattr(current, bits[0])
-                    if callable(current):
-                        if getattr(current, 'alters_data', False):
-                            current = ''
-                        else:
-                            try: # method call (assuming no args required)
-                                current = current()
-                            except SilentVariableFailure:
-                                current = ''
-                            except TypeError: # arguments *were* required
-                                current = '' # invalid method call
-                except (TypeError, AttributeError):
-                    try: # list-index lookup
-                        current = current[int(bits[0])]
-                    except (IndexError, ValueError, KeyError):
-                        raise VariableDoesNotExist, "Failed lookup for key [%s] in %r" % (bits[0], current) # missing attribute
-            del bits[0]
-    return current
-
-def resolve_variable_with_filters(var_string, context):
-    """
-    var_string is a full variable expression with optional filters, like:
-        a.b.c|lower|date:"y/m/d"
-    This function resolves the variable in the context, applies all filters and
-    returns the object.
-    """
-    var, filters = get_filters_from_token(var_string)
-    try:
-        obj = resolve_variable(var, context)
-    except VariableDoesNotExist:
-        obj = ''
-    for name, arg in filters:
-        obj = registered_filters[name][0](obj, arg)
-    return obj
-
-class Node:
-    def render(self, context):
-        "Return the node rendered as a string"
-        pass
-
-    def __iter__(self):
-        yield self
-
-    def get_nodes_by_type(self, nodetype):
-        "Return a list of all nodes (within this node and its nodelist) of the given type"
-        nodes = []
-        if isinstance(self, nodetype):
-            nodes.append(self)
-        if hasattr(self, 'nodelist'):
-            nodes.extend(self.nodelist.get_nodes_by_type(nodetype))
-        return nodes
-
-class NodeList(list):
-    def render(self, context):
-        bits = []
-        for node in self:
-            if isinstance(node, Node):
-                bits.append(node.render(context))
-            else:
-                bits.append(node)
-        return ''.join(bits)
-
-    def get_nodes_by_type(self, nodetype):
-        "Return a list of all nodes of the given type"
-        nodes = []
-        for node in self:
-            nodes.extend(node.get_nodes_by_type(nodetype))
-        return nodes
-
-class TextNode(Node):
-    def __init__(self, s):
-        self.s = s
-
-    def __repr__(self):
-        return "<Text Node: '%s'>" % self.s[:25]
-
-    def render(self, context):
-        return self.s
-
-class VariableNode(Node):
-    def __init__(self, var_string):
-        self.var_string = var_string
-
-    def __repr__(self):
-        return "<Variable Node: %s>" % self.var_string
-
-    def render(self, context):
-        output = resolve_variable_with_filters(self.var_string, context)
-        # Check type so that we don't run str() on a Unicode object
-        if not isinstance(output, basestring):
-            output = str(output)
-        elif isinstance(output, unicode):
-            output = output.encode(DEFAULT_CHARSET)
-        return output
-
-def register_tag(token_command, callback_function):
-    registered_tags[token_command] = callback_function
-
-def unregister_tag(token_command):
-    del registered_tags[token_command]
-
-def register_filter(filter_name, callback_function, has_arg):
-    registered_filters[filter_name] = (callback_function, has_arg)
-
-def unregister_filter(filter_name):
-    del registered_filters[filter_name]
-
-import defaulttags
-import defaultfilters
Index: django/core/defaultfilters.py
===================================================================
--- django/core/defaultfilters.py	(revision 772)
+++ django/core/defaultfilters.py	(working copy)
@@ -1,464 +0,0 @@
-"Default variable filters"
-
-import template, re
-import random as random_module
-
-###################
-# STRINGS         #
-###################
-
-def addslashes(value, _):
-    "Adds slashes - useful for passing strings to JavaScript, for example."
-    return value.replace('"', '\\"').replace("'", "\\'")
-
-def capfirst(value, _):
-    "Capitalizes the first character of the value"
-    value = str(value)
-    return value and value[0].upper() + value[1:]
-
-def fix_ampersands(value, _):
-    "Replaces ampersands with ``&amp;`` entities"
-    from django.utils.html import fix_ampersands
-    return fix_ampersands(value)
-
-def floatformat(text, _):
-    """
-    Displays a floating point number as 34.2 (with one decimal place) - but
-    only if there's a point to be displayed
-    """
-    from math import modf
-    if not text:
-        return ''
-    if modf(float(text))[0] < 0.1:
-        return text
-    return "%.1f" % float(text)
-
-def linenumbers(value, _):
-    "Displays text with line numbers"
-    from django.utils.html import escape
-    lines = value.split('\n')
-    # Find the maximum width of the line count, for use with zero padding string format command
-    width = str(len(str(len(lines))))
-    for i, line in enumerate(lines):
-        lines[i] = ("%0" + width  + "d. %s") % (i + 1, escape(line))
-    return '\n'.join(lines)
-
-def lower(value, _):
-    "Converts a string into all lowercase"
-    return value.lower()
-
-def make_list(value, _):
-    """
-    Returns the value turned into a list. For an integer, it's a list of
-    digits. For a string, it's a list of characters.
-    """
-    return list(str(value))
-
-def slugify(value, _):
-    "Converts to lowercase, removes non-alpha chars and converts spaces to hyphens"
-    value = re.sub('[^\w\s-]', '', value).strip().lower()
-    return re.sub('\s+', '-', value)
-
-def stringformat(value, arg):
-    """
-    Formats the variable according to the argument, a string formatting specifier.
-    This specifier uses Python string formating syntax, with the exception that
-    the leading "%" is dropped.
-
-    See http://docs.python.org/lib/typesseq-strings.html for documentation
-    of Python string formatting
-    """
-    try:
-        return ("%" + arg) % value
-    except (ValueError, TypeError):
-        return ""
-
-def title(value, _):
-    "Converts a string into titlecase"
-    return re.sub("([a-z])'([A-Z])", lambda m: m.group(0).lower(), value.title())
-
-def truncatewords(value, arg):
-    """
-    Truncates a string after a certain number of words
-
-    Argument: Number of words to truncate after
-    """
-    from django.utils.text import truncate_words
-    try:
-        length = int(arg)
-    except ValueError: # invalid literal for int()
-        return value # Fail silently.
-    if not isinstance(value, basestring):
-        value = str(value)
-    return truncate_words(value, length)
-
-def upper(value, _):
-    "Converts a string into all uppercase"
-    return value.upper()
-
-def urlencode(value, _):
-    "Escapes a value for use in a URL"
-    import urllib
-    return urllib.quote(value)
-
-def urlize(value, _):
-    "Converts URLs in plain text into clickable links"
-    from django.utils.html import urlize
-    return urlize(value, nofollow=True)
-
-def urlizetrunc(value, limit):
-    """
-    Converts URLs into clickable links, truncating URLs to the given character limit
-
-    Argument: Length to truncate URLs to.
-    """
-    from django.utils.html import urlize
-    return urlize(value, trim_url_limit=int(limit), nofollow=True)
-
-def wordcount(value, _):
-    "Returns the number of words"
-    return len(value.split())
-
-def wordwrap(value, arg):
-    """
-    Wraps words at specified line length
-
-    Argument: number of words to wrap the text at.
-    """
-    from django.utils.text import wrap
-    return wrap(value, int(arg))
-
-def ljust(value, arg):
-    """
-    Left-aligns the value in a field of a given width
-
-    Argument: field size
-    """
-    return str(value).ljust(int(arg))
-
-def rjust(value, arg):
-    """
-    Right-aligns the value in a field of a given width
-
-    Argument: field size
-    """
-    return str(value).rjust(int(arg))
-
-def center(value, arg):
-    "Centers the value in a field of a given width"
-    return str(value).center(int(arg))
-
-def cut(value, arg):
-    "Removes all values of arg from the given string"
-    return value.replace(arg, '')
-
-###################
-# HTML STRINGS    #
-###################
-
-def escape(value, _):
-    "Escapes a string's HTML"
-    from django.utils.html import escape
-    return escape(value)
-
-def linebreaks(value, _):
-    "Converts newlines into <p> and <br />s"
-    from django.utils.html import linebreaks
-    return linebreaks(value)
-
-def linebreaksbr(value, _):
-    "Converts newlines into <br />s"
-    return value.replace('\n', '<br />')
-
-def removetags(value, tags):
-    "Removes a space separated list of [X]HTML tags from the output"
-    tags = [re.escape(tag) for tag in tags.split()]
-    tags_re = '(%s)' % '|'.join(tags)
-    starttag_re = re.compile('<%s(>|(\s+[^>]*>))' % tags_re)
-    endtag_re = re.compile('</%s>' % tags_re)
-    value = starttag_re.sub('', value)
-    value = endtag_re.sub('', value)
-    return value
-
-def striptags(value, _):
-    "Strips all [X]HTML tags"
-    from django.utils.html import strip_tags
-    if not isinstance(value, basestring):
-        value = str(value)
-    return strip_tags(value)
-
-###################
-# LISTS           #
-###################
-
-def dictsort(value, arg):
-    """
-    Takes a list of dicts, returns that list sorted by the property given in
-    the argument.
-    """
-    decorated = [(template.resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
-    decorated.sort()
-    return [item[1] for item in decorated]
-
-def dictsortreversed(value, arg):
-    """
-    Takes a list of dicts, returns that list sorted in reverse order by the
-    property given in the argument.
-    """
-    decorated = [(template.resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
-    decorated.sort()
-    decorated.reverse()
-    return [item[1] for item in decorated]
-
-def first(value, _):
-    "Returns the first item in a list"
-    try:
-        return value[0]
-    except IndexError:
-        return ''
-
-def join(value, arg):
-    "Joins a list with a string, like Python's ``str.join(list)``"
-    try:
-        return arg.join(map(str, value))
-    except AttributeError: # fail silently but nicely
-        return value
-
-def length(value, _):
-    "Returns the length of the value - useful for lists"
-    return len(value)
-
-def length_is(value, arg):
-    "Returns a boolean of whether the value's length is the argument"
-    return len(value) == int(arg)
-
-def random(value, _):
-    "Returns a random item from the list"
-    return random_module.choice(value)
-
-def slice_(value, arg):
-    """
-    Returns a slice of the list.
-
-    Uses the same syntax as Python's list slicing; see
-    http://diveintopython.org/native_data_types/lists.html#odbchelper.list.slice
-    for an introduction.
-    """
-    try:
-        return value[slice(*[x and int(x) or None for x in arg.split(':')])]
-    except (ValueError, TypeError):
-        return value # Fail silently.
-
-def unordered_list(value, _):
-    """
-    Recursively takes a self-nested list and returns an HTML unordered list --
-    WITHOUT opening and closing <ul> tags.
-
-    The list is assumed to be in the proper format. For example, if ``var`` contains
-    ``['States', [['Kansas', [['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]]``,
-    then ``{{ var|unordered_list }}`` would return::
-
-        <li>States
-        <ul>
-                <li>Kansas
-                <ul>
-                        <li>Lawrence</li>
-                        <li>Topeka</li>
-                </ul>
-                </li>
-                <li>Illinois</li>
-        </ul>
-        </li>
-    """
-    def _helper(value, tabs):
-        indent = '\t' * tabs
-        if value[1]:
-            return '%s<li>%s\n%s<ul>\n%s\n%s</ul>\n%s</li>' % (indent, value[0], indent,
-                '\n'.join([unordered_list(v, tabs+1) for v in value[1]]), indent, indent)
-        else:
-            return '%s<li>%s</li>' % (indent, value[0])
-    return _helper(value, 1)
-
-###################
-# INTEGERS        #
-###################
-
-def add(value, arg):
-    "Adds the arg to the value"
-    return int(value) + int(arg)
-
-def get_digit(value, arg):
-    """
-    Given a whole number, returns the requested digit of it, where 1 is the
-    right-most digit, 2 is the second-right-most digit, etc. Returns the
-    original value for invalid input (if input or argument is not an integer,
-    or if argument is less than 1). Otherwise, output is always an integer.
-    """
-    try:
-        arg = int(arg)
-        value = int(value)
-    except ValueError:
-        return value # Fail silently for an invalid argument
-    if arg < 1:
-        return value
-    try:
-        return int(str(value)[-arg])
-    except IndexError:
-        return 0
-
-###################
-# DATES           #
-###################
-
-def date(value, arg):
-    "Formats a date according to the given format"
-    from django.utils.dateformat import format
-    return format(value, arg)
-
-def time(value, arg):
-    "Formats a time according to the given format"
-    from django.utils.dateformat import time_format
-    return time_format(value, arg)
-
-def timesince(value, _):
-    'Formats a date as the time since that date (i.e. "4 days, 6 hours")'
-    from django.utils.timesince import timesince
-    return timesince(value)
-
-###################
-# LOGIC           #
-###################
-
-def default(value, arg):
-    "If value is unavailable, use given default"
-    return value or arg
-
-def default_if_none(value, arg):
-    "If value is None, use given default"
-    if value is None:
-        return arg
-    return value
-
-def divisibleby(value, arg):
-    "Returns true if the value is devisible by the argument"
-    return int(value) % int(arg) == 0
-
-def yesno(value, arg):
-    """
-    Given a string mapping values for true, false and (optionally) None,
-    returns one of those strings accoding to the value:
-
-    ==========  ======================  ==================================
-    Value       Argument                Outputs
-    ==========  ======================  ==================================
-    ``True``    ``"yeah,no,maybe"``     ``yeah``
-    ``False``   ``"yeah,no,maybe"``     ``no``
-    ``None``    ``"yeah,no,maybe"``     ``maybe``
-    ``None``    ``"yeah,no"``           ``"no"`` (converts None to False
-                                        if no mapping for None is given.
-    ==========  ======================  ==================================
-   """
-    bits = arg.split(',')
-    if len(bits) < 2:
-        return value # Invalid arg.
-    try:
-        yes, no, maybe = bits
-    except ValueError: # unpack list of wrong size (no "maybe" value provided)
-        yes, no, maybe = bits[0], bits[1], bits[1]
-    if value is None:
-        return maybe
-    if value:
-        return yes
-    return no
-
-###################
-# MISC            #
-###################
-
-def filesizeformat(bytes, _):
-    """
-    Format the value like a 'human-readable' file size (i.e. 13 KB, 4.1 MB, 102
-    bytes, etc).
-    """
-    bytes = float(bytes)
-    if bytes < 1024:
-        return "%d byte%s" % (bytes, bytes != 1 and 's' or '')
-    if bytes < 1024 * 1024:
-        return "%.1f KB" % (bytes / 1024)
-    if bytes < 1024 * 1024 * 1024:
-        return "%.1f MB" % (bytes / (1024 * 1024))
-    return "%.1f GB" % (bytes / (1024 * 1024 * 1024))
-
-def pluralize(value, _):
-    "Returns 's' if the value is not 1, for '1 vote' vs. '2 votes'"
-    try:
-        if int(value) != 1:
-            return 's'
-    except ValueError: # invalid string that's not a number
-        pass
-    except TypeError: # value isn't a string or a number; maybe it's a list?
-        try:
-            if len(value) != 1:
-                return 's'
-        except TypeError: # len() of unsized object
-            pass
-    return ''
-
-def phone2numeric(value, _):
-    "Takes a phone number and converts it in to its numerical equivalent"
-    from django.utils.text import phone2numeric
-    return phone2numeric(value)
-
-def pprint(value, _):
-    "A wrapper around pprint.pprint -- for debugging, really"
-    from pprint import pformat
-    return pformat(value)
-
-# Syntax: template.register_filter(name of filter, callback, has_argument)
-template.register_filter('add', add, True)
-template.register_filter('addslashes', addslashes, False)
-template.register_filter('capfirst', capfirst, False)
-template.register_filter('center', center, True)
-template.register_filter('cut', cut, True)
-template.register_filter('date', date, True)
-template.register_filter('default', default, True)
-template.register_filter('dictsort', dictsort, True)
-template.register_filter('dictsortreversed', dictsortreversed, True)
-template.register_filter('divisibleby', divisibleby, True)
-template.register_filter('escape', escape, False)
-template.register_filter('filesizeformat', filesizeformat, False)
-template.register_filter('first', first, False)
-template.register_filter('fix_ampersands', fix_ampersands, False)
-template.register_filter('floatformat', floatformat, False)
-template.register_filter('get_digit', get_digit, True)
-template.register_filter('join', join, True)
-template.register_filter('length', length, False)
-template.register_filter('length_is', length_is, True)
-template.register_filter('linebreaks', linebreaks, False)
-template.register_filter('linebreaksbr', linebreaksbr, False)
-template.register_filter('linenumbers', linenumbers, False)
-template.register_filter('ljust', ljust, True)
-template.register_filter('lower', lower, False)
-template.register_filter('make_list', make_list, False)
-template.register_filter('phone2numeric', phone2numeric, False)
-template.register_filter('pluralize', pluralize, False)
-template.register_filter('pprint', pprint, False)
-template.register_filter('removetags', removetags, True)
-template.register_filter('random', random, False)
-template.register_filter('rjust', rjust, True)
-template.register_filter('slice', slice_, True)
-template.register_filter('slugify', slugify, False)
-template.register_filter('stringformat', stringformat, True)
-template.register_filter('striptags', striptags, False)
-template.register_filter('time', time, True)
-template.register_filter('timesince', timesince, False)
-template.register_filter('title', title, False)
-template.register_filter('truncatewords', truncatewords, True)
-template.register_filter('unordered_list', unordered_list, False)
-template.register_filter('upper', upper, False)
-template.register_filter('urlencode', urlencode, False)
-template.register_filter('urlize', urlize, False)
-template.register_filter('urlizetrunc', urlizetrunc, True)
-template.register_filter('wordcount', wordcount, False)
-template.register_filter('wordwrap', wordwrap, True)
-template.register_filter('yesno', yesno, True)
Index: django/core/template/defaultfilters.py
===================================================================
--- django/core/template/defaultfilters.py	(revision 0)
+++ django/core/template/defaultfilters.py	(working copy)
@@ -1,6 +1,8 @@
 "Default variable filters"
 
-import template, re
+from django.core.template import resolve_variable
+# from django.core import template
+import re
 import random as random_module
 
 ###################
Index: django/core/template/loaders/__init__.py
===================================================================
Index: django/core/template/defaulttags.py
===================================================================
--- django/core/template/defaulttags.py	(revision 0)
+++ django/core/template/defaulttags.py	(working copy)
@@ -1,7 +1,7 @@
 "Default tags used by the template system, available to all templates."
 
+from django.core import template
 import sys
-import template
 
 class CommentNode(template.Node):
     def render(self, context):
@@ -434,9 +434,9 @@
         ==========================  ================================================
         ``forloop.counter``         The current iteration of the loop (1-indexed)
         ``forloop.counter0``        The current iteration of the loop (0-indexed)
-        ``forloop.revcounter``      The number of iterations from the end of the 
+        ``forloop.revcounter``      The number of iterations from the end of the
                                     loop (1-indexed)
-        ``forloop.revcounter0``     The number of iterations from the end of the 
+        ``forloop.revcounter0``     The number of iterations from the end of the
                                     loop (0-indexed)
         ``forloop.first``           True if this is the first time through the loop
         ``forloop.last``            True if this is the last time through the loop
