diff --git a/web/lib/template.ssjs b/web/lib/template.ssjs
index a845681448aa8a8a8bd6f4b148b450f2c05ae373..3c450c779b6d6062ab9b83110656a8f38874a682 100644
--- a/web/lib/template.ssjs
+++ b/web/lib/template.ssjs
@@ -18,6 +18,13 @@
 /* the value of template.name.sname.                                         */
 /* (^^ and %% are also supported)                                            */
 /*                                                                           */
+/* Inside of REPEAT sections, the current object from the repeated array is  */
+/* Available to JS: replacements as RepeatObj                                */
+/*                                                                           */
+/* The convienience function Nz(value[, valifundefined]) is also available.  */
+/* It returns valifindefined if value is undefined, or value if it is.       */
+/* valifundefined defaults to the empty string.                              */
+/*                                                                           */
 /*****************************************************************************/
 
 /* $Id$ */
@@ -35,6 +42,15 @@ template.Theme_CSS_File=Themes[CurrTheme].css;
 template.server=server;
 template.system=system;
 
+function Nz(value, valifundefined)
+{
+	if(valifundefined==undefined)
+		valifundefined='';
+	if(value==undefined)
+		return(valifundefined);
+	return(value);
+}
+
 function write_template(filename)  {
     var fname='../web/templates/'+Themes[CurrTheme].dir+'/'+filename;
     if(!file_exists(fname)) {
@@ -48,63 +64,55 @@ function write_template(filename)  {
     }
     var file=inc.read();
     inc.close();
-    /* The following 'if' statement fixes performance problem with pages *not* containing REPEAT clauses */
-    if(file.search(/<<REPEAT .*>>/)>0)  
-        file=file.replace(/([\x00-\xff]*?)<<REPEAT (.*?)>>([\x00-\xff]*?)<<END REPEAT \2>>/g,
-            function(matched, start, objname, bit, offset, s) {
-                var ret='';
-                start=parse_regular_bit(start,"",template);
-                start=start.replace(/\<\!-- Magical Synchronet ([\^%@])-code --\>/g,'$1');
-                write(start);
-                for(obj in template[objname]) {
-                    var thisbit=parse_regular_bit(bit,objname,template[objname][obj]);
-                    thisbit=parse_regular_bit(thisbit,"",template);
-                    thisbit=thisbit.replace(/\<\!-- Magical Synchronet ([\^%@])-code --\>/g,'$1');
-                    write(thisbit);
-                }
-                return("");
-            });
-    file=parse_regular_bit(file, "", template);
-    file=file.replace(/\<\!-- Magical Synchronet ([\^%@])-code --\>/g,'$1');
-    write(file);
-}
-function parse_regular_bit(bit, objname, obj) {
-    if(objname=="JS") {
-        return(bit);
-    }
-    if(objname=='') {
-        bit=bit.replace(/([%^@])\1([^^%@\r\n]*?)\:([^:%^@\r\n]*?)\1\1/g,
-            function (matched, start, objname, prop, offset, s) {
-                var res=matched;
-                if(template[objname]!=undefined)
-                    res=escape_match(start, template[objname][prop]);
-                return(res);
-            });
-        bit=bit.replace(/([%^@])\1([^:^%@\r\n]*?)\1\1/g,
-            function (matched, start, exp, offset, s) {
-                var res=escape_match(start, template[exp]);
-                return(res);
-            });
-        bit=bit.replace(/([%^@])\1JS:([\x00-\xff]*?)\1\1/g,
-            function (matched, start, exp, offset, s) {
-                var res=escape_match(start, eval(exp));
-                return(res);
-            });
-        bit=bit.replace(/([%^@])\1(.*?)\1\1/g,'');
+    var offset;
+    while((offset=file.search(/<<REPEAT .*?>>/))>-1) {
+        parse_regular_bit(file.substr(0,offset),'',template);
+        file=file.substr(offset);
+        var m=file.match(/^<<REPEAT (.*?)>>([\x00-\xff]*?)<<END REPEAT \1>>/);
+        if(m.index>-1) {
+            for(obj in template[m[1]]) {
+                parse_regular_bit(m[2],m[1],template[m[1]][obj]);
+            }
+            file=file.substr(m[0].length);
+        }
     }
-    else {
-        bit=bit.replace(new RegExp('([%^@])\\1'+regex_escape(objname)+':([^^%@\r\n]*?)\\1\\1',"g"),
-            function (matched, start, exp, offset, s) {
-                var res=matched;
-                if(obj[exp]!=undefined)
-                    res=escape_match(start, obj[exp]);
-                return(res);
-            });
+    parse_regular_bit(file, "", template);
+}
+
+function parse_regular_bit(bit, objname, RepeatObj) {
+ var offset;
+ var i=0;
+ while((offset=bit.search(/([%^@])\1(.*?)\1\1/))>-1) {
+    write(bit.substr(0,offset));
+    bit=bit.substr(offset);
+    var m=bit.match(/^([%^@])\1([\x00-\xff]*?)\1\1/);
+    if(m.index>-1) {
+        if(m[2].substr(0,3)=='JS:') {
+            var val=eval(m[2].substr(3));
+            if(val!=undefined)
+                write(escape_match(m[1],eval(m[2].substr(3))));
+        }
+        else if(m[2].substr(0,objname.length+1)==objname+':') {
+            if(RepeatObj[m[2].substr(objname.length+1)]!=undefined)
+                write(escape_match(m[1],RepeatObj[m[2].substr(objname.length+1)]));
+        }
+        else if((i=m[2].search(/:/))>0) {
+            if(template[m[2].substr(0,i)]!=undefined) {
+                if(template[m[2].substr(0,i)][m[2].substr(i+1)]!=undefined)
+                    write(escape_match(m[1],template[m[2].substr(0,i)][m[2].substr(i+1)]));
+            }
+        }
+        else {
+            if(template[m[2]]!=undefined)
+                write(escape_match(m[1],template[m[2]]));
+        }
     }
-    return bit;
+    bit=bit.substr(m[0].length);
+ }
+ write(bit);
 }
 
-function escape_match(start, exp, end)  {
+function escape_match(start, exp)  {
     if(exp==undefined)
         exp='';
     exp=exp.toString();
@@ -112,9 +120,6 @@ function escape_match(start, exp, end)  {
         exp=html_encode(exp,false,false,false,false);
     if(start=="^")
         exp=encodeURIComponent(exp);
-    exp=exp.replace(/\@/g,'<!-- Magical Synchronet @-code -->');
-    exp=exp.replace(/\^/g,'<!-- Magical Synchronet ^-code -->');
-    exp=exp.replace(/\%/g,'<!-- Magical Synchronet %-code -->');
     return(exp);
 }
 
diff --git a/web/templates/default/leftnav.inc b/web/templates/default/leftnav.inc
index e67bd9fa2136639bfb293a36266588237383dc54..ec59e74bb9fa41b449f783640fe9f7efcae01301 100644
--- a/web/templates/default/leftnav.inc
+++ b/web/templates/default/leftnav.inc
@@ -23,7 +23,9 @@
         
 <!-- start Nodelisting -->
 
-      @@JS:if(!template.node_list.length || http_request.virtual_path=="/nodelist.ssjs")'<!--';@@Who's Online now ...<br /><table class="left_nodelist"><tbody><<REPEAT node_list>><tr><td class="left_nodelist"><a href="mailto:@@node_list:email@@">%%node_list:name%%</a> %%node_list:action%%</td></tr><<END REPEAT node_list>></tbody></table>@@JS:if(!template.node_list.length || http_request.virtual_path=="/nodelist.ssjs")'-->';@@
+      @@JS:if(!template.node_list.length || http_request.virtual_path=="/nodelist.ssjs")'<!--';@@
+Who's Online now ...<br /><table class="left_nodelist"><tbody><<REPEAT node_list>><tr><td class="left_nodelist"><a href="mailto:@@node_list:email@@">%%node_list:name%%</a> %%node_list:action%%</td></tr><<END REPEAT node_list>></tbody></table>
+@@JS:if(!template.node_list.length || http_request.virtual_path=="/nodelist.ssjs")'-->';@@
  
      </div>
      </td>                        
diff --git a/web/templates/default/msgs/choosegroup.inc b/web/templates/default/msgs/choosegroup.inc
index e3cbe1fc4b20546895d7d58a208ee6133bb33477..8342bb34d6b60b4e4f664a48e9b3a2632e540055 100644
--- a/web/templates/default/msgs/choosegroup.inc
+++ b/web/templates/default/msgs/choosegroup.inc
@@ -11,7 +11,7 @@
 <<REPEAT groups>>
 <tr>
     <td class="grouplist"><a class="grouplist" href="choosesubs.ssjs?msg_grp=^^groups:name^^">%%groups:description%%</a></td>
-    <td class="grouplist" align="right">@@JS:msg_area.grp_list['@@groups:index@@'].sub_list.length@@</td>
+    <td class="grouplist" align="right">@@JS:msg_area.grp_list[RepeatObj.index].sub_list.length@@</td>
 </tr>
 <<END REPEAT groups>>
 </table>
diff --git a/web/templates/default/msgs/choosesubs.inc b/web/templates/default/msgs/choosesubs.inc
index c285c20c9ab1d24ce4e47468474b88e1e3583214..d8c3fecb3df0021da91623d51648c620d2e165f6 100644
--- a/web/templates/default/msgs/choosesubs.inc
+++ b/web/templates/default/msgs/choosesubs.inc
@@ -21,13 +21,13 @@
     <td class="sublistright">%%subs:messages%%</td>
     <td class="sublistright" nowrap="nowrap">%%subs:lastmsg%%</td>
     <td class="sublist">
-      <input name="sub-%%subs:code%%" type="radio" value="1" @@JS:if(%%subs:ischecked%%==1)' checked="checked"';@@ />
+      <input name="sub-%%subs:code%%" type="radio" value="1" @@JS:if(RepeatObj.ischecked==1)' checked="checked"';@@ />
     </td>
     <td class="sublist">
-      <input name="sub-%%subs:code%%" type="radio" value="2" @@JS:if(%%subs:ischecked%%==2)' checked="checked"';@@ />
+      <input name="sub-%%subs:code%%" type="radio" value="2" @@JS:if(RepeatObj.ischecked==2)' checked="checked"';@@ />
     </td>
     <td class="sublist">  
-      <input name="sub-%%subs:code%%" type="radio" value="3" @@JS:if(%%subs:ischecked%%==3)' checked="checked"';@@ />
+      <input name="sub-%%subs:code%%" type="radio" value="3" @@JS:if(RepeatObj.ischecked==3)' checked="checked"';@@ />
     </td>
 </tr>
 <<END REPEAT subs>>
diff --git a/web/templates/default/msgs/groups.inc b/web/templates/default/msgs/groups.inc
index 987fca8746a57f1c1b3df3a9e01fe36b18707fd5..a1a8aadabe9fad9f9d7298920a34d8a1c87aa7c5 100644
--- a/web/templates/default/msgs/groups.inc
+++ b/web/templates/default/msgs/groups.inc
@@ -11,7 +11,7 @@
 <<REPEAT groups>>
 <tr>
     <td class="grouplist"><a class="grouplist" href="subs.ssjs?msg_grp=^^groups:name^^">%%groups:description%%</a></td>
-    <td class="grouplist" align="right">@@JS:msg_area.grp_list['@@groups:index@@'].sub_list.length@@</td>
+    <td class="grouplist" align="right">@@JS:msg_area.grp_list[RepeatObj.index].sub_list.length@@</td>
 </tr>
 <<END REPEAT groups>>
 </table>
diff --git a/web/templates/default/msgs/msg.inc b/web/templates/default/msgs/msg.inc
index 8b313dde56a6b0f2b01f958354b8373dddf61a1f..8912b8006b17b6743378bd49ed5eda7bd5c48bac 100644
--- a/web/templates/default/msgs/msg.inc
+++ b/web/templates/default/msgs/msg.inc
@@ -10,7 +10,7 @@
     <td width="1%" class="msgheader" nowrap="nowrap" onDblClick="window.open().document.write('%%hfields%%')">Subject:</td>
     <td nowrap="nowrap">%%hdr:subject%%</td>
     <td width="1%" class="msgheader" nowrap="nowrap">Date:</td>
-    <td nowrap="nowrap">%%JS:system.timestr(@@hdr:when_written_time@@)%%</td>
+    <td nowrap="nowrap">%%JS:system.timestr(template.hdr.when_written_time)%%</td>
 </tr>
 <tr class="msg">
     <td width="1%" class="msgheader" nowrap="nowrap">From:</td>
@@ -32,8 +32,8 @@
 <table class="msg2" width="100%">
 <tr>
     <td width="1%" class="msgnavleft" nowrap="nowrap">@@prevlink@@</td>
-    <td width="1%" class="msgnavmid">@@JS:template.can_post?'<a href="reply.ssjs?msg_sub=^^sub:code^^&amp;reply_to=^^hdr:number^^">Reply</a>':'Reply'@@</td>
-    <td width="1%"class="msgnavmid">@@JS:template.can_post?'<a href="post.ssjs?msg_sub=^^sub:code^^&amp;post=new">Post New</a>':'Post New'@@</td>
+    <td width="1%" class="msgnavmid">@@JS:template.can_post?'<a href="reply.ssjs?msg_sub='+template.sub.code+'&amp;reply_to='+template.hdr.number+'">Reply</a>':'Reply'@@</td>
+    <td width="1%"class="msgnavmid">@@JS:template.can_post?'<a href="post.ssjs?msg_sub='+template.sub.code+'&amp;post=new">Post New</a>':'Post New'@@</td>
     @@JS:template.can_delete?'<td width="1%" class="msgnavmid"><a href="management.ssjs?Action=Delete+Selected+Message%28s%29&amp;msg_sub='+template.sub.code+'&amp;number='+template.hdr.number+'">Delete</a>':'Delete'@@</td>
     <td width="1%" class="msgnavright" nowrap="nowrap">@@nextlink@@</td>
 </tr>
diff --git a/web/templates/default/msgs/msgs.inc b/web/templates/default/msgs/msgs.inc
index 45d0613520aafacf12e4c4a7d9af21b39de2c6b9..26dcf8217dbbce1086917390d91cc1ac7d479dca 100644
--- a/web/templates/default/msgs/msgs.inc
+++ b/web/templates/default/msgs/msgs.inc
@@ -7,7 +7,7 @@
 
 <div align="center">
 @@JS:template.can_post?'<form name="PostMsg" action="post.ssjs?msg_sub=^^sub:code^^&amp;post=new" method="post"><input type="submit" value="'+template.post_button+'" /></form>':''@@
-@@JS:template.show_choice==undefined ? '' : '(@@show_choice@@)<br /><br />'@@
+@@JS:template.show_choice==undefined ? '' : '(' + template.show_choice + ')<br /><br />'@@
 </div>
 
 <form name="DeleteMsg" action="management.ssjs" method="post">
@@ -27,27 +27,27 @@
     <tr class=@@JS:((template.color++)%2==0)?'"msglist1"':'"msglist2"';@@>
     @@JS:template.can_delete?'<td align=center><input name="number" value="^^messages:number^^" type="checkbox"></td>':''@@
        <td align="center">
-            @@JS:if(@@messages:attachments@@>0) '<img alt="Attachment" src="/graphics/attach_black.gif" />'; else '&nbsp;';@@
+            @@JS:if(RepeatObj.attachments>0) '<img alt="Attachment" src="/graphics/attach_black.gif" />'; else '&nbsp;';@@
        </td>
        <td>
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '<b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '<b>';@@
           <a class="msglist" href="msg.ssjs?msg_sub=^^sub:code^^&amp;message=^^messages:number^^">%%messages:subject%%</a>
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '</b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '</b>';@@
        </td>
        <td>
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '<b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '<b>';@@
           %%messages:from%%
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '</b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '</b>';@@
        </td>
        <td>
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '<b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '<b>';@@
           %%messages:to%%
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '</b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '</b>';@@
        </td>
        <td align="right" nowrap="nowrap">
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '<b>';@@
-          %%JS:system.timestr(@@messages:when_written_time@@)%%
-          @@JS:if(sub=='mail' && !(@@messages:attr@@ & MSG_READ)) '</b>';@@
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '<b>';@@
+          %%JS:system.timestr(RepeatObj.when_written_time)%%
+          @@JS:if(sub=='mail' && !(RepeatObj.attr & MSG_READ)) '</b>';@@
        </td>
     </tr>
     <<END REPEAT messages>>
diff --git a/web/templates/default/newuser.inc b/web/templates/default/newuser.inc
index 9db25de5ee2ea9cd0d9cfd83bd0d0aaba6dc6c37..97d67b2248186907fc2ff8dcd5b5191b2863fb15 100644
--- a/web/templates/default/newuser.inc
+++ b/web/templates/default/newuser.inc
@@ -63,7 +63,7 @@
             <tr>
             <td class="newuser">&nbsp;</td>
             <td class="newuser">
-                <input type="submit" value="Join!" />Join!
+                <input type="submit" value="Join!" />
             </td>
             </tr>
         </table>
diff --git a/web/templates/default/nodelist.inc b/web/templates/default/nodelist.inc
index 2cd75a441689fa7bfefc503caccdfcf1e1251e10..68505886e9f0c69621eccd12bb4bc0939f93ed94 100644
--- a/web/templates/default/nodelist.inc
+++ b/web/templates/default/nodelist.inc
@@ -27,9 +27,8 @@
                 <td class="main_nodelist" width="1%">@@who_online:node@@</td>  
                 <td class="main_nodelist"><a href="mailto:@@who_online:email@@">@@who_online:name@@</a></td>
                 <td class="main_nodelist">@@who_online:action@@</td>
-                @@JS:if(show_location)'<td class="main_nodelist" width="25%">@@who_online:location@@</td>'@@
-                @@JS:if(show_age)'<td class="main_nodelist" width="1%">%%who_online:age%%</td>'@@  
-                @@JS:if(show_gender)'<td class="main_nodelist" width="1%">@@who_online:gender@@</td>'@@    
+                @@JS:if(show_location)'<td class="main_nodelist" width="25%">'+Nz(RepeatObj.location)+'</td>'@@
+                @@JS:if(show_gender)'<td class="main_nodelist" width="1%">'+Nz(RepeatObj.gender)+'</td>'@@    
                 <td class="main_nodelist" width="1%">@@who_online:timeon@@</td>     
             </tr>
 <<END REPEAT who_online>>