Index: /Trac/Macros/trunk/AddComment.py
===================================================================
--- /Trac/Macros/trunk/AddComment.py	(revision 5)
+++ /Trac/Macros/trunk/AddComment.py	(revision 5)
@@ -0,0 +1,88 @@
+# vim: expandtab
+from trac.Wiki import WikiPage
+import trac.perm
+import time
+from StringIO import StringIO
+from trac.WikiFormatter import wiki_to_html
+from trac.util import TracError
+import re
+
+def execute(hdf, args, env):
+    authname = hdf.getValue("trac.authname", "anonymous")
+    db = env.get_db_cnx()
+    perm = trac.perm.PermissionCache(db, authname)
+    pagename = hdf.getValue("args.page", "WikiStart")
+    page = WikiPage(pagename, None, perm, db)
+    wikipreview = hdf.getValue("args.preview", "")
+    appendonly = (args == 'appendonly')
+    readonlypage = int(hdf.getValue("wiki.readonly", "0"))
+    # Can this user add a comment to this page?
+    cancomment = not readonlypage
+    # Is this an "append-only" comment or are we an administrator?
+    if perm.has_permission(trac.perm.WIKI_ADMIN) or appendonly:
+        cancomment = True
+
+    if not cancomment:
+        raise TracError('Error: Insufficient privileges to AddComment')
+
+    disabled = ''
+    comment = hdf.getValue("args.addcomment", "")
+    preview = hdf.getValue("args.previewaddcomment", "")
+    cancel = hdf.getValue("args.canceladdcomment", "")
+    submit = hdf.getValue("args.submitaddcomment", "")
+    if not cancel:
+        authname = hdf.getValue("args.authoraddcomment", authname)
+
+    # Ensure [[AddComment]] is not present in comment, so that infinite
+    # recursion does not occur.
+    comment = re.sub('(^|[^!])(\[\[AddComment)', '\\1!\\2', comment)
+
+    out = StringIO()
+    if wikipreview or not perm.has_permission(trac.perm.WIKI_MODIFY):
+        disabled = ' disabled="disabled"'
+
+    # If we are submitting or previewing, inject comment as it should look
+    if cancomment and comment and (preview or submit):
+        if preview:
+            out.write("<div class='wikipage' id='preview'>\n")
+        out.write("<h4 id='commentpreview'>Comment by %s on %s</h4>\n<p>\n%s\n</p>\n" % (authname, time.strftime('%c', time.localtime()), wiki_to_html(comment, hdf, env, db)))
+        if preview:
+            out.write("</div>\n")
+
+    # When submitting, inject comment before macro
+    if comment and submit:
+        submitted = False
+        newtext = StringIO()
+        for line in page.text.splitlines():
+            if line.find('[[AddComment') == 0:
+                newtext.write("==== Comment by %s on %s ====\n%s\n\n" % (authname, time.strftime('%c', time.localtime()), comment))
+                submitted = True
+            newtext.write(line + "\n")
+        if submitted:
+            # XXX Is this the dodigest hack ever? This is needed in 
+            # "appendonly" mode when the page is readonly. XXX
+            if appendonly:
+                perm.expand_meta_permission('WIKI_ADMIN');
+            page.set_content(newtext.getvalue())
+            # TODO: How do we get remote_addr from a macro?
+            page.commit(authname, 'Comment added', None)
+            comment = ""
+        else:
+            out.write("<div class='system-message'><strong>ERROR: [[AddComment]] macro call must be the only content on its line. Could not add comment.</strong></div>\n")
+
+    out.write("<form action='%s#commentpreview' method='post'>\n" % env.href.wiki(pagename))
+    out.write("<fieldset>\n<legend>Add comment</legend>\n")
+    out.write("<div class='field'>\n<textarea id='addcomment' name='addcomment' cols='80' rows='5'%s>" % disabled)
+    if wikipreview:
+        out.write("Page preview...")
+    elif not cancel:
+        out.write(comment)
+    out.write("</textarea>\n")
+    out.write("</div>\n")
+    out.write('<div class="field">\n<label for="authoraddcomment">Your email or username:</label>\n<br/><input id="authoraddcomment" type="text" name="authoraddcomment" size="30" value="%s" />\n</div>' % authname)
+    out.write("<div class='field'>\n<input size='30' type='submit' name='submitaddcomment' value='Add comment'%s/>\n" % disabled)
+    out.write("<input type='submit' name='previewaddcomment' value='Preview comment'%s/>\n" % disabled)
+    out.write("<input type='submit' name='canceladdcomment' value='Cancel'%s/>\n</div>\n" % disabled)
+    out.write("<script type='text/javascript'>\naddWikiFormattingToolbar(document.getElementById('addcomment'));\n</script>\n")
+    out.write("</fieldset>\n</form>\n")
+    return out.getvalue()# + "<pre>" + hdf.dump() + "</pre>"
Index: /Trac/Macros/trunk/BackLinks.py
===================================================================
--- /Trac/Macros/trunk/BackLinks.py	(revision 5)
+++ /Trac/Macros/trunk/BackLinks.py	(revision 5)
@@ -0,0 +1,40 @@
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    cursor = db.cursor()
+
+    thispage = None
+
+    if args:
+        thispage = args.replace('\'', '\'\'')
+    else :
+	thispage = hdf.getValue('wiki.page_name', '')
+
+
+    sql = 'SELECT w1.name FROM wiki w1, ' + \
+          '(SELECT name, MAX(version) AS VERSION FROM WIKI GROUP BY NAME) w2 ' + \
+          'WHERE w1.version = w2.version AND w1.name = w2.name '
+
+    if thispage:
+	    sql += 'AND w1.text LIKE \'%%[wiki:%s %%\' ' % thispage
+
+    cursor.execute(sql)
+
+    buf = StringIO()
+
+    buf.write('Pages linking to %s:\n' % thispage)
+    buf.write('<ul>')
+
+    while 1:
+        row = cursor.fetchone()
+        if row == None:
+            break
+        if row[0] != thispage:
+            buf.write('<li><a href="%s">' % env.href.wiki(row[0]))
+            buf.write(row[0])
+            buf.write('</a></li>\n')
+
+    buf.write('</ul>')
+
+    return buf.getvalue()
Index: /Trac/Macros/trunk/Blog.py
===================================================================
--- /Trac/Macros/trunk/Blog.py	(revision 5)
+++ /Trac/Macros/trunk/Blog.py	(revision 5)
@@ -0,0 +1,129 @@
+"""
+Blog macro 0.1-alpha
+Usage sample 1: [[Blog(blog/%)]]
+Usage sample 2: [[Blog(2004%,blog/%)]]
+
+"""
+
+from StringIO import StringIO
+import re,time
+import string
+from trac.WikiFormatter import *
+
+month_abbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+
+def execute(hdf, args, env):
+    if hdf.getValue('macro.blog.rendering', '0') == '1':
+        return ""
+    hdf.setValue('macro.blog.rendering', '1')
+    
+    pagename = hdf.getValue("args.page", "WikiStart")
+    
+    # we can accept two optional parameters: year and month, if not provided, will use today's
+    timeToday = time.localtime()
+    year = int(hdf.getValue("args.year", str(timeToday.tm_year)))
+    month = int(hdf.getValue("args.month", str(timeToday.tm_mon)))
+    
+    db = env.get_db_cnx()
+    formatter = Formatter(hdf, env, db)
+    
+    years = {}
+    # years = {
+    #    2004: {
+    #       1: 1,
+    #       2: 3,
+    #    },
+    #    2005: {
+    #       2: 4,
+    #       3: 3,
+    #    },
+    # }
+    
+    out1 = StringIO()   # the TOC
+    #~ out1.write('<p>Blog of %d/%d</p>' % (year, month))
+    out1.write('<a name="toc"></a><ul>')
+    
+    out2 = StringIO()   # the body
+    bIndex = 0
+    
+    for blogPattern in args.split(','):
+        blogPattern = blogPattern.strip()
+        sql = "SELECT DISTINCT name from wiki where name like '%s' order by time desc" % blogPattern
+        csName = db.cursor()   # the matched wiki name
+        csName.execute(sql)
+        while 1:
+            rowName = csName.fetchone()
+            if rowName == None:
+                break
+            
+            name = rowName[0]
+                
+            sql = "SELECT text,time,author from wiki where name = '%s' order by version desc limit 1" % name
+            csText = db.cursor()    # the wiki text and time and author
+            csText.execute(sql)
+            while 1:
+                rowText = csText.fetchone()
+                if rowText == None:
+                    break
+                
+                timeParts = time.localtime(rowText[1])
+                if not timeParts.tm_year in years.keys():
+                    years[timeParts.tm_year] = {timeParts.tm_mon: 1}
+                else:
+                    if not timeParts.tm_mon in years[timeParts.tm_year].keys():
+                        years[timeParts.tm_year][timeParts.tm_mon] = 1
+                    else:
+                        years[timeParts.tm_year][timeParts.tm_mon] += 1
+                    
+                if timeParts.tm_year != year or timeParts.tm_mon != month:
+                    break
+                    
+                text = rowText[0]
+                timeStr = time.ctime(rowText[1])
+                author = rowText[2]
+                out3 = StringIO()   # the rendered output of current wiki
+                #~ env.log.debug('rendering %s' % pagename)
+                formatter.format(text, out3)
+                text = out3.getvalue()
+                out3 = None
+                
+                # get the wiki title from its output
+                matchedTitle = re.search(r"<(h\d+).*?>(.*?)</\1>", text)
+                title = name
+                if matchedTitle != None:
+                    title = string.strip(matchedTitle.group(2))
+                    
+                bIndex+=1
+                out1.write('<li><a name="t%d"></a><a href="#b%d">%s</a></li>' % (bIndex, bIndex, title))
+                
+                out2.write('<a name="b%d"></a>' % bIndex)
+                out2.write('<div class="nav"><ul>')
+                out2.write('<li><a href="%s">%s</a></li>' % (env.href.wiki(name), title))
+                out2.write('<li>%s</li>' % author)
+                out2.write('<li>%s</li>' % timeStr)
+                out2.write('<li><a href="#t%d">top</a></li>'  % bIndex)
+                out2.write('</ul></div>')
+                
+                
+                out2.write(text)
+    out1.write('</ul>')
+    
+    out = StringIO()
+    #~ out.write('<p>Blog by Date:</p>')
+    out.write('<ul>')
+    ykeys = years.keys()
+    ykeys.sort()
+    ykeys.reverse()
+    for y in ykeys:
+        out.write('<li>%d:' % y)
+        for m in years[y].keys():
+            if y == year and m == month:
+                out.write('&nbsp;%s(%d)' % (month_abbr[m-1], years[y][m]))
+            else:
+                shref = '<a href="%s?year=%d&month=%d">' % (env.href.wiki(pagename), y, m)
+                out.write('&nbsp;%s%s</a>(%s%d</a>)' % (shref, month_abbr[m-1], shref, years[y][m]))
+        out.write('</li>')
+    out.write('</ul>')
+    out.write(out1.getvalue())
+    out.write(out2.getvalue())
+    return out.getvalue()
Index: /Trac/Macros/trunk/DateOffset.py
===================================================================
--- /Trac/Macros/trunk/DateOffset.py	(revision 5)
+++ /Trac/Macros/trunk/DateOffset.py	(revision 5)
@@ -0,0 +1,51 @@
+# Author: Muness Alrubaie
+# Last Modified: 2004-12-21
+#
+# Copyright 2004 Muness Alrubaie
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may 
+# not use this file except in compliance with the License. 
+# You may obtain a copy of the License at 
+#    http://www.apache.org/licenses/LICENSE-2.0 
+#
+# Unless required by applicable law or agreed to in writing, software 
+# distributed under the License is distributed on an "AS IS" BASIS, 
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+# See the License for the specific language governing permissions and 
+# limitations under the License.
+#
+#
+# Returns the date referred to as follows:
+# First arg is the offset, i.e. the date to start from
+# Second arg is the multiplier to multiply the count by (e.g. 7 for a week)
+# Third arg is the count (i.e. the number of additions to make).
+#
+# So, for example
+# [[DateOffset(2005/01/05,7,0)]] retuns Wed Jan Wed Jan 05
+# [[DateOffset(2005/01/05,7,4)]] returns Wed Feb 02
+#
+# You can also configure the input and output date formats.  
+# (See http://python.org/doc/2.3.4/lib/module-time.html)
+# e.g. [[DateOffset(2005/01/05,7,0,%Y/%m/%d,%A %B %d)]] returns Wednesday January 05
+
+import time
+
+def execute(hdf, txt, env):
+    args=txt.split(',',4)
+    offset=args[0]
+    multiplier=args[1]
+    count=args[2]
+    if len(args) > 3:
+        infmt=args[3]
+        outfmt=args[4]
+    else:
+        infmt = "%Y/%m/%d"
+        outfmt = "%a %b %d"
+    
+    startdate = time.mktime(time.strptime(offset,infmt))
+    
+    sec_per_day = 24 * 60 * 60
+    days = int(multiplier) * int(count)
+    secs = sec_per_day * days
+    
+    return time.strftime(outfmt, time.localtime(startdate + secs))
Index: /Trac/Macros/trunk/FootNote.py
===================================================================
--- /Trac/Macros/trunk/FootNote.py	(revision 5)
+++ /Trac/Macros/trunk/FootNote.py	(revision 5)
@@ -0,0 +1,40 @@
+from StringIO import StringIO
+from trac.util import escape
+from trac.WikiFormatter import wiki_to_oneliner
+
+def unescape(text):
+	"""Un-escapes &, <, > and \""""
+	if not text:
+		return ''
+	return str(text).replace('&amp;', '&') \
+		.replace('&lt;', '<') \
+		.replace('&gt;', '>') \
+		.replace('&#34;', '"')
+
+footnote_set = 1
+footnotes = []
+
+def execute(hdf, args, env):
+	global footnotes, footnote_set
+	# Display and clear footnotes...
+	if not args:
+		out = StringIO()
+		out.write('<div class="footnotes">\n');
+		out.write('<hr style="width: 10%; padding: 0; margin: 2em 0 1em 0;"/>\n');
+		out.write('<ol style="padding: 0 0 0 1em; margin: 0;">\n')
+		for i, v in enumerate(footnotes):
+			id = "%i.%i" % (footnote_set, i + 1)
+			out.write('<li style="list-style: none;" id="FootNote%s"><a style="font-weight: bold;" href="#FootNoteRef%s">%i.</a> %s</li>\n' % (id, id, i + 1, wiki_to_oneliner(unescape(v), hdf, env, env.get_db_cnx())))
+		out.write('</ol>\n')
+		out.write('</div>\n');
+		footnotes = []
+		footnote_set += 1
+		return out.getvalue()
+	else:
+		id = len(footnotes) + 1
+		try:
+			id = int(args)
+		except ValueError:
+			footnotes.append(args)
+		full_id = "%i.%i" % (footnote_set, id)
+		return '<sup><a style="font-size: 8pt; font-weight: bold;" id="FootNoteRef%s" href="#FootNote%s">%i</a></sup>' % (full_id, full_id, id)
Index: /Trac/Macros/trunk/Image.py
===================================================================
--- /Trac/Macros/trunk/Image.py	(revision 5)
+++ /Trac/Macros/trunk/Image.py	(revision 5)
@@ -0,0 +1,124 @@
+"""
+Display image in attachment or repository onto the wiki page.
+You can use this macro in wiki or ticket module.
+First argument is filename (file spec).
+Rest of optional arguments are attribute/style string of IMG element.
+If it is digits and unit, treat as size (ex. 120, 25%) of IMG.
+If it is 'right', 'left', 'top' or 'bottom', treat as align of IMG.
+if it is key=value style, treat as attribute of IMG.
+if it is key:value style, treat as style of IMG.
+
+Ex.
+  [[Image(photo.jpg)]]                          # simplest
+  [[Image(photo.jpg,120px)]]                    # with size
+  [[Image(photo.jpg,right)]]                    # aligned by keyword
+  [[Image(photo.jpg,align=right)]]              # aligned by attribute
+  [[Image(photo.jpg,float:right)]]              # aligned by style
+  [[Image(photo.jpg,border:solid 5px green)]]   # with any style
+
+You can use image from other page, other ticket or other module.
+  [[Image(OtherPage/foo.bmp)]]    # if current module is wiki
+  [[Image(base/sub/bar.bmp)]]     # from hierarchical wiki page
+  [[Image(3/baz.bmp)]]            # if in a ticket, point to #3
+  [[Image(ticket/36/boo.jpg)]]
+  [[Image(file/images/bee.jpg)]]
+  
+"""
+
+import os
+import re
+import string
+
+from  trac.util import escape
+
+def execute(hdf, txt, env):
+    # args will be null if the macro is called without parentesis.
+    if not txt:
+        return ''
+    # parse arguments
+    # we expect 1st arguemnt is filename (filespec)
+    args = txt.split(',')
+    if len(args) == 0:
+        raise Exception("No argument.")
+    file = args[0]
+    size_re = re.compile('^[0-9]+%?$')
+    align_re = re.compile('^(?:left|right|top|bottom)$')
+    keyval_re = re.compile('^([-a-z0-9]+)([=:])(.*)')
+    quoted_re = re.compile("^(?:&#34;|')(.*)(?:&#34;|')$")
+    attr = {}
+    style = {}
+    for arg in args[1:]:
+        arg = arg.strip()
+        if size_re.search(arg):
+            # 'width' keyword
+            attr['width'] = arg
+            continue
+        if align_re.search(arg):
+            # 'align' keyword
+            attr['align'] = arg
+            continue
+        match = keyval_re.search(arg)
+        if match:
+            key = match.group(1)
+            sep = match.group(2)
+            val = match.group(3)
+            m = quoted_re.search(val) # unquote &#34; character "
+            if m:
+                val = m.group(1)
+            if sep == '=':
+                attr[key] = val;
+            elif sep == ':':
+                style[key] = val
+
+    # get current module and id from hdf
+    module = hdf.getValue('args.mode', 'wiki')
+    if module == 'wiki':
+        id = hdf.getValue('args.page', 'WikiStart')
+    elif module == 'ticket':
+        id = hdf['args.id'] # for ticket
+    else:
+        # limit of use
+        raise Exception('Cannot use this macro in %s module' % module)
+    # parse file argument to get module and id if contained.
+    # we allow 'file', 'id/file', 'module/id/file' format.
+    # id can be dir/dir/node.
+    # module can be 'wiki', 'ticket' or 'file'
+    # if for file module id (means path) can be omitted.
+    parts = file.split('/')
+    file = parts.pop() # anyway, last one is filename
+    if 0 < len(parts):
+        if parts[0] in ['wiki', 'ticket', 'file']:
+            # full spec
+            id = string.join(parts[1:], '/')
+            module = parts[0]
+        else:
+            # module name is not speciifed
+            id = string.join(parts, '/')
+    if module == 'file':
+        path = "%s/%s" % (id, file)
+        url = env.href.file(path)
+        raw_url = env.href.file(path, format='raw')
+        desc = file
+    else:
+        url = env.href.attachment(module, id, file)
+        raw_url = env.href.attachment(module, id, file, 'raw')
+        # get description for file from db.
+        cnx = env.get_db_cnx()
+        cursor = cnx.cursor()
+        cursor.execute("SELECT description from attachment where type='%s' and id='%s' and filename='%s'" % (module, id, file))
+        row = cursor.fetchone()
+        if row:
+            desc = row[0]
+        else:
+            raise Exception("Attachment is missed: module=%s, id=%s, file=%s" %(module, id, file))
+
+    for key in ['title', 'alt']:
+        if desc and not attr.has_key(key):
+            attr[key] = desc
+    a_style = 'padding:0; border:none' # style of anchor
+    img_attr = string.join(map(lambda x: '%s="%s"' % x, attr.iteritems()),
+                           ' ')
+    img_style = string.join(map(lambda x: "%s:%s" % x, style.iteritems()),
+                            ' ')
+    return "<a href='%s' style='%s'><img src='%s' %s style=\"%s\" /></a>" % (
+        url, a_style, raw_url, img_attr, img_style)
Index: /Trac/Macros/trunk/Include.py
===================================================================
--- /Trac/Macros/trunk/Include.py	(revision 5)
+++ /Trac/Macros/trunk/Include.py	(revision 5)
@@ -0,0 +1,67 @@
+"""
+We take an argument which is a file to go get.	The second argument is going to be None, or wiki at this point.
+
+do we include it, and then parse it thru the wiki formatter or not?
+
+url, can be a special case 'trunk' and it will grab from the local svn repository.
+
+a couple of examples:
+
+This will do no formatting on the url.
+[[Include(http://www.yuma.ca/tech/license.html,None)]]
+
+This will get the url, and do the Trac wiki formatting on it.
+[[Include(http://www.yuma.ca/tech/license.html,wiki)]]
+
+This will get the file out of the local SVN Repository(latest revision only).
+[[Include(trunk/needs_document/Employee/employee_file.txt,wiki)]]
+
+Theoretically you can modify this to handle more formatters, but I haven't the need so I stopped.
+
+If you include Arguments, you MUST include both.  Sorry I'm lazy.
+
+"""
+
+from trac import util
+from trac.WikiFormatter import wiki_to_html
+from StringIO import StringIO
+import os
+import urllib
+
+def execute(hdf, args, env):
+	# Args seperated by commas:
+	# url, formatter
+	#
+	# url is the url to go get.
+	# Formatter is which formatter if any to parse.	 Default: None
+	_href = env.abs_href or env.href
+	formatter = None
+	url = None
+	db = env.get_db_cnx()
+	cursor = db.cursor()
+	cs = db.cursor()
+	buf = StringIO()
+
+	currentpage =  hdf.getValue('wiki.page_name', '') + '/'
+	if args:
+		args = args.replace('\'', '\'\'')
+	args = args.split(',')
+	if args[0] != 'None':
+		url = args[0]
+	if args[1] != 'None':
+		formatter = args[1]
+	if url[:5] == 'trunk':
+		# we need to get the file from the svn repo.
+		#http://financial.trac.yumaed.org/trac.cgi/file/trunk/needs_document/Employee/employee_file.txt?format=raw
+		url = 'http://' + os.getenv('HTTP_HOST') + env.href.base + '/file/' +  url + '?format=raw'
+	try:
+            f = urllib.urlopen(url)
+        except:
+            raise util.TracError('The "%s" argument doesnt seem to be a valid link' % (args))
+			#buf.write('<P>bad url: ')
+			#buf.write(url)
+	txt = f.read()
+	if formatter == 'wiki':
+		txt = wiki_to_html(txt,hdf,env,db,0)
+	buf.write(txt)
+	return buf.getvalue()
Index: /Trac/Macros/trunk/LastModified.py
===================================================================
--- /Trac/Macros/trunk/LastModified.py	(revision 5)
+++ /Trac/Macros/trunk/LastModified.py	(revision 5)
@@ -0,0 +1,102 @@
+# Author: Steven N. Severinghaus <sns@severinghaus.org>
+# Last Modified: 2004-11-30
+#
+# Copyright (C) 2004 Steven N. Severinghaus <sns@severinghaus.org>
+#
+# The LastModified macro is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 2 of the License, or (at
+# your option) any later version.
+#
+# Created for the BFGFF project, http://chimp.acm.uiuc.edu/
+#
+# Shows the last modification date of the specified page, or the page the
+# macro appears in if not specified. An optional argument,  delta, can be
+# given to show the time elapsed since the last modification. The output is
+# placed in span with a title that gives the exact modification date and
+# the author of the change.
+#
+# For example, [[LastModified(CustomMacros)]] produces:
+#   <span class="last-modified" title="Wed Oct  6 20:34:51 2004 by sevrnghs">2004-10-06</span>
+#
+# Alternatively, [[LastModified(CustomMacros,delta)]] produces:
+#   <span class="last-modified" title="Wed Oct  6 20:34:51 2004 by sevrnghs">7 weeks</span>
+#
+# This is a CSS style to apply that will make it about 3.14% slicker:
+#   span.last-modified { border-bottom: 1px dotted gray; cursor: help; }
+# 
+
+import time
+import datetime
+import re
+
+def execute(hdf, txt, env):
+    if not txt:
+        page_name=hdf.getValue('title', '')
+        page_name=re.sub(' \(.*$', '', page_name)
+        page_name=page_name or 'WikiStart'
+        mode='normal'
+    elif txt.find(',')==-1:
+        if txt=='delta':
+            mode='delta'
+            page_name=hdf.getValue('title', '')
+            page_name=re.sub(' \(.*$', '', page_name)
+            page_name=page_name or 'WikiStart'
+        else:
+            page_name=txt
+            mode='normal'
+    else:
+        args=txt.split(',',1)
+        page_name=args[0]
+        mode=args[1]
+
+    db=env.get_db_cnx()
+    cursor=db.cursor()
+    cursor.execute("SELECT author, time FROM wiki WHERE name = %s "
+            "ORDER BY version DESC LIMIT 1", page_name)
+    row=cursor.fetchone()
+    author=row[0]
+    time_int=row[1]
+    timestamp=time.localtime(time_int)
+
+    if mode=='delta':
+        now=datetime.datetime.utcfromtimestamp(time.time())
+        last_modified=datetime.datetime.utcfromtimestamp(time_int)
+        elapsed=now-last_modified
+        if elapsed.days==0:
+            if elapsed.seconds/3600>1.5:
+                count=elapsed.seconds/3600
+                unit='hour'
+            elif elapsed.seconds/60>1.5:
+                count=elapsed.seconds/60
+                unit='minute'
+            else:
+                count=elapsed.seconds
+                unit='second'
+        elif elapsed.days/3650>1.5:
+            count=elapsed.days/3650
+            unit='decade'
+        elif elapsed.days/365>1.5:
+            count=elapsed.days/365
+            unit='year'
+        elif elapsed.days/30>1.5:
+            count=elapsed.days/30
+            unit='month'
+        elif elapsed.days/7>1.5:
+            count=elapsed.days/7
+            unit='week'
+        else:
+            count=elapsed.days
+            unit='day'
+        output=""+repr(count)+" "+unit
+        if count>1: output+="s"
+    else: 
+        output=time.strftime("%Y-%m-%d", timestamp)
+
+    wrapped_output='<span class="last-modified" title="'+\
+            time.asctime(timestamp)+' by '+author+'">'+\
+            output+'</span>'
+
+    return wrapped_output
+
+
Index: /Trac/Macros/trunk/ParentWiki.py
===================================================================
--- /Trac/Macros/trunk/ParentWiki.py	(revision 5)
+++ /Trac/Macros/trunk/ParentWiki.py	(revision 5)
@@ -0,0 +1,35 @@
+"""
+Inserts a link to the "parent" wiki entry.  
+
+This only applies to wikis that have a "/" in their name indicating heirarchy.  
+
+e.g. an entry named Java/Introduction will have a parent of Java.  All other wiki entries have a parent of WikiStart.
+"""
+
+import re
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    cursor = db.cursor()
+
+    buf = StringIO()
+
+    prefix = None
+    if args:
+        prefix = args.replace('\'', '\'\'')
+    else :
+	prefix = hdf.getValue('wiki.page_name', '') + '/'
+
+
+    parent = 'WikiStart'
+
+    m = re.search("(\S+)/(\S+)$", prefix)
+    if m:
+    	parent = m.group(1)
+
+    buf.write('<a href="%s">' % env.href.wiki(parent))
+    buf.write(parent)
+    buf.write('</a>\n')
+
+    return buf.getvalue()
Index: /Trac/Macros/trunk/Poll.py
===================================================================
--- /Trac/Macros/trunk/Poll.py	(revision 5)
+++ /Trac/Macros/trunk/Poll.py	(revision 5)
@@ -0,0 +1,100 @@
+# vim: expandtab tabstop=4
+import re
+import pickle
+from os import mkdir
+from binascii import crc32
+
+# Set this to where you want the poll state to be stored
+polldir = "/var/state/trac/polls"
+
+def title2label(title):
+	return hex(crc32(title))[2:]
+
+class Poll:
+    def __init__(self, path, title, options):
+        self.path = path
+        self.label = title2label(title)
+        self.title = title
+        self.options = []
+        # Set defaults
+        for option in options:
+            self.options.append([option, {}])
+
+        # Restore on-disk representation first
+        try:
+            merge = pickle.load(open(self.path, "r"))
+            for i, option in enumerate(merge):
+                self.options[i][1] = merge[i][1]
+        except:
+            pass
+        # Then "overwrite"
+        for i, option in enumerate(options):
+            self.options[i][0] = option
+
+    def render(self, hdf):
+        commit = 0
+        html = "<form action='#%s' method='get'>\n" % self.label
+        html += "<a name='%s'></a>" % self.label
+        html += "<fieldset>\n<legend>%s</legend>\n" % self.title
+        html += "<input type='hidden' name='poll' value='%s'>\n" % self.label
+
+        user = hdf.getValue("trac.authname", "anonymous")
+        poll = hdf.getValue("args.poll", "") 
+        pollvalue = int(hdf.getValue("args.pollvalue", "0"))
+
+        error = ""
+
+        # Check for existing vote
+        if poll == self.label:
+            for i, option in enumerate(self.options):
+                if user in option[1]:
+                    if pollvalue != i:
+                        error = "<div class='system-message'><strong>Changed your vote.</strong></div>\n"
+                    if user != "anonymous":
+                        del(self.options[i][1][user])
+                    commit = 1
+
+        for i, option in enumerate(self.options):
+            label = title2label(option[0])
+            checked = ""
+            if poll == self.label and pollvalue == i:
+                if self.options[i][1].has_key(user):
+                    self.options[i][1][user] += 1
+                else:
+                    self.options[i][1][user] = 1
+                commit = 1
+            if user in self.options[i][1]:
+                checked = "checked"
+            voters = ""
+            if len(option[1]):
+                voters = "<strong>"
+                voter_list = []
+                for voter in option[1].keys():
+                    if option[1][voter] > 1:
+                        voter_list.append('%s &times; %i' % (voter, option[1][voter]))
+                    else:
+                        voter_list.append(voter)
+                voters = " <strong>(%s)</strong>" % ", ".join(voter_list)
+            html += "<input type='radio' name='pollvalue' value='%i'%s> %s%s<br>\n" % (i, checked, option[0], voters)
+        html += "<input type='submit' value='Vote'>\n"
+        html += error
+        html += "</fieldset>\n"
+        html += "</form>\n"
+
+        if commit:
+            try:
+                pickle.dump(self.options, open(self.path, "w"))
+            except:
+                pass
+        return html
+
+def execute(hdf, txt, env):
+    args = re.split('\s*;\s*', txt)
+    path = "%s/%s" % (polldir, title2label(hdf.getValue("project.name.encoded", "default")))
+    try:
+        mkdir(path)
+    except:
+        pass
+    path += "/%s.p" % title2label(args[0])
+    poll = Poll(path, args.pop(0), args)
+    return poll.render(hdf)# + "<pre>" + hdf.dump() + "</pre>"
Index: /Trac/Macros/trunk/README.LAL
===================================================================
--- /Trac/Macros/trunk/README.LAL	(revision 5)
+++ /Trac/Macros/trunk/README.LAL	(revision 5)
@@ -0,0 +1,5 @@
+Ce répertoire contient les macros Trac implémentant des extensions à la
+version standard. Ils proviennent généralement de MacroBazaar. Ce
+répertoire est géré via le repository Subversion SystemConfig.
+
+Michel Jouvin - 20/5/05
Index: /Trac/Macros/trunk/ReTickets.py
===================================================================
--- /Trac/Macros/trunk/ReTickets.py	(revision 5)
+++ /Trac/Macros/trunk/ReTickets.py	(revision 5)
@@ -0,0 +1,41 @@
+open """
+
+Lists all tickets matching a given regular expression
+
+This macro takes one parameter, the regexp
+
+"""
+
+import time
+import re
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    cursor = db.cursor()
+
+    regexp = 'ZZ'
+    if args:
+        argv = [arg.strip() for arg in args.split(',')]
+        if len(argv) > 0:
+            regexp = argv[0].replace('\'', '\'\'')
+
+    sql = 'SELECT id, owner, summary, description FROM ticket WHERE status IN (\'new\', \'assigned\', \'reopened\')'
+
+    cursor.execute(sql)
+
+    buf = StringIO()
+    while 1:
+        row = cursor.fetchone()
+        if row == None:
+            break
+        m = re.search(regexp,row[2])
+        if m:
+          buf.write('<a href="%s" title="(%s) %s">[#%s(%s)]</a> ' % (env.href.ticket(row[0]), 
+                                                   row[2],
+                                                   row[3],
+                                                   row[0],
+                                                   row[1]))
+
+    return buf.getvalue()
+
Index: /Trac/Macros/trunk/Search.py
===================================================================
--- /Trac/Macros/trunk/Search.py	(revision 5)
+++ /Trac/Macros/trunk/Search.py	(revision 5)
@@ -0,0 +1,32 @@
+"""
+Build a search URL for the supplied argument or just a link to a search
+engine if no args are present.
+
+Defaults to google.  Edit the macro to modify the engine(/url).
+
+This script doesn't encode the search string provided.  Seems to work fine
+on IE 6 and FireFox 1.0.
+"""
+
+searchurl_prefix="http://www.google.com/search?hl=en&q="
+searchurl="http://www.google.com/"
+
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+
+  url= None
+  link= None
+  if args:
+      text = args
+      url = searchurl_prefix + args
+  else:
+      text = "Search"
+      url = searchurl
+
+  buf = StringIO()
+  buf.write('<a title="Search" href="%s">' % url)
+  buf.write(text)
+  buf.write('</a>\n')
+
+  return buf.getvalue()
Index: /Trac/Macros/trunk/ShowPath.py
===================================================================
--- /Trac/Macros/trunk/ShowPath.py	(revision 5)
+++ /Trac/Macros/trunk/ShowPath.py	(revision 5)
@@ -0,0 +1,35 @@
+"""
+Show the path to a heirarchical wiki entry (a la the directory names at
+the top of the svn source browser)
+"""
+
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    cursor = db.cursor()
+
+    prefix = None
+    if args :
+        prefix = args.replace('\'', '\'\'')
+    else :
+        prefix = hdf.getValue('wiki.page_name', '')
+
+    heirarchy = prefix.split('/')
+    prev = StringIO()
+    buf = StringIO()
+
+    buf.write('<a href="%s">' % env.href.wiki('WikiStart'))
+    buf.write('WikiStart')
+    buf.write('</a>/')
+
+    for i in heirarchy[0:-1]:
+        wiki = prev.getvalue() + i
+        buf.write('<a href="%s">' % env.href.wiki(wiki))
+        buf.write(i)
+        buf.write('</a>/')
+        prev.write(i + '/')
+
+    buf.write(heirarchy[-1])
+	    
+    return buf.getvalue()
Index: /Trac/Macros/trunk/SubWiki.py
===================================================================
--- /Trac/Macros/trunk/SubWiki.py	(revision 5)
+++ /Trac/Macros/trunk/SubWiki.py	(revision 5)
@@ -0,0 +1,39 @@
+"""
+Inserts an alphabetic list of sub-wiki pages into the output.
+A sub-wiki page is a page that is is deeper in the hierachy than the current page.  e.g. if the current page is People, the this will return a list of all wiki entries that start with "People/"
+
+Accepts a prefix string as parameter: if provided, only pages with names that
+start with the prefix are included in the resulting list. If this parameter is
+omitted, all pages are listed.
+"""
+
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    cursor = db.cursor()
+
+    prefix = None
+    if args:
+        prefix = args.replace('\'', '\'\'')
+    else :
+	prefix = hdf.getValue('wiki.page_name', '') + '/'
+
+    sql = 'SELECT DISTINCT name FROM wiki '
+    if prefix:
+        sql += 'WHERE name LIKE \'%s%%\' ' % prefix
+    sql += 'ORDER BY name'
+    cursor.execute(sql)
+
+    buf = StringIO()
+    buf.write('<ul>')
+    while 1:
+        row = cursor.fetchone()
+        if row == None:
+            break
+        buf.write('<li><a href="%s">' % env.href.wiki(row[0]))
+        buf.write(row[0])
+        buf.write('</a></li>\n')
+    buf.write('</ul>')
+
+    return buf.getvalue()
Index: /Trac/Macros/trunk/SvnFiles.py
===================================================================
--- /Trac/Macros/trunk/SvnFiles.py	(revision 5)
+++ /Trac/Macros/trunk/SvnFiles.py	(revision 5)
@@ -0,0 +1,45 @@
+"""
+
+Lists all files for a given svn directory matching a given filetype
+
+This macro takes 2 parameters, the path and the filetype
+
+"""
+
+import posixpath
+import svn
+import re
+from trac.core import open_svn_repos
+
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+
+  path = filetype = ''
+  if args:
+    argv = [arg.strip() for arg in args.split(',')]
+    if len(argv) > 0:
+      path = argv[0]
+      if len(argv) > 1:
+        filetype = argv[1]
+
+  repos_dir = env.get_config('trac', 'repository_dir')
+  pool, rep, fs_ptr = open_svn_repos(repos_dir)
+
+  rev = svn.fs.youngest_rev(fs_ptr, pool)
+  root = svn.fs.revision_root(fs_ptr, rev, pool)
+  node_type = svn.fs.check_path(root, path, pool)
+  
+  buf = StringIO()
+  if node_type == svn.core.svn_node_dir:
+    entries = svn.fs.dir_entries(root, path, pool)
+    
+    for item in entries.keys():
+      m = re.search(filetype,item)
+      if m:
+        fullpath = posixpath.join(path,item)
+        buf.write('<a href="%s">%s</a> ' % (env.href.file(fullpath),
+                                            item))
+  
+  return buf.getvalue()
+
Index: /Trac/Macros/trunk/TOC.py
===================================================================
--- /Trac/Macros/trunk/TOC.py	(revision 5)
+++ /Trac/Macros/trunk/TOC.py	(revision 5)
@@ -0,0 +1,108 @@
+# vim: expandtab tabstop=4
+from StringIO import StringIO
+import re
+import string
+from trac.util import escape
+
+rules_re = re.compile(r"""(?P<heading>^\s*(?P<hdepth>=+)\s(?P<header>.*)\s(?P=hdepth)\s*$)""")
+anchor_re = re.compile('[^\w\d]+')
+
+def parse_toc(env, out, page, body, max_depth = 999):
+    current_depth = 1
+    in_pre = False
+    seen_anchors = []
+
+    for line in body.splitlines():
+        line = escape(line)
+
+        # Skip over wiki-escaped code, e.g. code examples (Steven N.
+        # Severinghaus <sns@severinghaus.org>)
+        if in_pre:
+            if line == '}}}':
+                in_pre = False
+            else:
+                continue
+        if line == '{{{':
+            in_pre = True
+            continue
+
+        match = rules_re.match(line)
+        if match:
+            header = match.group('header')
+            new_depth = len(match.group('hdepth'))
+            if new_depth < current_depth:
+                while new_depth < current_depth:
+                    current_depth -= 1
+                    if current_depth == max_depth:
+                        out.write("</li><li>\n")
+                    elif current_depth < max_depth:
+                        out.write("</li></ol><li>\n")
+            elif new_depth > current_depth:
+                while new_depth > current_depth:
+                    current_depth += 1
+                    if current_depth <= max_depth:
+                        out.write("<ol><li>\n")
+            else:
+                if current_depth <= max_depth:
+                    out.write("</li><li>\n")
+            default_anchor = anchor = anchor_re.sub("", header)
+            anchor_n = 1
+            while anchor in seen_anchors:
+                anchor = default_anchor + str(anchor_n)
+                anchor_n += 1
+            seen_anchors.append(anchor)
+            link = page + "#" + anchor
+            if current_depth <= max_depth:
+                out.write('<a href="%s">%s</a>' % (env.href.wiki(link), header))
+    while current_depth > 1:
+        if current_depth <= max_depth:
+            out.write("</li></ol>\n")
+        current_depth -= 1
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    # Has the user supplied a list of pages?
+    if not args:
+        args = hdf.getValue("args.page", "WikiStart")
+    pre_pages = re.split('\s*,\s*', args)
+    # Options
+    inline = False
+    heading = 'Table of Contents'
+    pages = []
+    root = ''
+    params = { }
+    # Global options
+    for page in pre_pages:
+        if page == 'inline':
+            inline = True
+        elif page == 'noheading':
+            heading = None
+        elif page[:8] == 'heading=':
+            heading = page[8:]
+        else:
+            pages.append(page)
+    out = StringIO()
+    if not inline:
+        out.write("<div class='wiki-toc'>\n")
+    out.write("<ol>\n")
+    if heading:
+        out.write("<h4>%s</h4>\n" % heading)
+    for page in pages:
+        # Override arguments
+        if page[:6] == 'depth=':
+            params['max_depth'] = int(page[6:])
+        elif page[:5] == 'root=':
+            root = page[5:]
+        else:
+            page = root + page
+            cursor = db.cursor()
+            cursor.execute("SELECT text FROM wiki WHERE name='%s' ORDER BY version desc LIMIT 1" % page)
+            row = cursor.fetchone()
+            if row:
+                parse_toc(env, out, page, row[0], **params)
+            else:
+                out.write('<div class="system-message"><strong>Error: Page %s does not exist</strong></div>' % page)
+    out.write("</ol>\n")
+    if not inline:
+        out.write("</div>\n")
+    return out.getvalue()
Index: /Trac/Macros/trunk/TicketBox.py
===================================================================
--- /Trac/Macros/trunk/TicketBox.py	(revision 5)
+++ /Trac/Macros/trunk/TicketBox.py	(revision 5)
@@ -0,0 +1,34 @@
+"""
+Display a box contains ticket links and place it onto right of page.
+You can place ticket
+Use like this:
+
+  [[TicketBox(1,7,31)]]
+
+"""
+
+import re
+import string
+
+from trac.WikiFormatter import wiki_to_oneliner
+
+def execute(hdf, txt, env):
+    # args will be null if the macro is called without parentesis.
+    if not txt:
+        txt = ''
+    items = []
+    style = "float:right; background:#f7f7f0"
+    for arg in txt.split(','):
+        arg = arg.strip()
+        match = re.search("^#?([0-9]+)$", arg)
+        if match:
+            items.append('#' + match.group(1))
+    try:
+        str = wiki_to_oneliner(string.join(items, ", "), env, env.get_db_cnx())
+    except:
+        # for trac 0.8
+        str = wiki_to_oneliner(string.join(items, ", "), hdf, env, env.get_db_cnx())
+    if str != '':
+        return '<fieldset class="ticketbox" style="%s"><legend>Tickets</legend>%s</fieldset>' % (style, str)
+    else:
+        return ''
Index: /Trac/Macros/trunk/TracNav.py
===================================================================
--- /Trac/Macros/trunk/TracNav.py	(revision 5)
+++ /Trac/Macros/trunk/TracNav.py	(revision 5)
@@ -0,0 +1,167 @@
+import re
+import sys
+
+listRule = re.compile(r"""^(?P<indent> *)\* +(?:(?P<wikilink>\[wiki:(?P<link>(&#34;([^&#34;]*)&#34;|'([^']*)')|([^ \]]+)) +(?P<label>[^\]]*)\])|(?P<text>.*))""", re.M)
+
+def getToc(hdf, env, db, curpage, name):
+    preview = hdf.getValue('args.preview', "")
+
+    tocText = "* Table of contents"
+    if preview and (name == curpage):
+        tocText = hdf.getValue('wiki.page_source', tocText);
+    else:
+        cursor = db.cursor()
+        cursor.execute('SELECT text FROM wiki WHERE name=%s ORDER BY version DESC LIMIT 1', name)
+        row = cursor.fetchone()
+        if row:
+            tocText = row[0]
+
+    # env.log.debug(tocText)
+    return tocText
+
+
+def parseToc(tocText):
+    stack = []
+    nextPos = 0
+    while 1:
+        match = listRule.search(tocText, nextPos)
+        if not match:
+            # env.log.debug("No more matches")
+            break
+
+        indent = len(match.group('indent'))
+        if match.group('wikilink'):
+            link = match.group('link')
+            label = match.group('label')
+        else:
+            link = None
+            label = match.group('text')
+
+        # if link == None:
+        #     env.log.debug(label + " ---")
+        # else:
+        #     env.log.debug(label + ": " + link)
+
+	if len(stack) == 0:
+            stack.append((indent, []))
+
+        (lastIndent, list) = stack[len(stack) - 1]
+
+        if indent > lastIndent:
+            stack.append((indent, [(link, label, None)]))
+        elif indent == lastIndent:
+            list.append((link, label, None))
+        else:
+            while indent < lastIndent:
+                (_, list) = stack.pop()
+                (lastIndent, topList) = stack[len(stack) - 1]
+                (topLink, topLabel, _) = topList[len(topList) - 1]
+                topList[len(topList) - 1] = (topLink, topLabel, list)
+
+            (lastIndent, list) = stack[len(stack) - 1]
+            list.append((link, label, None))
+                
+        nextPos = match.end()
+
+    while len(stack) > 1:
+        (_, list) = stack.pop()
+        (_, topList) = stack[len(stack) - 1]
+        (topLink, topLabel, _) = topList[len(topList) - 1]
+        topList[len(topList) - 1] = (topLink, topLabel, list)
+
+    (_, list) = stack.pop()
+    return list
+
+
+def execute(hdf, args, env):
+    preview = hdf.getValue('args.preview', "")
+    curpage = hdf.getValue('args.page', "")
+    name = args
+    if not name:
+        name = 'TOC'
+
+    db = env.get_db_cnx()
+    toc = parseToc(getToc(hdf, env, db, curpage, name))
+    if not toc:
+        msg = ''
+        msg += '<div class="system-message"><strong>Error: Table of contents does not exist.'
+        if (not preview) and (hdf.getValue('trac.acl.WIKI_MODIFY', '')):
+            msg += ' Click here to <a href="%s?edit=yes">edit</a>.' % env.href.wiki(name)
+        msg += '</strong></div>\n'
+        return msg
+
+    (found, filtered) = filter(curpage, toc, 0)
+    if found:
+        return displayAll(hdf, env, name, curpage, filtered, 0)
+    else:
+        return displayAll(hdf, env, name, curpage, toc, 0)
+
+
+def filter(curpage, toc, level):
+    found = 0
+    result = []
+    for name, title, sub in toc:
+        if sub == None:
+            if name == curpage:
+                found = 1
+            result.append((name, title, None))
+        else:
+            (subfound, subtoc) = filter(curpage, sub, level + 1)
+            if subfound or (name == None):
+                found = 1
+                if level == 0 and name != None:
+                    prepended = [(name, title, subtoc)]
+                    prepended.extend(result)
+                    result = prepended
+                else:
+                    result.append((name, title, subtoc))
+            else:
+                result.append((name, title, []))
+    return (found, result)
+
+def indentation(col):
+    return ' ' * col
+
+def displayAll(hdf, env, name, curpage, toc, col):
+    preview = hdf.getValue('args.preview', "")
+    html = ''
+    html += '%s<div class="wiki-toc trac-nav">\n' % indentation(col)
+    col += 1
+    if (not preview) and hdf.getValue('trac.acl.WIKI_MODIFY', ''):
+        html += '%s<div class="edit"><a href="%s?edit=yes">edit</a></div>\n' % (indentation(col), env.href.wiki(name))
+    html += '%s<ul>\n' % indentation(col)
+    col += 1
+    html += display(env, curpage, toc, 0, col)
+    col -= 1
+    html += '%s</ul>\n' % indentation(col)
+    col -= 1
+    html += '%s</div>\n' % indentation(col)
+    return html
+
+def display(env, curpage, toc, depth, col):
+    html = ''
+    for name, title, sub in toc:
+        liStyle = ' style="padding-left: %dem;"' % (depth + 1)
+        if sub == None:
+            if name == curpage:
+                cls = ' class="active"'
+            else:
+                cls = ''
+            html += '%s<li%s%s>' % (indentation(col), liStyle, cls)
+            if name == None:
+                html += title
+            else:
+                html += '<a href="%s">%s</a>' % (env.href.wiki(name), title)
+            html += '</li>\n'
+        else:
+            html += '%s<li%s>\n' % (indentation(col), liStyle)
+            col += 1
+            if name == None or len(sub) > 0:
+                html += '%s<h4>%s</h4>\n' % (indentation(col), title)
+            else:
+                html += '%s<h4><a href="%s">%s...</a></h4>\n' % (indentation(col), env.href.wiki(name), title)
+            col -= 1
+            html += '%s</li>\n' % indentation(col)
+            if len(sub) > 0:
+                html += display(env, curpage, sub, depth + 1, col)
+    return html
Index: /Trac/Macros/trunk/TracSearch.py
===================================================================
--- /Trac/Macros/trunk/TracSearch.py	(revision 5)
+++ /Trac/Macros/trunk/TracSearch.py	(revision 5)
@@ -0,0 +1,43 @@
+"""
+Creates a link to search in trac for the given words, by building a link to Trac's inbuilt
+search facility.
+
+Examples:
+    [[TracSearch(keyword)]]
+    [[TracSearch(keyword,wiki)]]
+    [[TracSearch(keyword1 keyword2,changeset,ticket)]]
+"""
+
+
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    default_include = ['wiki', 'changeset', 'ticket']
+    buf = StringIO()
+
+    if args:
+    	args = args.split(',')
+    	term = args[0]
+    	if len(args) > 1:
+    	    include = args[1:]
+    	else:
+    	    include = default_include
+
+        objects = []
+        if 'wiki' in include:
+            objects.append('Wiki pages')
+        if 'changeset' in include:
+            objects.append('Changeset messages')
+        if 'ticket' in include:
+            objects.append('Tickets')
+
+        object_list = ", ".join(objects)
+
+        url = env.href.search(query=term, include=include)
+
+        buf.write("<a href='%(url)s'>%(objects)s containing '%(term)s'</a>\n" %
+            dict(objects=object_list, term=term, url=url))
+    else:
+        buf.write("<p style='font-weight:bold; color:red;'>[[Search()]] macro requires a search term</p>\n")
+
+    return buf.getvalue()
Index: /Trac/Macros/trunk/UserChanges.py
===================================================================
--- /Trac/Macros/trunk/UserChanges.py	(revision 5)
+++ /Trac/Macros/trunk/UserChanges.py	(revision 5)
@@ -0,0 +1,46 @@
+import time
+from StringIO import StringIO
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    cursor = db.cursor()
+
+    author = limit = None
+    if args:
+        argv = [arg.strip() for arg in args.split(',')]
+        if len(argv) > 0:
+            author = argv[0].replace('\'', '\'\'')
+            if len(argv) > 1:
+                limit = int(argv[1])
+
+    sql = 'SELECT name, max(time) FROM wiki '
+    if author:
+        sql += 'WHERE author LIKE \'%s%%\' ' % author
+    sql += 'GROUP BY name ORDER BY max(time) DESC'
+    if limit:
+        sql += ' LIMIT %d' % limit
+    cursor.execute(sql)
+
+    buf = StringIO()
+    #debug
+    #buf.write('%s<br>' % sql);
+    if author == None:
+    	author = 'all users'
+    buf.write('<h2>Recent Changes for %s</h2>' % author)
+    prevtime = None
+    while 1:
+        row = cursor.fetchone()
+        if row == None:
+            break
+        t = time.strftime('%x', time.localtime(int(row[1])))
+        if not t == prevtime:
+            if prevtime:
+                buf.write('</ul>')
+            buf.write('<h3>%s</h3><ul>' % t)
+            prevtime = t
+        buf.write('<li><a href="%s">%s</a></li>\n' % (env.href.wiki(row[0]),
+                                                      row[0]))
+    if prevtime:
+        buf.write('</ul>')
+
+    return buf.getvalue()
Index: /Trac/Macros/trunk/WikiCalendar.2.py
===================================================================
--- /Trac/Macros/trunk/WikiCalendar.2.py	(revision 5)
+++ /Trac/Macros/trunk/WikiCalendar.2.py	(revision 5)
@@ -0,0 +1,56 @@
+import time
+import calendar
+from cStringIO import StringIO
+
+cell_template = '<td%(style)s><a href="%(url)s"%(class)s>%(day)s</a></td>'
+
+def execute(hdf, fmt, env):
+    today = time.localtime()
+    year = int(hdf.getValue("args.year", str(today.tm_year)))
+    month = int(hdf.getValue("args.month", str(today.tm_mon)))
+    curr_day = None
+    if year == today.tm_year and month == today.tm_mon:
+        curr_day = today.tm_mday
+
+    # Can use this to change the day the week starts on, but this
+    # is a system-wide setting
+    #calendar.setfirstweekday(calendar.SUNDAY)
+    cal = calendar.monthcalendar(year, month)
+
+    buff = StringIO()
+
+    date = [year, month] + [1] * 7
+
+    buff.write('<table><caption>')
+    buff.write(time.strftime('%B %Y', tuple(date)))
+    buff.write('</caption>\n<thead><tr align="center">')
+    for day in calendar.weekheader(2).split():
+        buff.write('<th scope="col">%s</th>' % day)
+    buff.write('</tr></thead>\n<tbody>\n')
+
+    for row in cal:
+        buff.write('<tr align="right">')
+        for day in row:
+            if not day:
+                buff.write('<td>&nbsp;</td>')
+            else:
+                date[2] = day
+                wiki = time.strftime(fmt, tuple(date))
+                exists = env._wiki_pages.has_key(wiki)
+                url = env.href.wiki(wiki)
+                if not exists:
+                    url += "?action=edit"
+                buff.write(cell_template % {
+                        'url': url,
+                        'day': day,
+                        'style': day == curr_day and ' style="border: 1px solid #b00;"' or '',
+                        'class': not exists and ' class="missing"' or '',
+                        })
+
+        buff.write('</tr>\n')
+
+    buff.write('</tbody>\n</table>')
+            
+    table = buff.getvalue()
+    buff.close()
+    return table
Index: /Trac/Macros/trunk/WikiCalendar.py
===================================================================
--- /Trac/Macros/trunk/WikiCalendar.py	(revision 5)
+++ /Trac/Macros/trunk/WikiCalendar.py	(revision 5)
@@ -0,0 +1,56 @@
+import time
+import calendar
+from cStringIO import StringIO
+
+cell_template = '<td%(style)s><a href="%(url)s"%(class)s>%(day)s</a></td>'
+
+def execute(hdf, fmt, env):
+    today = time.localtime()
+    year = int(hdf.getValue("args.year", str(today.tm_year)))
+    month = int(hdf.getValue("args.month", str(today.tm_mon)))
+    curr_day = None
+    if year == today.tm_year and month == today.tm_mon:
+        curr_day = today.tm_mday
+
+    # Can use this to change the day the week starts on, but this
+    # is a system-wide setting
+    #calendar.setfirstweekday(calendar.SUNDAY)
+    cal = calendar.monthcalendar(year, month)
+
+    buff = StringIO()
+
+    date = [year, month] + [1] * 7
+
+    buff.write('<table><caption>')
+    buff.write(time.strftime('%B %Y', tuple(date)))
+    buff.write('</caption>\n<thead><tr align="center">')
+    for day in calendar.weekheader(2).split():
+        buff.write('<th scope="col">%s</th>' % day)
+    buff.write('</tr></thead>\n<tbody>\n')
+
+    for row in cal:
+        buff.write('<tr align="right">')
+        for day in row:
+            if not day:
+                buff.write('<td>&nbsp;</td>')
+            else:
+                date[2] = day
+                wiki = time.strftime(fmt, tuple(date))
+                exists = env._wiki_pages.has_key(wiki)
+                url = env.href.wiki(wiki)
+                if not exists:
+                    url += "?action=edit"
+                buff.write(cell_template % {
+                        'url': url,
+                        'day': day,
+                        'style': day == curr_day and ' style="border: 1px solid #b00;"' or '',
+                        'class': not exists and ' class="missing"' or '',
+                        })
+
+        buff.write('</tr>\n')
+
+    buff.write('</tbody>\n</table>')
+            
+    table = buff.getvalue()
+    buff.close()
+    return table
Index: /Trac/Macros/trunk/WikiFile.py
===================================================================
--- /Trac/Macros/trunk/WikiFile.py	(revision 5)
+++ /Trac/Macros/trunk/WikiFile.py	(revision 5)
@@ -0,0 +1,30 @@
+
+from trac.WikiFormatter import wiki_to_html, WikiProcessor
+from trac import util
+import os
+
+
+def execute(hdf, file, env):
+    # Currently hdf is set only when the macro is called
+    # From a wiki page
+    args = file or ''
+
+    if args:
+        import urllib
+        try:
+            f = urllib.urlopen(args)
+        except:
+            raise util.TracError('The "%s" argument doesnt seem to be a valid link' % (args))
+        txt =  f.read()
+        (path, suffix) = os.path.splitext(args)
+        suffix = suffix[1:]
+        try:
+            Format = WikiProcessor(env,suffix)
+            html = Format.process(hdf, txt)        
+            return html
+        except:
+            raise util.TracError('The "%s" argument doesnt seem to be a valid link' % (suffix))
+            return wiki_to_html(txt, hdf, env, env.get_db_cnx)
+    else:
+        raise util.TracError('The include macro requires an url as argument')
+
Index: /Trac/Macros/trunk/WikiInclude.py
===================================================================
--- /Trac/Macros/trunk/WikiInclude.py	(revision 5)
+++ /Trac/Macros/trunk/WikiInclude.py	(revision 5)
@@ -0,0 +1,28 @@
+from StringIO import StringIO
+from trac.WikiFormatter import *
+
+def execute(hdf, txt, env):
+	db = env.get_db_cnx()
+	formatter = Formatter(hdf, env, db)
+	out = StringIO()
+	
+	txt = txt or ''
+	args = txt.split('|')
+	name = args.pop(0).replace('\'', '\'\'')
+	sql = "SELECT text from wiki where name = '%s' order by version desc limit 1" % name
+	cs = db.cursor()
+	cs.execute(sql)
+	
+	row = cs.fetchone()
+	if row == None:
+		return ''
+	text = row[0]
+	
+	i = 0
+	for arg in args:
+		text = text.replace('{{%d}}' % (i+1), args[i])
+		i += 1
+	
+	formatter.format(text, out)
+	
+	return out.getvalue()
Index: /Trac/Macros/trunk/acronym.py
===================================================================
--- /Trac/Macros/trunk/acronym.py	(revision 5)
+++ /Trac/Macros/trunk/acronym.py	(revision 5)
@@ -0,0 +1,5 @@
+def execute(hdf, txt, env):
+    args = txt.split(',', 1)
+    title = args[1]
+    linktext = args[0].strip()
+    return '<acronym title="%s">%s</acronym>' % (title, linktext)
Index: /Trac/Macros/trunk/add_trac_macros
===================================================================
--- /Trac/Macros/trunk/add_trac_macros	(revision 5)
+++ /Trac/Macros/trunk/add_trac_macros	(revision 5)
@@ -0,0 +1,45 @@
+#!/bin/ksh
+#
+# Definit un lien symbolique dans le répertoire wikimacros d'une version Trac (pro
+# par défaut) pour chaque macro présent dans le répertoire site-macros.
+#
+# Michel Jouvin - LAL / CNRS - 8/4/05
+
+trac_prefix=/www/Web/servers/trac
+version="pro"
+site_macros_dir=${trac_prefix}/site-macros
+trac_python_version=2.4
+
+if [ -n "$1" ]
+then
+    version=$1
+fi
+
+trac_macros_dir=${trac_prefix}/$version/lib/python${trac_python_version}/site-packages/trac/wikimacros
+if [ ! -d  ${trac_macros_dir} ]
+then
+    echo "Trac macros dir not found (${trac_macros_dir})"
+    exit 1
+fi
+
+if [ ! -d  ${site_macros_dir} ]
+then
+    echo "Trac site macros dir not found (${site_macros_dir})"
+    exit 1
+fi
+
+macros=$(find ${site_macros_dir} -name '*.py')
+
+for macro in $macros
+do
+    macro_name=$(basename $macro)
+    trac_macro=${trac_macros_dir}/${macro_name}
+    if [ -e ${trac_macro} ]
+    then
+	echo "Macro ${macro_name} already exists. Not redefined"
+    else
+	echo "Macro ${macro_name} added"
+	ln -s ${macro} ${trac_macro}
+    fi
+done
+
Index: /Trac/Macros/trunk/docbook.py
===================================================================
--- /Trac/Macros/trunk/docbook.py	(revision 5)
+++ /Trac/Macros/trunk/docbook.py	(revision 5)
@@ -0,0 +1,16 @@
+import trac.util
+import libxml2, libxslt
+
+def execute(hdf, text, env):
+    stylesheet = env.get_config('docbook', 'stylesheet')
+    if not stylesheet:
+        raise trac.util.TracError('DocBook stylesheet not configured.')
+    else:
+        style = libxslt.parseStylesheetDoc(libxml2.parseFile(stylesheet))
+        doc = libxml2.parseDoc(text)
+        result = style.applyStylesheet(doc, None)
+        html = style.saveResultToString(result)
+        style.freeStylesheet()
+        doc.freeDoc()
+        result.freeDoc()
+        return html[html.find('<body>')+6:html.find('</body>')].strip()
Index: /Trac/Macros/trunk/javadoc.py
===================================================================
--- /Trac/Macros/trunk/javadoc.py	(revision 5)
+++ /Trac/Macros/trunk/javadoc.py	(revision 5)
@@ -0,0 +1,104 @@
+# Copyright 2004 Matthew Good
+# "THE BEER-WARE LICENSE" (Revision 42):
+# Matthew Good <matt-good.net> wrote this file.  As long as you retain
+# this notice you can do whatever you want with this stuff. If we meet some
+# day, and you think this stuff is worth it, you can buy me a beer in return.
+# Matthew Good
+
+# BEER-WARE LICENSE courtesy of Poul-Henning Kamp <phk@login.dknet.dk>
+
+# Author Matthew Good <trac@matt-good.net>
+
+# Trac WikiMacro for rendering links to Javadoc urls
+# Accepts one or two arguments separated by a comma.
+
+# The first argument is the fully qualified Java class or package.
+# Classes are assumed to begin with an uppercase letter and packages
+# with a lowercase letter according to standard Java naming conventions.
+
+# The second optional argument is the link text.
+# If the second argument is ommitted the class name is used,
+# or in the case of a package the full package name is used.
+
+#-------------------------------------------------------------------------------
+# This block can be edited to change the urls used for the Javadocs
+# Note: all Javadoc urls should end with a '/' or index.html
+
+j2se_url = 'http://java.sun.com/j2se/1.4.2/docs/api/index.html'
+j2ee_url = 'http://java.sun.com/j2ee/1.4/docs/api/index.html'
+xerces_url = 'http://xml.apache.org/xerces2-j/javadocs/api/index.html'
+
+urls = {
+    # The URL for the standard Java API
+    '': j2se_url,
+
+    # Mappings from package names to Javadoc URLs
+    'javax.activation': j2ee_url,
+    'javax.ejb': j2ee_url,
+    'javax.enterprise': j2ee_url,
+    'javax.jms': j2ee_url,
+    'javax.mail': j2ee_url,
+    'javax.management': j2ee_url,
+    'javax.resource': j2ee_url,
+    'javax.security.jacc': j2ee_url,
+    'javax.servlet': j2ee_url,
+    'javax.transaction': j2ee_url,
+    'javax.xml': j2ee_url,
+
+    'org.apache.commmons.beanutils':
+        'http://jakarta.apache.org/commons/beanutils/commons-beanutils-1.7.0/docs/api/',
+    'org.apache.commons.collections':
+        'http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_1/index.html',
+    'org.apache.commons.lang':
+        'http://jakarta.apache.org/commons/lang/api/index.html',
+
+    'org.w3c.dom': xerces_url,
+    'org.xml.sax': xerces_url
+    }
+#-------------------------------------------------------------------------------
+
+from urlparse import urljoin
+from string import uppercase
+
+def best_match(value, items):
+    match = ''
+    for i in items:
+        if len(i) > len(match) and value.startswith(i):
+            match = i
+            
+    return match
+
+def base_url(package):
+    return urls[best_match(package, urls.keys())]
+    
+def package_path(package):
+    return package.replace('.', '/') + '/'
+    
+def type_path(package, clss):
+    return package_path(package) + (clss and (clss + '.html') or 'package-summary.html')
+    
+def javadoc_url(package, clss):
+    return urljoin(base_url(package), type_path(package, clss))
+    
+def split_at(a, index):
+    return (a[:index], a[index + 1:])
+    
+def split_type(value):
+    package, clss = split_at(value, value.rfind('.'))
+    if clss[0] in uppercase:
+        return (package, clss)
+    else:
+        return (value, None)
+    
+def link(href, text):
+    return '<a href="%s" class="javadoc">%s</a>' % (href, text)
+    
+def javadoc_link(value, linktext):
+    package, clss = split_type(value)
+    return link(javadoc_url(package, clss), linktext or clss or package)
+
+def execute(hdf, txt, env):
+    args = txt.split(',', 1)
+    javatype = args[0].strip()
+    linktext = len(args) > 1 and args[1].strip() or None
+    return javadoc_link(javatype, linktext)
Index: /Trac/Macros/trunk/redirect.py
===================================================================
--- /Trac/Macros/trunk/redirect.py	(revision 5)
+++ /Trac/Macros/trunk/redirect.py	(revision 5)
@@ -0,0 +1,30 @@
+# vim: expandtab tabstop=4
+from StringIO import StringIO
+import re
+import string
+from trac import WikiFormatter
+from trac.WikiFormatter import CommonFormatter
+
+def execute(hdf, args, env):
+    db = env.get_db_cnx()
+    out = StringIO()
+    fmt = CommonFormatter(hdf, env, db)
+    if args:
+	link = fmt._expand_module_link(args)
+        if link[0] != None:
+            # out.write("<tt>");
+	    # out.write(link[0]);
+	    # out.write("</tt>");
+            out.write("<script language=\"JavaScript\">\n")
+            out.write("document.location=\"")
+            out.write(link[0])
+	    out.write("\";\n")
+            out.write("</script>")
+            return out.getvalue()
+        else:
+            out.write('<div class="system-message"><strong>Error: Redirection target not found.</strong></div>')
+    else:
+        out.write('<div class="system-message"><strong>Error: Missing redirection URL.</strong></div>')
+
+
+
