Index: /branches/release-36/php/lib/function.mtsignoutlink.php
===================================================================
--- /branches/release-36/php/lib/function.mtsignoutlink.php (revision 2062)
+++ /branches/release-36/php/lib/function.mtsignoutlink.php (revision 2062)
@@ -0,0 +1,35 @@
+<?php
+# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
+# This program is distributed under the terms of the
+# GNU General Public License, version 2.
+#
+# $Id$
+
+function smarty_function_mtsignoutlink($args, &$ctx) {
+    // status: complete
+    // parameters: none
+    $entry = $ctx->stash('entry');
+    require_once "function.mtcgipath.php";
+    $path = smarty_function_mtcgipath($args, $ctx);
+    if (isset($args['no_static']) && ($args['no_static'] == 1)) {
+        $static_arg = '';
+    } else {
+        $url = $args['static'];
+        if (isset($url) && ($url != '1')) {
+            $static_arg = "&static=" . urlencode($url);
+        } else if (isset($url) && ($url == 1)) {
+            $static_arg = "&static=1";
+        } else {
+            $static_arg = "&static=0";
+        }
+    }
+
+    $path = $path . $ctx->mt->config('CommentScript') .
+        '?__mode=handle_sign_in' .
+        $static_arg .
+        '&logout=1';
+    if ($entry) {
+        $path .= '&entry_id=' . $entry['entry_id'];
+    }
+    return $path;
+}
Index: /branches/release-36/php/lib/function.mtcommentreplylink.php
===================================================================
--- /branches/release-36/php/lib/function.mtcommentreplylink.php (revision 1688)
+++ /branches/release-36/php/lib/function.mtcommentreplylink.php (revision 2062)
@@ -15,9 +15,12 @@
     $label or $label = $mt->translate("Reply");
 
+    $onclick = $args['onclick'];
+    $onclick or $onclick = 'mtCommentReplyOnClick';
+
     $comment_author = $comment['comment_author'];
     require_once("MTUtil.php");
     $comment_author = encode_js($comment_author);
 
-    return sprintf("<a title\"%s\" href=\"javascript:void(0);\" onclick=\"replyComment(%d, '%s')\">%s</a>",
+    return sprintf("<a title\"%s\" href=\"javascript:void(0);\" onclick=\"$onclick(%d, '%s')\">%s</a>",
         $label, $comment['comment_id'], $comment_author, $label);
 }
Index: /branches/release-36/php/lib/function.mtsigninlink.php
===================================================================
--- /branches/release-36/php/lib/function.mtsigninlink.php (revision 2062)
+++ /branches/release-36/php/lib/function.mtsigninlink.php (revision 2062)
@@ -0,0 +1,22 @@
+<?php
+# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
+# This program is distributed under the terms of the
+# GNU General Public License, version 2.
+#
+# $Id$
+
+function smarty_function_mtsigninlink($args, &$ctx) {
+    $blog = $ctx->stash('blog');
+    $entry = $ctx->stash('entry');
+    $static_arg = $args['static'] ? "&static=1" : "&static=0";
+
+    require_once "function.mtcgipath.php";
+    $path = smarty_function_mtcgipath($args, $ctx);
+    $return = $path . $ctx->mt->config('CommentScript') .
+        '?__mode=login' . $static_arg;
+    if ($blog)
+        $return .= '&blog_id' . $blog['blog_id'];
+    if ($entry)
+        $return .= '&entry_id' . $entry['entry_id'];
+    return $return;
+}
Index: /branches/release-36/php/lib/MTViewer.php
===================================================================
--- /branches/release-36/php/lib/MTViewer.php (revision 1956)
+++ /branches/release-36/php/lib/MTViewer.php (revision 2062)
@@ -363,5 +363,21 @@
         if (!isset($args['format'])) $args['format'] = null;
         require_once("MTUtil.php");
-        return format_ts($args['format'], $ts, $blog, isset($args['language']) ? $args['language'] : null);
+        $fds = format_ts($args['format'], $ts, $blog, isset($args['language']) ? $args['language'] : null);
+        if (isset($args['relative'])) {
+            if ($args['relative'] == 'js') {
+                preg_match('/(\d\d\d\d)[^\d]?(\d\d)[^\d]?(\d\d)[^\d]?(\d\d)[^\d]?(\d\d)[^\d]?(\d\d)/', $ts, $match);
+                list($xx, $y, $mo, $d, $h, $m, $s) = $match;
+                $mo--;
+                $js = <<<EOT
+<script type="text/javascript">
+/* <![CDATA[ */
+document.write(mtRelativeDate(new Date($y,$mo,$d,$h,$m,$s), '$fds'));
+/* ]]> */
+</script><noscript>$fds</noscript>
+EOT;
+                return $js;
+            }
+        }
+        return $fds;
     }
 
Index: /branches/release-36/default_templates/main_index.mtml
===================================================================
--- /branches/release-36/default_templates/main_index.mtml (revision 1923)
+++ /branches/release-36/default_templates/main_index.mtml (revision 2062)
@@ -6,4 +6,5 @@
     <$mt:include module="<__trans phrase="HTML Head">"$>
     <link rel="EditURI" type="application/rsd+xml" title="RSD" href="<$MTLink template="rsd"$>" />
+    <script type="text/javascript" src="<$MTLink template="javascript"$>"></script>
 </head>
 <body id="<$mt:BlogTemplateSetID$>" class="mt-main-index <$MTVar name="page_layout"$>">
Index: /branches/release-36/default_templates/page.mtml
===================================================================
--- /branches/release-36/default_templates/page.mtml (revision 1964)
+++ /branches/release-36/default_templates/page.mtml (revision 2062)
@@ -8,5 +8,5 @@
     <script type="text/javascript" src="<$MTLink template="javascript"$>"></script>
 </head>
-<body id="<$mt:BlogTemplateSetID$>" class="mt-page-archive <$MTVar name="page_layout"$>" onload="individualArchivesOnLoad(commenter_name)">
+<body id="<$mt:BlogTemplateSetID$>" class="mt-page-archive <$MTVar name="page_layout"$>" onload="mtEntryOnLoad()">
     <div id="container">
         <div id="container-inner">
Index: /branches/release-36/default_templates/entry_summary.mtml
===================================================================
--- /branches/release-36/default_templates/entry_summary.mtml (revision 1979)
+++ /branches/release-36/default_templates/entry_summary.mtml (revision 2062)
@@ -6,7 +6,7 @@
             <span class="byline">
     <MTIfNonEmpty tag="EntryAuthorDisplayName">
-                <__trans phrase="By [_1] on [_2]" params="<span class="vcard author"><$MTEntryAuthorLink show_hcard="1"$></span>%%<abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X"$></abbr>">
+                <__trans phrase="By [_1] on [_2]" params="<span class="vcard author"><$MTEntryAuthorLink show_hcard="1"$></span>%%<abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X" relative="js"$></abbr>">
     <MTElse>
-                <abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X"$></abbr>
+                <abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X" relative="js"$></abbr>
     </MTIfNonEmpty>
             </span>
Index: /branches/release-36/default_templates/entry.mtml
===================================================================
--- /branches/release-36/default_templates/entry.mtml (revision 1983)
+++ /branches/release-36/default_templates/entry.mtml (revision 2062)
@@ -10,5 +10,5 @@
     <script type="text/javascript" src="<$MTLink template="javascript"$>"></script>
 </head>
-<body id="<$mt:BlogTemplateSetID$>" class="mt-entry-archive <$MTVar name="page_layout"$>" onload="individualArchivesOnLoad(commenter_name)">
+<body id="<$mt:BlogTemplateSetID$>" class="mt-entry-archive <$MTVar name="page_layout"$>" onload="mtEntryOnLoad()">
     <div id="container">
         <div id="container-inner">
@@ -32,7 +32,7 @@
                                         <span class="byline">
 <MTIfNonEmpty tag="EntryAuthorDisplayName">
-                                            <__trans phrase="By [_1] on [_2]" params="<span class="vcard author"><$MTEntryAuthorLink show_hcard="1"$></span>%%<abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X"$></abbr>">
+                                            <__trans phrase="By [_1] on [_2]" params="<span class="vcard author"><$MTEntryAuthorLink show_hcard="1"$></span>%%<abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X" relative="js"$></abbr>">
 <MTElse>
-                                            <abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X"$></abbr>
+                                            <abbr class="published" title="<$MTEntryDate format_name="iso8601"$>"><$MTEntryDate format="%x %X" relative="js"$></abbr>
 </MTIfNonEmpty>
                                         </span>
Index: /branches/release-36/default_templates/javascript.mtml
===================================================================
--- /branches/release-36/default_templates/javascript.mtml (revision 1964)
+++ /branches/release-36/default_templates/javascript.mtml (revision 2062)
@@ -1,171 +1,472 @@
-function hideDocumentElement(id) {
-    var el = document.getElementById(id);
-    if (el)
-        el.style.display = 'none';
-}
-
-function showDocumentElement(id) {
-    var el = document.getElementById(id);
-    if (el)
-        el.style.display = 'block';
+<mt:ignore>
+/* The following functions are here to support legacy MT templates.
+   If you have refreshed your JavaScript template but still use older
+   MT comment templates, you may need to uncomment this block in order
+   for those templates to work properly. Simply remove the wrapping
+   'mt:ignore' tag to do so. */
+function hideDocumentElement(id) { return mtHide(id) }
+function showDocumentElement(id) { return mtShow(id) }
+function individualArchivesOnLoad() { return mtEntryOnLoad() }
+function writeCommenterGreeting() { return mtShowGreeting() }
+function rememberMe(f) { return mtRememberMe(f) }
+function forgetMe(f) { return mtForgetMe(f) }
+</mt:ignore>
+
+// The cookie name to use for storing the blog-side comment session cookie.
+var cookie_name = "mt_blog<$MTBlogID$>_user";
+// The cookie path to use for storing the blog-side comment session cookie.
+var blog_path = "<$MTBlogURL$>".replace(/^.*?\/\/[^\/]+?\//, '/');
+
+<mt:ignore>
+/***
+ * Simple routine for showing a DOM element (applying a CSS display
+ * attribute of 'none').
+ */
+</mt:ignore>
+function mtHide(id) {
+    var el = (typeof id == "string") ? document.getElementById(id) : id;
+    if (el) el.style.display = 'none';
+}
+
+<mt:ignore>
+/***
+ * Simple routine for showing a DOM element (applying a CSS display
+ * attribute of 'block').
+ */
+</mt:ignore>
+function mtShow(id) {
+    var el = (typeof id == "string") ? document.getElementById(id) : id;
+    if (el) el.style.display = 'block';
 }
 
 var captcha_timer;
-function showAnonymousForm() {
-    showDocumentElement('comments-form');
-<MTIfNonEmpty tag="MTCaptchaFields">
-    captcha_timer = setInterval('delayShowCaptcha()', 1000);
-</MTIfNonEmpty>
-}
-<MTIfNonEmpty tag="MTCaptchaFields">
-function delayShowCaptcha() {
-    clearInterval(captcha_timer);
+<mt:ignore>
+/***
+ * Used to display the comment form and captcha field.
+ */
+</mt:ignore>
+function mtShowAnonymousForm() {
+    mtShow('comments-form');
+    captcha_timer = setInterval('mtShowCaptcha()', 1000);
+}
+
+<mt:ignore>
+/***
+ * Displays a relative date.
+ * 'ts' is a Date object, 'fds' is a string of the date which
+ * will be displayed if the given date is older than 1 week.
+ */
+</mt:ignore>
+function mtRelativeDate(ts, fds) {
+    var now = new Date();
+    var ref = ts;
+    var delta = Math.floor((now.getTime() - ref.getTime()) / 1000);
+
+    var str;
+    if (delta < 60) {
+        str = '<__trans phrase="moments ago">';
+    } else if (delta <= 86400) {
+        // less than 1 day
+        var hours = Math.floor(delta / 3600);
+        var min = Math.floor((delta % 3600) / 60);
+        if (hours == 1)
+            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="1">';
+        else if (hours > 1)
+            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="2">'.replace(/2/, hours);
+        else if (min == 1)
+            str = '<__trans phrase="[quant,_1,minute,minutes] ago" params="1">';
+        else
+            str = '<__trans phrase="[quant,_1,minute,minutes] ago" params="2">'.replace(/2/, min);
+    } else if (delta <= 604800) {
+        // less than 1 week
+        var days = Math.floor(delta / 86400);
+        var hours = Math.floor((delta % 86400) / 3600);
+        if (days == 1)
+            str = '<__trans phrase="[quant,_1,day,days] ago" params="1">';
+        else if (days > 1)
+            str = '<__trans phrase="[quant,_1,day,days] ago" params="2">'.replace(/2/, days);
+        else if (hours == 1)
+            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="1">';
+        else
+            str = '<__trans phrase="[quant,_1,hour,hours] ago" params="2">'.replace(/2/, hours);
+    }
+    return str ? str : fds;
+}
+
+<mt:ignore>
+/***
+ * Used to display an edit link for the given entry.
+ */
+</mt:ignore>
+function mtEditLink(entry_id, author_id) {
+    var u = mtGetUser();
+    if (! u) return;
+    if (! entry_id) return;
+    if (! author_id) return;
+    if (u.id != author_id) return;
+    var link = '<__trans phrase='<a href="[_1]">Edit</a>' params="<$MTAdminScript$>?__mode=view&amp;_type=entry&amp;id=' + entry_id + '">';
+    document.write(link);
+}
+
+<mt:ignore>
+/***
+ * Displays a captcha field for anonymous commenters.
+ */
+</mt:ignore>
+function mtShowCaptcha() {
+    if (captcha_timer) clearInterval(captcha_timer);
     var div = document.getElementById('comments-open-captcha');
     if (div)
         div.innerHTML = '<$MTCaptchaFields$>';
 }
-</MTIfNonEmpty>
-
-var AUTHOR = 1;
-var COMMENTER = 2;
-var commenter_name;
-var commenter_status;
-var commenter_id;
-var commenter_url
+
+<mt:ignore>
+/* user object
+    -- saved in user cookie --
+    u.name (display name)
+    u.url (link to home page)
+    u.email (for anonymous only)
+    u.userpic (url for commenter/author)
+    u.profile (link to profile)
+    u.is_trusted (boolean)
+    u.is_author (user has posting rights)
+    u.is_banned (banned status; neither post/comment perms)
+    u.can_post (has permission to post)
+    u.can_comment (has permission to comment)
+
+    -- status fields --
+    u.is_authenticated (boolean)
+    u.is_anonymous (user is anonymous)
+*/
+</mt:ignore>
+
 var is_preview;
-var mtcmtmail;
-var mtcmtauth;
-var mtcmthome;
-
-function individualArchivesOnLoad(commenter_name) {
-    hideDocumentElement('comment-form-reply');
-<MTIfCommentsAccepted>
-<MTElse>
-    hideDocumentElement('comments-open');
-</MTIfCommentsAccepted>
-<MTIfPingsAccepted>
-<MTElse>
-    hideDocumentElement('trackbacks-info');
-</MTIfPingsAccepted>
-<MTIfRegistrationAllowed>
-    <MTIfRegistrationRequired>
-    if ( commenter_status > 0 ) {
-        hideDocumentElement('comment-form-name');
-        hideDocumentElement('comment-form-email');
-        hideDocumentElement('comment-form-url');
-        hideDocumentElement('comment-form-remember-me');
-        showDocumentElement('comments-open-text');
-        showDocumentElement('comments-open-footer');
+var user;
+<mt:ignore>
+/***
+ * Assigns a user object as the actively logged in user; also saves the
+ * user information in a browser cookie.
+ */
+</mt:ignore>
+function mtSetUser(u) {
+    if (u) {
+        // persist this
+        user = u;
+        mtSaveUser();
+    }
+}
+
+<mt:ignore>
+/***
+ * Simple function that escapes single quote characters for storing
+ * in a cookie.
+ */
+</mt:ignore>
+function mtEscapeJS(s) {
+    s = s.replace(/'/g, "&apos;");
+    return s;
+}
+
+<mt:ignore>
+/***
+ * Simple function that unescapes single quote characters that were
+ * stored in a cookie.
+ */
+</mt:ignore>
+function mtUnescapeJS(s) {
+    s = s.replace(/&apos;/g, "'");
+    return s;
+}
+
+<mt:ignore>
+/***
+ * Serializes a user object into a string, suitable for storing as a cookie.
+ */
+</mt:ignore>
+function mtBakeUserCookie(u) {
+    var str = "";
+    if (u.name) str += "name:'" + mtEscapeJS(u.name) + "';";
+    if (u.url) str += "url:'" + mtEscapeJS(u.url) + "';";
+    if (u.email) str += "email:'" + mtEscapeJS(u.email) + "';";
+    if (u.is_authenticated) str += "is_authenticated:'1';";
+    if (u.profile) str += "profile:'" + mtEscapeJS(u.profile) + "';";
+    if (u.userpic) str += "userpic:'" + mtEscapeJS(u.userpic) + "';";
+    str += "is_trusted:'" + (u.is_trusted ? "1" : "0") + "';";
+    str += "is_author:'" + (u.is_author ? "1" : "0") + "';";
+    str += "is_banned:'" + (u.is_banned ? "1" : "0") + "';";
+    str += "can_post:'" + (u.can_post ? "1" : "0") + "';";
+    str += "can_comment:'" + (u.can_comment ? "1" : "0") + "';";
+    str = str.replace(/;$/, '');
+    return str;
+}
+
+<mt:ignore>
+/***
+ * Unserializes a user cookie and returns a user object with the restored
+ * state.
+ */
+</mt:ignore>
+function mtUnbakeUserCookie(s) {
+    if (!s) return;
+
+    var u = {};
+    var m;
+    while (m = s.match(/^((name|url|email|is_authenticated|profile|userpic|is_trusted|is_author|is_banned|can_post|can_comment):'([^']+?)';?)/)) {
+        s = s.substring(m[1].length);
+        if (m[2].match(/^(is|can)_/)) // boolean fields
+            u[m[2]] = m[3] == '1' ? true : false;
+        else
+            u[m[2]] = mtUnescapeJS(m[3]);
+    }
+    if (u.is_authenticated) {
+        u.is_anonymous = false;
     } else {
-        hideDocumentElement('comments-open-data');
-        hideDocumentElement('comments-open-text');
-        hideDocumentElement('comments-open-footer');
-    }
-    <MTElse>
-    // comments are allowed but registration not required
-    if ( commenter_status > 0 ) {
-        hideDocumentElement('comment-form-name');
-        hideDocumentElement('comment-form-email');
-    } else if (is_preview) {
-<MTIfNonEmpty tag="MTCaptchaFields">
-        delayShowCaptcha();
-</MTIfNonEmpty>
+        u.is_anonymous = true;
+        u.can_post = false;
+        u.is_author = false;
+        u.is_banned = false;
+        u.is_trusted = false;
+    }
+    return u;
+}
+
+<mt:ignore>
+/***
+ * Retrieves an object of the currently logged in user's state.
+ * If no user is logged in or cookied, this will return null.
+ */
+</mt:ignore>
+function mtGetUser() {
+    if (!user) {
+        var cookie = mtGetCookie(cookie_name);
+        if (!cookie) return;
+        user = mtUnbakeUserCookie(cookie);
+        if (! user) {
+            user = {};
+            user.is_anonymous = true;
+            user.can_post = false;
+            user.is_author = false;
+            user.is_banned = false;
+            user.is_trusted = false;
+        }
+    }
+    return user;
+}
+
+<mt:ignore>
+/***
+ * Issues a request to the MT comment script to retrieve the currently
+ * logged-in user (if any).
+ */
+</mt:ignore>
+function mtFetchUser() {
+    document.write('<scr' + 'ipt src="<$MTCGIPath$><$MTCommentScript$>?__mode=session_js&blog_id=<$MTBlogID$>&jsonp=mtSetUser"></scr' + 'ipt>');
+}
+
+<mt:ignore>
+/***
+ * Called when the 'Remember me' checkbox is changed. If the checkbox
+ * is cleared, the cached user cookie is immediately cleared.
+ */
+</mt:ignore>
+function mtRememberMeOnClick(b) {
+    if (!b.checked)
+        mtClearUser(b.form);
+    return true;
+}
+
+<mt:ignore>
+/***
+ * Called when comment form is sent.
+ * Required parameter: Form DOM object of comment form.
+ * If form has a 'bakecookie' member, it will be used to signal
+ * storing the anonymous commenter information to a cookie.
+ * If form has a 'armor' member, it will be used to store
+ * a token that is checked by the comment script.
+ */
+</mt:ignore>
+var mtRequestSubmitted = false;
+function mtCommentOnSubmit(f) {
+    if (!mtRequestSubmitted) {
+        mtRequestSubmitted = true;
+
+        if (f.armor)
+            f.armor.value = '<$MTBlogSitePath encode_sha1="1"$>';
+        if (f.bakecookie && f.bakecookie.checked)
+            mtSaveUser(f);
+
+        // disable submit buttons
+        if (f.preview_button) f.preview_button.disabled = true;
+        if (f.post) f.post.disabled = true;
+        if (f.preview.value == '1')
+            f.preview_button.value = '<__trans phrase="Posting...">';
+        else
+            f.post.value = '<__trans phrase="Posting...">';
+
+        return true;
+    }
+    return false;
+}
+
+<mt:ignore>
+/***
+ * Called when an entry archive page is loaded.
+ * This routine controls which elements of the comment form are shown
+ * or hidden, depending on commenter type and blog configuration.
+ */
+</mt:ignore>
+function mtEntryOnLoad() {
+    var u = mtGetUser();
+
+<mt:unless tag="IfCommentsAccepted">
+    mtHide('comments-open');
+</mt:unless>
+<mt:unless tag="IfPingsAccepted">
+    mtHide('trackbacks-info');
+</mt:unless>
+
+<mt:IfRegistrationRequired>
+    if ( !u || u.is_anonymous ) {
+        mtHide('comments-open-data');
+        mtHide('comments-open-text');
+        mtHide('comments-open-footer');
     } else {
-        hideDocumentElement('comments-form');
-    }
-    </MTIfRegistrationRequired>
-</MTIfRegistrationAllowed>
-
+        mtHide('comments-open-data');
+        mtShow('comments-open-text');
+        mtShow('comments-open-footer');
+    }
+<mt:else>
+<mt:IfRegistrationAllowed>
+    if (is_preview && u && u.is_anonymous) {
+        mtShowAnonymousForm();
+    } else {
+        // comments are allowed but registration not required
+        if ( !u || u.is_anonymous )
+            mtHide('comments-form');
+        else
+            mtHide('comments-open-data');
+    }
+<mt:else>
+    mtShowAnonymousForm();
+</mt:IfRegistrationAllowed>
+</mt:IfRegistrationRequired>
+
+    mtShowGreeting();
+
+    // populate anonymous comment fields if
+    // user is cookied as anonymous
     var cf = document.comments_form;
     if (cf) {
-        if (!commenter_name && (cf.email != undefined) &&
-            (mtcmtmail = getCookie("mtcmtmail")))
-            cf.email.value = mtcmtmail;
-        if (!commenter_name && (cf.author != undefined) &&
-            (mtcmtauth = getCookie("mtcmtauth")))
-            cf.author.value = mtcmtauth;
-        if (cf.url != undefined &&
-            (mtcmthome = getCookie("mtcmthome")))
-            cf.url.value = mtcmthome;
-        if (cf["bakecookie"]) {
-            if (mtcmtauth || mtcmthome) {
-                cf.bakecookie.checked = true;
+        if (u && u.is_anonymous) {
+            if (u.email) cf.email.value = u.email;
+            if (u.name) cf.author.value = u.name;
+            if (u.url) cf.url.value = u.url;
+            if (cf.bakecookie)
+                cf.bakecookie.checked = u.name || u.email;
+        }
+        if (cf.post.disabled) {
+            cf.post.disabled = false;
+            cf.post.value = '<__trans phrase="Submit">';
+        }
+        if (cf.preview_button.disabled) {
+            cf.preview_button.disabled = false;
+            cf.preview_button.value = '<__trans phrase="Preview">';
+        }
+    }
+}
+
+<mt:ignore>
+/***
+ * Handles the action of the "Sign in" link. First clears any existing
+ * user cookie, then directs to the MT comment script to sign the user in.
+ */
+</mt:ignore>
+function mtSignIn(entry_id) {
+    var doc_url = document.URL;
+    doc_url = doc_url.replace(/#.+/, '');
+    var url = '<$MTSignInLink$>&entry_id=' + entry_id +
+        '&return_to=' + encodeURIComponent(doc_url);
+    mtClearUser();
+    location.href = url;
+}
+
+<mt:ignore>
+/***
+ * Handles the action of the "Sign out" link. First clears any existing
+ * user cookie, then direts to the MT comment script to sign the user out.
+ */
+</mt:ignore>
+function mtSignOut(entry_id) {
+    var url = '<$MTSignOutLink$>&entry_id=' + entry_id;
+    mtClearUser();
+    location.href = url;
+}
+
+<mt:ignore>
+/***
+ * Handles the display of the greeting message, depending on what kind of
+ * user is logged in and blog comment policy.
+ */
+</mt:ignore>
+function mtShowGreeting() {
+<mt:IfRegistrationAllowed>
+    var reg_reqd = <mt:IfRegistrationRequired>true<mt:else>false</mt:IfRegistrationRequired>;
+
+    var cf = document.comments_form;
+    if (!cf) return;
+
+    var el = document.getElementById('comment-greeting');
+    if (!el)  // legacy MT 4.x element id
+        el = document.getElementById('comment-form-external-auth');
+    if (!el) return;
+
+    var eid = cf.entry_id;
+    var entry_id;
+    if (eid) entry_id = eid.value;
+
+    var phrase;
+    var u = mtGetUser();
+
+    if ( u && u.is_authenticated ) {
+        if ( u.is_banned ) {
+            phrase = '<__trans phrase="You do not have permission to comment on this blog. ([_1]sign out[_2])" params="<a href="javascript:void(0);" onclick="mtSignOut(' + entry_id + ')">%%</a>">';
+        } else {
+            var user_link;
+            if ( u.is_author ) {
+                user_link = '<a href="<$MTCGIPath$><$MTCommentScript$>?__mode=edit_profile&blog_id=<$MTBlogID$>';
+                if (entry_id)
+                    user_link += '&entry_id=' + entry_id;
+                user_link += '">' + u.name + '</a>';
             } else {
-                cf.bakecookie.checked = false;
+                // registered user, but not a user with posting rights
+                if (u.url)
+                    user_link = '<a href="' + u.url + '">' + u.name + '</a>';
+                else
+                    user_link = u.name;
             }
+            // TBD: supplement phrase with userpic if one is available.
+            phrase = '<__trans phrase="Thanks for signing in, [_1]. ([_2]sign out[_3])" params="' + user_link + '%%<a href="javascript:void(0)" onclick="mtSignOut(' + entry_id + ')">%%</a>">';
         }
-    }
-}
-
-function writeCommenterGreeting(commenter_name, entry_id, blog_id, commenter_id, commenter_url) {
-<MTIfRegistrationAllowed>
-    if ( commenter_status > 0 ) {
-        var commenter_link;
-        if ( commenter_status == COMMENTER ) {
-            if (commenter_url) {
-                commenter_link = '<a href="' + commenter_url + '">' + commenter_name + '</a>';
-            } else {
-                commenter_link = commenter_name;
-            }
-        } else if ( commenter_status == AUTHOR ) {
-            if (commenter_id) {
-                commenter_link = '<a href="<$MTCGIPath$><$MTCommentScript$>?__mode=edit_profile&commenter=' + commenter_id + '&blog_id=' + blog_id;
-                if (entry_id) {
-                    commenter_link += '&entry_id=' + entry_id;
-                } else {
-                    commenter_link += '&static=1';
-                }
-                commenter_link += '">' + commenter_name + '</a>';
-            }
-
+    } else {
+        if (reg_reqd) {
+            phrase = '<__trans phrase="[_1]Sign in[_2] to comment." params="<a href="javascript:void(0)" onclick="mtSignIn()">%%</a>">';
+        } else {
+            phrase = '<__trans phrase="[_1]Sign in[_2] to comment, or [_3]comment anonymously[_2]." params="<a href="javascript:void(0)" onclick="mtSignIn(' + entry_id + ')">%%</a>%%<a href="javascript:void(0);" onclick="mtShowAnonymousForm();">">';
         }
-        document.write(
-            '<__trans phrase="Thanks for signing in, [_1]. Now you can comment. ([_2]sign out[_3])" params="' + commenter_link + '%%<a href="<$MTRemoteSignOutLink static="1"$>&entry_id=' + entry_id + '">%%</a>">'
-        );
-    } else if (commenter_name) {
-        document.write('<__trans phrase="You do not have permission to comment on this blog. ([_1]sign out[_2])" params="<a href="<$MTRemoteSignOutLink static="1"$>&entry_id=' + entry_id + '">%%</a>">');
-    } else {
-<MTIfRegistrationRequired>
-        var phrase = '<__trans phrase="[_1]Sign in[_2] to comment on this entry." params="<a href="<$MTCGIPath$><$MTCommentScript$>?__mode=login&entry_id=' + entry_id + '&blog_id=' + blog_id + '&static=1&return_to=' + encodeURIComponent(document.URL) + '">%%</a>">';
-<MTElse>
-        var phrase = '<__trans phrase="[_1]Sign in[_2] to comment on this entry, or [_3]comment anonymously[_2]." params="<a href="<$MTCGIPath$><$MTCommentScript$>?__mode=login&entry_id=' + entry_id + '&blog_id=' + blog_id + '&static=1&return_to=' + encodeURIComponent(document.URL) + '">%%</a>%%<a href="javascript:void(0);" onclick="showAnonymousForm();">">';
-</MTIfRegistrationRequired>
-        document.write(phrase);
-    }
-</MTIfRegistrationAllowed>
-}
-
-<MTIfRegistrationAllowed>
-<$MTCGIHost exclude_port="1" setvar="cgi_host"$><$MTBlogHost exclude_port="1" setvar="blog_host"$>
-<MTIf name="cgi_host" eq="$blog_host">
-commenter_name = getCookie('commenter_name');
-commenter_url = getCookie('commenter_url');
-ids = getCookie('commenter_id').split(':');
-commenter_id = ids[0];
-if ( ids[1] == 'S' ) {
-    commenter_status = AUTHOR;
-}
-else if ( ids[1] == 'N' ) {
-    document.write('<script src="<$MTCGIPath$><$MTCommentScript$>?__mode=cmtr_status_js&blog_id=<$MTBlogID$>"></script>');
-}
-else if ( commenter_name && !commenter_id ) {
-    commenter_status = COMMENTER;
-}
-else if ( commenter_name 
-  && commenter_id
-  && ( ids[1].indexOf("'<$MTBlogID$>'") > -1 ) ) {
-    commenter_status = AUTHOR;
-}
-else {
-    commenter_status = 0;
-}
-<MTElse>
-document.write('<script src="<$MTCGIPath$><$MTCommentScript$>?__mode=cmtr_name_js&blog_id=<$MTBlogID$>"></script>');
-</MTIf>
-</MTIfRegistrationAllowed>
-
-function replyComment(parent_id, author) {
-    showDocumentElement('comment-form-reply');
-    
+    }
+    el.innerHTML = phrase;
+<mt:else>
+    mtShowCaptcha();
+</mt:IfRegistrationAllowed>
+}
+
+<mt:ignore>
+/***
+ * Handles the action of the 'Reply' links.
+ */
+</mt:ignore>
+function mtReplyCommentOnClick(parent_id, author) {
+    mtShow('comment-form-reply');
+
     var checkbox = document.getElementById('comment-reply');
     var label = document.getElementById('comment-reply-label');
@@ -180,74 +481,155 @@
     text.focus();
 
-    setCommentParentID();
-}
-
-function setCommentParentID() {
+    mtSetCommentParentID();
+}
+
+<mt:ignore>
+/***
+ * Sets the parent comment ID when replying to a comment.
+ */
+</mt:ignore>
+function mtSetCommentParentID() {
     var checkbox = document.getElementById('comment-reply');
     var parent_id_field = document.getElementById('comment-parent-id');
+    if (!checkbox || !parent_id_field) return;
+
     var pid = 0;
-    
-    if(checkbox.checked == true)
+    if (checkbox.checked == true)
         pid = checkbox.value;
-    
     parent_id_field.value = pid;
 }
 
-
-// Copyright (c) 1996-1997 Athenia Associates.
-// http://www.webreference.com/js/
-// License is granted if and only if this entire
-// copyright notice is included. By Tomer Shiran.
-
-    function setCookie (name, value, expires, path, domain, secure) {
-        var curCookie = name + "=" + escape(value) + (expires ? "; expires=" + expires.toGMTString() : "") +
-            (path ? "; path=" + path : "") + (domain ? "; domain=" + domain : "") + (secure ? "secure" : "");
-        document.cookie = curCookie;
-    }
-
-    function getCookie (name) {
-        var prefix = name + '=';
-        var c = document.cookie;
-        var nullstring = '';
-        var cookieStartIndex = c.indexOf(prefix);
-        if (cookieStartIndex == -1)
-            return nullstring;
-        var cookieEndIndex = c.indexOf(";", cookieStartIndex + prefix.length);
-        if (cookieEndIndex == -1)
-            cookieEndIndex = c.length;
-        return unescape(c.substring(cookieStartIndex + prefix.length, cookieEndIndex));
-    }
-
-    function deleteCookie (name, path, domain) {
-        if (getCookie(name))
-            document.cookie = name + "=" + ((path) ? "; path=" + path : "") +
-                ((domain) ? "; domain=" + domain : "") + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
-    }
-
-    function fixDate (date) {
-        var base = new Date(0);
-        var skew = base.getTime();
-        if (skew > 0)
-            date.setTime(date.getTime() - skew);
-    }
-
-    function rememberMe (f) {
-        var now = new Date();
-        fixDate(now);
-        now.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
-        if (f.author != undefined)
-           setCookie('mtcmtauth', f.author.value, now, '/', '', '');
-        if (f.email != undefined)
-           setCookie('mtcmtmail', f.email.value, now, '/', '', '');
-        if (f.url != undefined)
-           setCookie('mtcmthome', f.url.value, now, '/', '', '');
-    }
-
-    function forgetMe (f) {
-        deleteCookie('mtcmtmail', '/', '');
-        deleteCookie('mtcmthome', '/', '');
-        deleteCookie('mtcmtauth', '/', '');
-    }
-
+<mt:ignore>
+/***
+ * Persists a copy of the current user cookie into the browser cookie stash.
+ */
+</mt:ignore>
+function mtSaveUser(f) {
+    // We can't reliably store the user cookie during a preview.
+    if (is_preview) return;
+
+    var u = mtGetUser();
+
+    if (f && (!u || u.is_anonymous)) {
+        if ( !u ) {
+            u = {};
+            u.is_authenticated = false;
+            u.can_comment = true;
+            u.is_author = false;
+            u.is_banned = false;
+            u.is_anonymous = true;
+            u.is_trusted = false;
+        }
+        if (f.author != undefined) u.name = f.author.value;
+        if (f.email != undefined) u.email = f.email.value;
+        if (f.url != undefined) u.url = f.url.value;
+    }
+
+    if (!u) return;
+
+    var cache_period = 60 * 60 * 1000; // 1 hour
+
+    // cache anonymous user info for a long period if the
+    // user has requested to be remembered
+    if (u.is_anonymous && f && f.bakecookie && f.bakecookie.checked)
+        cache_period = 365 * 24 * 60 * 60 * 1000;
+
+    var now = new Date();
+    mtFixDate(now);
+    now.setTime(now.getTime() + cache_period);
+
+    var cmtcookie = mtBakeUserCookie(u);
+    mtSetCookie(cookie_name, cmtcookie, now, blog_path, null,
+        location.protocol == 'https:');
+}
+
+<mt:ignore>
+/***
+ * Clears the blog-side user cookie.
+ */
+</mt:ignore>
+function mtClearUser() {
+    mtDeleteCookie(cookie_name, blog_path);
+}
+
+<mt:ignore>
+/***
+ * Sets a browser cookie.
+ */
+</mt:ignore>
+function mtSetCookie(name, value, expires, path, domain, secure) {
+    var curCookie = name + "=" + escape(value) +
+        (expires ? "; expires=" + expires.toGMTString() : "") +
+        (path ? "; path=" + path : "") +
+        (domain ? "; domain=" + domain : "") +
+        (secure ? "; secure" : "");
+    document.cookie = curCookie;
+}
+
+<mt:ignore>
+/***
+ * Retrieves a browser cookie.
+ */
+</mt:ignore>
+function mtGetCookie (name) {
+    var prefix = name + '=';
+    var c = document.cookie;
+    var cookieStartIndex = c.indexOf(prefix);
+    if (cookieStartIndex == -1)
+        return '';
+    var cookieEndIndex = c.indexOf(";", cookieStartIndex + prefix.length);
+    if (cookieEndIndex == -1)
+        cookieEndIndex = c.length;
+    return unescape(c.substring(cookieStartIndex + prefix.length, cookieEndIndex));
+}
+
+<mt:ignore>
+/***
+ * Deletes a browser cookie.
+ */
+</mt:ignore>
+function mtDeleteCookie (name, path, domain, secure) {
+    if (mtGetCookie(name))
+        document.cookie = name + "=" +
+            (path ? "; path=" + path : "") +
+            (domain ? "; domain=" + domain : "") +
+            (secure ? "; secure" : "") +
+            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
+}
+
+function mtFixDate(date) {
+    var skew = (new Date(0)).getTime();
+    if (skew > 0)
+        date.setTime(date.getTime() - skew);
+}
+
+<mt:ignore>
+/***
+ * Returns a XMLHttpRequest object (for Ajax operations).
+ */
+</mt:ignore>
+function mtGetXmlHttp() {
+    if ( !window.XMLHttpRequest ) {
+        window.XMLHttpRequest = function() {
+            var types = [
+                "Microsoft.XMLHTTP",
+                "MSXML2.XMLHTTP.5.0",
+                "MSXML2.XMLHTTP.4.0",
+                "MSXML2.XMLHTTP.3.0",
+                "MSXML2.XMLHTTP"
+            ];
+
+            for ( var i = 0; i < types.length; i++ ) {
+                try {
+                    return new ActiveXObject( types[ i ] );
+                } catch( e ) {}
+            }
+
+            return undefined;
+        };
+    }
+    if ( window.XMLHttpRequest )
+        return new XMLHttpRequest();
+}
 
 // BEGIN: fast browser onload init
@@ -256,25 +638,25 @@
 // http://dean.edwards.name/weblog/2006/06/again/?full#comment5338
 
-function init() {
-  // quit if this function has already been called
-  if (arguments.callee.done) return;
-
-  // flag this function so we don't do the same thing twice
-  arguments.callee.done = true;
-
-  // kill the timer
-  // DWD - check against window
-  if ( window._timer ) clearInterval(window._timer);
-  
-  // DWD - fire the window onload now, and replace it
-  if ( window.onload && ( window.onload !== window.init ) ) {
-    window.onload();
-    window.onload = function() {};
-  }
-};
+function mtInit() {
+    // quit if this function has already been called
+    if (arguments.callee.done) return;
+
+    // flag this function so we don't do the same thing twice
+    arguments.callee.done = true;
+
+    // kill the timer
+    // DWD - check against window
+    if ( window._timer ) clearInterval(window._timer);
+
+    // DWD - fire the window onload now, and replace it
+    if ( window.onload && ( window.onload !== window.mtInit ) ) {
+        window.onload();
+        window.onload = function() {};
+    }
+}
 
 /* for Mozilla/Opera9 */
 if (document.addEventListener) {
-  document.addEventListener("DOMContentLoaded", init, false);
+    document.addEventListener("DOMContentLoaded", mtInit, false);
 }
 
@@ -282,25 +664,42 @@
 /*@cc_on @*/
 /*@if (@_win32)
-  document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
-  var script = document.getElementById("__ie_onload");
-  script.onreadystatechange = function() {
+document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
+var script = document.getElementById("__ie_onload");
+script.onreadystatechange = function() {
     if (this.readyState == "complete") {
-      init(); // call the onload handler
-    }
-  };
+        mtInit(); // call the onload handler
+    }
+};
 /*@end @*/
 
 /* for Safari */
 if (/WebKit/i.test(navigator.userAgent)) { // sniff
-  _timer = setInterval(function() {
-    if (/loaded|complete/.test(document.readyState)) {
-      init(); // call the onload handler
-    }
-  }, 10);
+    _timer = setInterval(function() {
+        if (/loaded|complete/.test(document.readyState)) {
+            mtInit(); // call the onload handler
+        }
+    }, 10);
 }
 
 /* for other browsers */
-window.onload = init;
+window.onload = mtInit;
 
 // END: fast browser onload init
 
+<mt:IfRegistrationAllowed>
+/***
+ * If request contains a '#_login' or '#_logout' hash, use this to
+ * also delete the blog-side user cookie, since we're coming back from
+ * a login, logout or edit profile operation.
+ */
+var clearCookie = ( window.location.hash && window.location.hash.match( /^#_log(in|out)/ ) ) ? true : false;
+if (clearCookie) {
+    // clear any logged in state
+    mtClearUser();
+    if (RegExp.$1 == 'in')
+        mtFetchUser();
+} else if (! mtGetUser()) {
+    // gather user info
+    mtFetchUser();
+}
+</mt:IfRegistrationAllowed>
Index: /branches/release-36/default_templates/trackbacks.mtml
===================================================================
--- /branches/release-36/default_templates/trackbacks.mtml (revision 1976)
+++ /branches/release-36/default_templates/trackbacks.mtml (revision 2062)
@@ -2,5 +2,5 @@
 <MTIfPingsActive>
 <div id="trackbacks" class="trackbacks">
-    <h2 class="trackbacks-header"><$MTEntryTrackbackCount singular="<__trans phrase="1 TrackBack">" plural="<__trans phrase="# TrackBacks">"$></h2>
+    <h2 class="trackbacks-header"><$MTEntryTrackbackCount singular="<__trans phrase="1 TrackBack">" plural="<__trans phrase="# TrackBacks">" none="<__trans phrase="No TrackBacks">"$></h2>
 
     <mt:ignore><!-- Display TrackBack details if TrackBacks are being accepted --></mt:ignore>
@@ -21,5 +21,5 @@
                 <div class="trackback-header">
                     <div class="asset-meta">
-                        <__trans phrase="<a href="[_1]">[_2]</a> from [_3] on <a href="[_4]">[_5]</a>" params="<$MTPingURL$>%%<$MTPingTitle$>%%<$MTPingBlogName$>%%#ping-<$MTPingID$>%%<$MTPingDate$>">
+                        <__trans phrase="<a href="[_1]">[_2]</a> from [_3] on <a href="[_4]">[_5]</a>" params="<$MTPingURL$>%%<$MTPingTitle$>%%<$MTPingBlogName$>%%#ping-<$MTPingID$>%%<$MTPingDate relative="js"$>">
                     </div>
                 </div>
Index: /branches/release-36/default_templates/comments.mtml
===================================================================
--- /branches/release-36/default_templates/comments.mtml (revision 1976)
+++ /branches/release-36/default_templates/comments.mtml (revision 2062)
@@ -1,14 +1,18 @@
-<mt:ignore><!-- Display comments for the entry/page or commenting form if entry/page is accepting comments --></mt:ignore>
+<mt:ignore>
+<!-- Display comments for the entry/page or commenting form if entry/page is accepting comments -->
+</mt:ignore>
 <MTIfCommentsActive>
 <div id="comments" class="comments">
 
 
-    <mt:ignore><!-- Display comments --></mt:ignore>
+    <mt:ignore>
+    <!-- Display comments -->
+    </mt:ignore>
     <MTComments>
         <MTCommentsHeader>
-    <h2 class="comments-header"><$MTEntryCommentCount singular="<__trans phrase="1 Comment">" plural="<__trans phrase="# Comments">"$></h2>
+    <h2 class="comments-header"><$MTEntryCommentCount singular="<__trans phrase="1 Comment">" plural="<__trans phrase="# Comments">" none="<__trans phrase="No Comments">"$></h2>
     <div class="comments-content">
         </MTCommentsHeader>
-        <div class="comment<mt:IfCommentParent> comment-reply</mt:IfCommentParent>"<MTIfArchiveTypeEnabled archive_type="Individual"> id="comment-<$MTCommentID$>"</MTIfArchiveTypeEnabled>>
+        <div class="comment<mt:IfCommentParent> comment-reply</mt:IfCommentParent>" id="comment-<$MTCommentID$>">
             <div class="inner">
                 <div class="comment-header">
@@ -16,9 +20,10 @@
                         <span class="byline">
                             <mt:IfCommentParent>
-                                <__trans phrase="[_1] replied to <a href="[_2]">comment from [_3]</a>" params="<MTIfNonEmpty tag="CommentAuthorIdentity"><$MTCommentAuthorIdentity$></MTIfNonEmpty> <span class="vcard author"><$MTCommentAuthorLink default_name="Anonymous" show_email="0"$></span>%%<mt:CommentParent>#comment-<$MTCommentID$></mt:CommentParent>%%<mt:CommentParent><$MTCommentAuthor$></mt:CommentParent>">
+                                <__trans phrase="[_1] replied to <a href="[_2]">comment from [_3]</a>" params="<MTIf tag="CommentAuthorIdentity"><$MTCommentAuthorIdentity$></MTIf> <span class="vcard author"><$MTCommentAuthorLink$></span>%%<mt:CommentParent>#comment-<$MTCommentID$></mt:CommentParent>%%<mt:CommentParent><$MTCommentAuthor$></mt:CommentParent>">
                             <mt:else>
-                                <MTIfNonEmpty tag="CommentAuthorIdentity"><$MTCommentAuthorIdentity$></MTIfNonEmpty> <span class="vcard author"><$MTCommentAuthorLink default_name="Anonymous" show_email="0"$></span>
+                                <$MTCommentAuthorIdentity$>
+                                <span class="vcard author"><$MTCommentAuthorLink$></span>
                             </mt:IfCommentParent>
-                            | <a href="#comment-<$MTCommentID$>"><abbr class="published" title="<$MTCommentDate format_name="iso8601"$>"><$MTCommentDate$></abbr></a>
+                            | <a href="#comment-<$MTCommentID$>"><abbr class="published" title="<$MTCommentDate format_name="iso8601"$>"><$MTCommentDate relative="js"$></abbr></a>
                             <MTIfCommentsAccepted> | <$MTCommentReplyLink$></MTIfCommentsAccepted>
                         </span>
@@ -36,5 +41,7 @@
 
 
-    <mt:ignore><!-- Display commenting form if entry/page is accepting comments --></mt:ignore>
+    <mt:ignore>
+    <!-- Display commenting form if entry/page is accepting comments -->
+    </mt:ignore>
     <MTIfCommentsAccepted>
     <div class="comments-open" id="comments-open">
@@ -42,22 +49,16 @@
         <div class="comments-open-content">
 
+        <mt:ignore>
+        <!-- Display greeting for users if blog allows users to register locally -->
+        </mt:ignore>
+            <div id="comment-greeting"></div>
 
-        <mt:ignore><!-- Display greeting for users if blog allows users to register locally --></mt:ignore>
-        <MTIfRegistrationAllowed>
-            <div id="comment-form-external-auth">
-                <script type="text/javascript">
-                /* <![CDATA[ */
-                writeCommenterGreeting(commenter_name, <$MTEntryID$>, <$MTEntryBlogID$>, commenter_id, commenter_url);
-                /* ]]> */
-                </script>
-            </div>
-        </MTIfRegistrationAllowed>
-
-
-            <form method="post" action="<$MTCGIPath$><$MTCommentScript$>" name="comments_form" id="comments-form" onsubmit="if (this.bakecookie.checked) rememberMe(this)">
+            <form method="post" action="<$MTCGIPath$><$MTCommentScript$>" name="comments_form" id="comments-form" onsubmit="return mtCommentOnSubmit(this)">
                 <input type="hidden" name="static" value="1" />
                 <input type="hidden" name="entry_id" value="<$MTEntryID$>" />
                 <input type="hidden" name="__lang" value="<$MTBlogLanguage$>" />
-                <input type="hidden" name="parent_id" value="<MTIf name="comment_preview_template"><$MTCommentParentID$></MTIf>" id="comment-parent-id" />
+                <input type="hidden" name="parent_id" value="<$MTCommentParentID$>" id="comment-parent-id" />
+                <input type="hidden" name="armor" value="1" />
+                <input type="hidden" name="preview" value="" />
                 <div id="comments-open-data">
                     <div id="comment-form-name">
@@ -74,23 +75,20 @@
                     </div>
                     <div id="comment-form-remember-me">
-                        <input type="checkbox" id="comment-bake-cookie" name="bakecookie" onclick="if (!this.checked) forgetMe(document.comments_form)" value="1" />
+                        <input type="checkbox" id="comment-bake-cookie" name="bakecookie" onclick="mtRememberMeOnClick(this)" value="1" accesskey="r" />
                         <label for="comment-bake-cookie"><__trans phrase="Remember personal info?"></label>
                     </div>
-                    <div id="comment-form-reply">
-                        <input type="checkbox" id="comment-reply" name="comment_reply" value="" onclick="setCommentParentID();" />
-                        <label for="comment-reply" id="comment-reply-label"></label>
-                    </div>
+                </div>
+                <div id="comment-form-reply" style="display:none">
+                    <input type="checkbox" id="comment-reply" name="comment_reply" value="" onclick="mtSetCommentParentID()" />
+                    <label for="comment-reply" id="comment-reply-label"></label>
                 </div>
                 <div id="comments-open-text">
-                    <label for="comment-text"><__trans phrase="Comments"> <MTIfAllowCommentHTML><__trans phrase="(You may use HTML tags for style)"></MTIfAllowCommentHTML></label>
+                    <label for="comment-text"><__trans phrase="Comments">
+                    <MTIfAllowCommentHTML><__trans phrase="(You may use HTML tags for style)"></MTIfAllowCommentHTML></label>
                     <textarea id="comment-text" name="text" rows="15" cols="50"></textarea>
                 </div>
-                <MTIfNonEmpty tag="MTCaptchaFields">
-                <MTIfCommentsAccepted><MTIfRegistrationAllowed><MTElse><$MTCaptchaFields$></MTIfRegistrationAllowed></MTIfCommentsAccepted>
-                <div id="comments-open-captcha">
-                </div>
-                </MTIfNonEmpty>
+                <div id="comments-open-captcha"></div>
                 <div id="comments-open-footer">
-                    <input type="submit" accesskey="v" name="preview" id="comment-preview" value="<__trans phrase="Preview">" />
+                    <input type="submit" accesskey="v" name="preview_button" id="comment-preview" value="<__trans phrase="Preview">" onclick="this.form.preview.value='1';" />
                     <input type="submit" accesskey="s" name="post" id="comment-submit" value="<__trans phrase="Submit">" />
                 </div>
Index: /branches/release-36/default_templates/search_results.mtml
===================================================================
--- /branches/release-36/default_templates/search_results.mtml (revision 1961)
+++ /branches/release-36/default_templates/search_results.mtml (revision 2062)
@@ -7,34 +7,10 @@
     <MTIgnore>Below Javascript adds ajax search capability</MTIgnore>
     <script type="text/javascript">
-    <!--
+    /* <![CDATA[ */
     <MTIfMoreResults>
-    function getXmlHttp() {
-        if ( !window.XMLHttpRequest ) {
-            window.XMLHttpRequest = function() {
-                var types = [
-                    "Microsoft.XMLHTTP",
-                    "MSXML2.XMLHTTP.5.0",
-                    "MSXML2.XMLHTTP.4.0",
-                    "MSXML2.XMLHTTP.3.0",
-                    "MSXML2.XMLHTTP"
-                ];
-
-                for ( var i = 0; i < types.length; i++ ) {
-                    try {
-                        return new ActiveXObject( types[ i ] );
-                    } catch( e ) {}
-                }
-
-                return undefined;
-            };
-        }
-        if ( window.XMLHttpRequest )
-            return new XMLHttpRequest();
-    }
-
     function getResults(page) {
         page = parseInt(page);
         if (timer) window.clearTimeout(timer);
-        var xh = getXmlHttp();
+        var xh = mtGetXmlHttp();
         if (!xh) return false;
         var res = results[page];
@@ -82,6 +58,7 @@
     }</MTIfPreviousResults>
     </MTIfMoreResults>
-    //-->
+    /* ]]> */
     </script>
+    <script type="text/javascript" src="<$MTLink template="javascript"$>"></script>
 </head>
 <body id="<$mt:BlogTemplateSetID$>" class="mt-search-results <$MTVar name="page_layout"$>">
Index: /branches/release-36/default_templates/comment_preview.mtml
===================================================================
--- /branches/release-36/default_templates/comment_preview.mtml (revision 1923)
+++ /branches/release-36/default_templates/comment_preview.mtml (revision 2062)
@@ -5,7 +5,12 @@
     <title><$MTBlogName encode_html="1"$>: <__trans phrase="Previewing your Comment"></title>
     <$mt:include module="<__trans phrase="HTML Head">"$>
+    <script type="text/javascript">
+    /* <![CDATA[ */
+    var is_preview = true;
+    /* ]]> */
+    </script>
     <script type="text/javascript" src="<$MTLink template="javascript"$>"></script>
 </head>
-<body id="<$mt:BlogTemplateSetID$>" class="mt-comment-preview <$MTVar name="page_layout"$>" onload="individualArchivesOnLoad(commenter_name)">
+<body id="<$mt:BlogTemplateSetID$>" class="mt-comment-preview <$MTVar name="page_layout"$>" onload="mtEntryOnLoad()">
     <div id="container">
         <div id="container-inner">
@@ -27,5 +32,5 @@
 
 <mt:ignore><!-- Comment Preview --></mt:ignore>
-                            <div class="comment"<MTIfArchiveTypeEnabled archive_type="Individual"> id="comment-<$MTCommentID$>"</MTIfArchiveTypeEnabled>>
+                            <div class="comment" id="comment-<$MTCommentID$>">
                                 <div class="inner">
                                     <div class="comment-header">
@@ -33,10 +38,10 @@
                                             <span class="byline">
                                                 <mt:IfCommentParent>
-                                                    <__trans phrase="[_1] replied to <a href="[_2]">comment from [_3]</a>" params="<MTIfNonEmpty tag="CommentAuthorIdentity"><$MTCommentAuthorIdentity$></MTIfNonEmpty> <span class="vcard author"><$MTCommentAuthorLink default_name="Anonymous" show_email="0"$></span>%%<mt:CommentParent>#comment-<$MTCommentID$></mt:CommentParent>%%<mt:CommentParent><$MTCommentAuthor$></mt:CommentParent>">
+                                                    <__trans phrase="[_1] replied to <a href="[_2]">comment from [_3]</a>" params="<$MTCommentAuthorIdentity$> <span class="vcard author"><$MTCommentAuthorLink$></span>%%<mt:CommentParent>#comment-<$MTCommentID$></mt:CommentParent>%%<mt:CommentParent><$MTCommentAuthor$></mt:CommentParent>">
                                                 <mt:else>
-                                                    <MTIfNonEmpty tag="CommentAuthorIdentity"><$MTCommentAuthorIdentity$></MTIfNonEmpty> <span class="vcard author"><$MTCommentAuthorLink default_name="Anonymous" show_email="0"$></span>
+                                                    <$MTCommentAuthorIdentity$>
+                                                    <span class="vcard author"><$MTCommentAuthorLink$></span>
                                                 </mt:IfCommentParent>
                                                 | <a href="#comment-<$MTCommentID$>"><abbr class="published" title="<$MTCommentDate format_name="iso8601"$>"><$MTCommentDate$></abbr></a>
-                                                <MTIfCommentsAccepted> | <$MTCommentReplyLink$></MTIfCommentsAccepted>
                                             </span>
                                         </div>
@@ -50,20 +55,12 @@
 
 <mt:ignore><!-- Comment Form --></mt:ignore>
-<MTIfCommentsAccepted>
                             <div class="comments-open" id="comments-open">
                                 <h2 class="comments-open-header"><__trans phrase="Leave a comment"></h2>
                                 <div class="comments-open-content">
-    <MTIfRegistrationAllowed>
-                                        <div id="comment-form-external-auth">
-                                            <script type="text/javascript">
-                                            /* <![CDATA[ */
-                                            is_preview = true;
-                                            writeCommenterGreeting(commenter_name, <$MTEntryID$>, <$MTEntryBlogID$>, commenter_id, commenter_url);
-                                            /* ]]> */
-                                            </script>
-                                        </div>
-    </MTIfRegistrationAllowed>
-                                    <form method="post" action="<$MTCGIPath$><$MTCommentScript$>" name="comments_form" id="comments-form" onsubmit="if (this.bakecookie.checked) rememberMe(this)">
+                                    <div id="comment-greeting"></div>
+                                    <form method="post" action="<$MTCGIPath$><$MTCommentScript$>" name="comments_form" id="comments-form" onsubmit="mtCommentOnSubmit(this)">
                                         <input type="hidden" name="static" value="1" />
+                                        <input type="hidden" name="armor" value="1" />
+                                        <input type="hidden" name="preview" value="" />
                                         <input type="hidden" name="entry_id" value="<$MTEntryID$>" />
                                         <input type="hidden" name="__lang" value="<$MTBlogLanguage$>" />
@@ -81,8 +78,4 @@
                                                 <input id="comment-url" name="url" size="30" value="<$MTCommentURL encode_html="1"$>" />
                                             </div>
-                                            <div id="comment-form-remember-me">
-                                                <label for="comment-bake-cookie"><input type="checkbox" id="comment-bake-cookie" name="bakecookie" onclick="if (!this.checked) forgetMe(document.comments_form)" value="1" />
-                                                    <__trans phrase="Remember personal info?"></label>
-                                            </div>
                                         </div>
                                         <div id="comments-open-text">
@@ -90,11 +83,7 @@
                                             <textarea id="comment-text" name="text" rows="15" cols="50"><$MTCommentBody autolink="0" sanitize="0" convert_breaks="0" encode_html="1"$></textarea>
                                         </div>
-    <MTIfNonEmpty tag="MTCaptchaFields">
-                                        <MTIfCommentsAccepted><MTIfRegistrationAllowed><MTElse><$MTCaptchaFields$></MTIfRegistrationAllowed></MTIfCommentsAccepted>
-                                        <div id="comments-open-captcha">
-                                        </div>
-    </MTIfNonEmpty>
+                                        <div id="comments-open-captcha"></div>
                                         <div id="comments-open-footer">
-                                            <input type="submit" accesskey="v" name="preview" id="comment-preview" value="<__trans phrase="Preview">" />
+                                            <input type="submit" accesskey="v" name="preview_button" id="comment-preview" value="<__trans phrase="Preview">" onclick="this.form.preview.value='1';" />
                                             <input type="submit" accesskey="s" name="post" id="comment-submit" value="<__trans phrase="Submit">" />
                                             <input type="button" name="cancel" id="comment-cancel" value="<__trans phrase="Cancel">" onclick="window.location='<$MTEntryPermalink$>'" />
@@ -103,5 +92,4 @@
                                 </div>
                             </div>
-</MTIfCommentsAccepted>
                         </div>
                     </div>
Index: /branches/release-36/extras/examples/plugins/CommentByGoogleAccount/lib/CommentByGoogleAccount.pm
===================================================================
--- /branches/release-36/extras/examples/plugins/CommentByGoogleAccount/lib/CommentByGoogleAccount.pm (revision 1174)
+++ /branches/release-36/extras/examples/plugins/CommentByGoogleAccount/lib/CommentByGoogleAccount.pm (revision 2062)
@@ -39,5 +39,5 @@
         my $nick_escaped = escape_unicode($nick);
         $nick = encode_text($nick, 'utf-8', undef);
-        $session = $app->_make_commenter_session($app->make_magic_token, $email,
+        $session = $app->make_commenter_session($app->make_magic_token, $email,
                                                  $name, $nick_escaped);
         unless ($session) {
Index: /branches/release-36/lib/MT/Auth/TypeKey.pm
===================================================================
--- /branches/release-36/lib/MT/Auth/TypeKey.pm (revision 1823)
+++ /branches/release-36/lib/MT/Auth/TypeKey.pm (revision 2062)
@@ -62,5 +62,5 @@
         my $nick_escaped = escape_unicode($nick);
         $nick = encode_text($nick, 'utf-8', undef);
-        $session = $app->_make_commenter_session($sig_str, $email,
+        $session = $app->make_commenter_session($sig_str, $email,
                                                  $name, $nick_escaped, undef, $url);
         unless ($session) {
Index: /branches/release-36/lib/MT/Auth/OpenID.pm
===================================================================
--- /branches/release-36/lib/MT/Auth/OpenID.pm (revision 1914)
+++ /branches/release-36/lib/MT/Auth/OpenID.pm (revision 2062)
@@ -117,5 +117,5 @@
         my $nick_escaped = escape_unicode($nick);
         $nick = encode_text($nick, 'utf-8', undef);
-        $session = $app->_make_commenter_session($app->make_magic_token, q(),
+        $session = $app->make_commenter_session($app->make_magic_token, q(),
                                                  $name, $nick_escaped, undef, $name);
         unless ($session) {
Index: /branches/release-36/lib/MT/Auth/MT.pm
===================================================================
--- /branches/release-36/lib/MT/Auth/MT.pm (revision 1823)
+++ /branches/release-36/lib/MT/Auth/MT.pm (revision 2062)
@@ -66,5 +66,5 @@
         $pass = $app->param('password');
         $remember = $app->param('remember') ? 1 : 0;
-        return { %$ctx, username => $user, password => $pass, permanent => $remember };
+        return { %$ctx, username => $user, password => $pass, permanent => $remember, auth_type => 'MT' };
     }
     return undef;
@@ -79,5 +79,5 @@
     if ($cookies->{$app->user_cookie}) {
         my ($user, $session_id, $remember) = split /::/, $cookies->{$app->user_cookie}->value;
-        return { %$ctx, username => $user, session_id => $session_id, permanent => $remember };
+        return { %$ctx, username => $user, session_id => $session_id, permanent => $remember, auth_type => 'MT' };
     }
     return undef;
@@ -108,5 +108,5 @@
         # load author from db
         my $user_class = $app->user_class;
-        my ($author) = $user_class->search({ name => $username, type => AUTHOR });
+        my ($author) = $user_class->search({ name => $username, type => AUTHOR, auth_type => 'MT' });
 
         if ($author) {
Index: /branches/release-36/lib/MT/App.pm
===================================================================
--- /branches/release-36/lib/MT/App.pm (revision 2024)
+++ /branches/release-36/lib/MT/App.pm (revision 2062)
@@ -277,5 +277,5 @@
 
     my $class = $app->model($type) or return;
-    my $list_pref = $app->list_pref($type);
+    my $list_pref = $app->list_pref($type) if $app->can('list_pref');
     $param->{$_} = $list_pref->{$_} for keys %$list_pref;
     my $limit = $list_pref->{rows};
@@ -938,9 +938,11 @@
 sub is_authorized { 1 }
 
+sub commenter_cookie { COMMENTER_COOKIE_NAME() }
+
 sub user_cookie { $COOKIE_NAME }
 
 sub user {
     my $app = shift;
-    $app->{author} = $app->{$COOKIE_NAME} = $_[0] if @_;
+    $app->{author} = $app->{ $app->user_cookie } = $_[0] if @_;
     return $app->{author};
 }
@@ -1013,5 +1015,5 @@
 }
 
-sub _make_commenter_session {
+sub make_commenter_session {
     my $app = shift;
     my ($session_key, $email, $name, $nick, $id, $url, $timeout, $blog_id) = @_;
@@ -1021,5 +1023,5 @@
     my $nick_escaped = MT::Util::escape_unicode( $nick );
 
-    $timeout = '+' . $app->{cfg}->CommentSessionTimeout . 's' unless defined $timeout;
+    $timeout = '+' . $app->config->CommentSessionTimeout . 's' unless defined $timeout;
     my %kookee = (-name => COMMENTER_COOKIE_NAME(),
                   -value => $session_key,
@@ -1033,82 +1035,25 @@
     $app->bake_cookie(%name_kookee);
     if (defined $id) {
-        my $blog_ids;
-        if ($app->user && $app->user->is_superuser) {
-            # Do not send blog ids in cookie because it may become huge.
-            $blog_ids = 'S';
-        }
-        else {
-            my @blogs = $app->model('blog')->load(undef,
-              {
-                fetchonly => [ 'id' ],
-                join => MT::Permission->join_on('blog_id',
-                  {
-                    permissions => "\%'comment'\%",
-                    author_id   => $id
-                  },
-                  { 'like' => { 'permissions' => 1 } }
-                )
-              }
-            );
-
-            # Has permissions to 20+ blogs - do not send these ids in cookie.
-            $blog_ids = 20 < scalar(@blogs)
-              ? 'N'
-              : @blogs
-                ? "'" . join("','", map { $_->id } @blogs) . "'" 
-                : '';
-        }
-
-        if ( $blog_ids ne 'S' && $blog_ids ne 'N' ) {
-            my $perm = MT::Permission->load({ blog_id => $blog_id, author_id => $id });
-            if ($perm) {
-                # double-check to see if this user hasn't been denied commenting
-                # permission. user has 'comment' permission through a role,
-                # but check for a restriction to comment on this blog
-                if ($perm->is_restricted('comment')) {
-                    $blog_ids =~ s/(,|^)'$blog_id'(,|$)//;
-                }
-
-                # But if the permission carries a 'can administer' permission
-                # they should be allowed
-                if ($blog_id && ($blog_ids !~ m/(,|^)'$blog_id'(,|$)/)) {
-                    if ($perm->can_administer_blog()) {
-                        # user is a blog administrator, so yes, they can comment too
-                        $blog_ids .= ($blog_ids ne '' ? ',' : '')
-                            . "'" . $blog_id . "'";
-                    }
-                }
-            }
-            else {
-                if ($blog_id && ($blog_ids !~ m/(,|^)'$blog_id'(,|$)/)) {
-                    # extra check to see if this user can comment on requested
-                    # blog; this is specific to the Comment application, so
-                    # only do this if we're running the comments app.
-                    if ( $app->isa( 'MT::App::Comments' )) {
-                        if ( $app->_check_commenter_author($app->user, $blog_id) ) {
-                            # is this blog open to commenting from registered users?
-                            # if so, this user really can comment, even though they
-                            # don't have explicit permissions for it
-                            $blog_ids .= ($blog_ids ne '' ? ',' : '')
-                                . "'" . $blog_id . "'";
-                        }
-                    }
-                }
-            }
-        }
-
-        my %id_kookee = (-name => "commenter_id",
-                           -value => $id . ':' . $blog_ids,
-                           -path => '/',
-                           ($timeout ? (-expires => $timeout) : ()));
-        $app->bake_cookie(%id_kookee);
-    }
-    if (defined($url) && $url) {
-        my %id_kookee = (-name => "commenter_url",
-                           -value => $url,
-                           -path => '/',
-                           ($timeout ? (-expires => $timeout) : ()));
-        $app->bake_cookie(%id_kookee);
-    }
+        my $banned = 0;
+        my $perm = MT::Permission->load({ blog_id => $blog_id, author_id => $id });
+        if ($perm) {
+            if (!$perm->can_administer_blog && $perm->is_restricted('comment')) {
+                $banned = 1;
+            }
+        }
+
+        # my %id_kookee = (-name => "commenter_id",
+        #                    -value => $id . ':' . $blog_ids,
+        #                    -path => '/',
+        #                    ($timeout ? (-expires => $timeout) : ()));
+        # $app->bake_cookie(%id_kookee);
+    }
+    # if (defined($url) && $url) {
+    #     my %id_kookee = (-name => "commenter_url",
+    #                        -value => $url,
+    #                        -path => '/',
+    #                        ($timeout ? (-expires => $timeout) : ()));
+    #     $app->bake_cookie(%id_kookee);
+    # }
 
     require MT::Session;
@@ -1135,27 +1080,28 @@
     my $sess_obj = MT::Session->load({id => $session });
     $sess_obj->remove() if ($sess_obj);
-    
-    my $timeout = $app->{cfg}->CommentSessionTimeout;
-
-    my %kookee = (-name => COMMENTER_COOKIE_NAME(),
-                  -value => '',
-                  -path => '/',
-                  -expires => "+${timeout}s");
-    $app->bake_cookie(%kookee);
-    my %url_kookee = (-name => 'commenter_url',
-                       -value => '',
-                       -path => '/',
-                       -expires => "+${timeout}s");
-    $app->bake_cookie(%url_kookee);
-    my %name_kookee = (-name => 'commenter_name',
-                       -value => '',
-                       -path => '/',
-                       -expires => "+${timeout}s");
-    $app->bake_cookie(%name_kookee);
-    my %id_kookee = (-name => 'commenter_id',
-                       -value => '',
-                       -path => '/',
-                       -expires => "+${timeout}s");
-    $app->bake_cookie(%id_kookee);
+
+    $app->logout();
+
+    # my $timeout = $app->config->CommentSessionTimeout;
+    # my %kookee = (-name => COMMENTER_COOKIE_NAME(),
+    #               -value => '',
+    #               -path => '/',
+    #               -expires => "+${timeout}s");
+    # $app->bake_cookie(%kookee);
+    # my %url_kookee = (-name => 'commenter_url',
+    #                    -value => '',
+    #                    -path => '/',
+    #                    -expires => "+${timeout}s");
+    # $app->bake_cookie(%url_kookee);
+    # my %name_kookee = (-name => 'commenter_name',
+    #                    -value => '',
+    #                    -path => '/',
+    #                    -expires => "+${timeout}s");
+    # $app->bake_cookie(%name_kookee);
+    # my %id_kookee = (-name => 'commenter_id',
+    #                    -value => '',
+    #                    -path => '/',
+    #                    -expires => "+${timeout}s");
+    # $app->bake_cookie(%id_kookee);
 }
 
@@ -1169,5 +1115,5 @@
     }
     my $session = make_session($author, $remember);
-    my %arg = (-name => $COOKIE_NAME,
+    my %arg = (-name => $app->user_cookie,
                -value => join('::',
                               $author->name,
@@ -1501,5 +1447,5 @@
                 # Presence of 'password' indicates this is a login request;
                 # do session/cookie management.
-                $app->_make_commenter_session(
+                $app->make_commenter_session(
                     $app->make_magic_token, 
                     $author->email, 
@@ -1579,6 +1525,6 @@
 
     MT::Auth->invalidate_credentials({ app => $app });
-    my %cookies = $app->cookies();
-    $app->_invalidate_commenter_session(\%cookies);
+    # my %cookies = $app->cookies();
+    # $app->_invalidate_commenter_session(\%cookies);
 
     # The login box should only be displayed in the event of non-delegated auth
@@ -1884,5 +1830,5 @@
 sub clear_login_cookie {
     my $app = shift;
-    $app->bake_cookie(-name => $COOKIE_NAME, -value => '', -expires => '-1y',
+    $app->bake_cookie(-name => $app->user_cookie, -value => '', -expires => '-1y',
         -path => $app->config->CookiePath || $app->mt_path);
 }
Index: /branches/release-36/lib/MT/Template/ContextHandlers.pm
===================================================================
--- /branches/release-36/lib/MT/Template/ContextHandlers.pm (revision 2052)
+++ /branches/release-36/lib/MT/Template/ContextHandlers.pm (revision 2062)
@@ -82,11 +82,11 @@
             Loop => \&_hdlr_loop,
             Section => \&_hdlr_section,
-            IfNonEmpty => \&_hdlr_if_nonempty,
-            IfNonZero => \&_hdlr_if_nonzero,
-
-            IfCommenterTrusted => \&_hdlr_commenter_trusted,
-            CommenterIfTrusted => \&_hdlr_commenter_trusted,
-            IfCommenterIsAuthor => \&_hdlr_commenter_isauthor,
-            IfCommenterIsEntryAuthor => \&_hdlr_commenter_isauthor,
+            'IfNonEmpty?' => \&_hdlr_if_nonempty,
+            'IfNonZero?' => \&_hdlr_if_nonzero,
+
+            'IfCommenterTrusted?' => \&_hdlr_commenter_trusted,
+            'CommenterIfTrusted?' => \&_hdlr_commenter_trusted,
+            'IfCommenterIsAuthor?' => \&_hdlr_commenter_isauthor,
+            'IfCommenterIsEntryAuthor?' => \&_hdlr_commenter_isauthor,
 
             'IfBlog?' => \&_hdlr_blog_id,
@@ -105,5 +105,5 @@
             EntryCategories => \&_hdlr_entry_categories,
             EntryAdditionalCategories => \&_hdlr_entry_additional_categories,
-            BlogIfCommentsOpen => \&_hdlr_blog_if_comments_open,
+            'BlogIfCommentsOpen?' => \&_hdlr_blog_if_comments_open,
             EntryPrevious => \&_hdlr_entry_previous,
             EntryNext => \&_hdlr_entry_next,
@@ -124,10 +124,10 @@
             SetHashVar => \&_hdlr_set_hashvar,
 
-            IfCommentsModerated => \&_hdlr_comments_moderated,
-            IfRegistrationRequired => \&_hdlr_reg_required,
-            IfRegistrationNotRequired => \&_hdlr_reg_not_required,
-            IfRegistrationAllowed => \&_hdlr_reg_allowed,
-
-            IfTypeKeyToken => \&_hdlr_if_typekey_token,
+            'IfCommentsModerated?' => \&_hdlr_comments_moderated,
+            'IfRegistrationRequired?' => \&_hdlr_reg_required,
+            'IfRegistrationNotRequired?' => \&_hdlr_reg_not_required,
+            'IfRegistrationAllowed?' => \&_hdlr_reg_allowed,
+
+            'IfTypeKeyToken?' => \&_hdlr_if_typekey_token,
 
             Comments => \&_hdlr_comments,
@@ -135,5 +135,5 @@
             CommentsFooter => \&_hdlr_pass_tokens,
             CommentEntry => \&_hdlr_comment_entry,
-            CommentIfModerated => \&_hdlr_comment_if_moderated,
+            'CommentIfModerated?' => \&_hdlr_comment_if_moderated,
 
             CommentParent => \&_hdlr_comment_parent,
@@ -159,5 +159,5 @@
 
             Categories => \&_hdlr_categories,
-            CategoryIfAllowPings => \&_hdlr_category_allow_pings,
+            'CategoryIfAllowPings?' => \&_hdlr_category_allow_pings,
             CategoryPrevious => \&_hdlr_category_prevnext,
             CategoryNext => \&_hdlr_category_prevnext,
@@ -167,18 +167,18 @@
             PingEntry => \&_hdlr_ping_entry,
 
-            IfAllowCommentHTML => \&_hdlr_if_allow_comment_html,
-            IfCommentsAllowed => \&_hdlr_if_comments_allowed,
-            IfCommentsAccepted => \&_hdlr_if_comments_accepted,
-            IfCommentsActive => \&_hdlr_if_comments_active,
-            IfPingsAllowed => \&_hdlr_if_pings_allowed,
-            IfPingsAccepted => \&_hdlr_if_pings_accepted,
-            IfPingsActive => \&_hdlr_if_pings_active,
-            IfPingsModerated => \&_hdlr_if_pings_moderated,
-            IfNeedEmail => \&_hdlr_if_need_email,
-            IfRequireCommentEmails => \&_hdlr_if_need_email,
-            EntryIfAllowComments => \&_hdlr_if_comments_active,
-            EntryIfCommentsOpen => \&_hdlr_entry_if_comments_open,
-            EntryIfAllowPings => \&_hdlr_entry_if_allow_pings,
-            EntryIfExtended => \&_hdlr_entry_if_extended,
+            'IfAllowCommentHTML?' => \&_hdlr_if_allow_comment_html,
+            'IfCommentsAllowed?' => \&_hdlr_if_comments_allowed,
+            'IfCommentsAccepted?' => \&_hdlr_if_comments_accepted,
+            'IfCommentsActive?' => \&_hdlr_if_comments_active,
+            'IfPingsAllowed?' => \&_hdlr_if_pings_allowed,
+            'IfPingsAccepted?' => \&_hdlr_if_pings_accepted,
+            'IfPingsActive?' => \&_hdlr_if_pings_active,
+            'IfPingsModerated?' => \&_hdlr_if_pings_moderated,
+            'IfNeedEmail?' => \&_hdlr_if_need_email,
+            'IfRequireCommentEmails?' => \&_hdlr_if_need_email,
+            'EntryIfAllowComments?' => \&_hdlr_entry_if_allow_comments,
+            'EntryIfCommentsOpen?' => \&_hdlr_entry_if_comments_open,
+            'EntryIfAllowPings?' => \&_hdlr_entry_if_allow_pings,
+            'EntryIfExtended?' => \&_hdlr_entry_if_extended,
 
             SubCategories => \&_hdlr_sub_categories,
@@ -373,4 +373,6 @@
             RemoteSignOutLink => \&_hdlr_remote_sign_out_link,
             RemoteSignInLink => \&_hdlr_remote_sign_in_link,
+            SignOutLink => \&_hdlr_sign_out_link,
+            SignInLink => \&_hdlr_sign_in_link,
 
             CommentID => \&_hdlr_comment_id,
@@ -1423,10 +1425,14 @@
     elsif (defined(my $tag = $args->{tag})) {
         $tag =~ s/^MT:?//i;
-        my ($handler) = $ctx->handler_for($tag);
+        my ($handler, $type) = $ctx->handler_for($tag);
         if (defined($handler)) {
             local $ctx->{__stash}{tag} = $args->{tag};
             $value = $handler->($ctx, { %$args });
-            if (my $ph = $ctx->post_process_handler) {
-                $value = $ph->($ctx, $args, $value);
+            if ($type == 2) { # conditional tag; just use boolean
+                $value = $value ? 1 : 0;
+            } else {
+                if (my $ph = $ctx->post_process_handler) {
+                    $value = $ph->($ctx, $args, $value);
+                }
             }
             $ctx->{__stash}{vars}{__cond_tag__} = $args->{tag};
@@ -2186,7 +2192,7 @@
     my $blog = $_[0]->stash('blog');
     if ($blog->remote_auth_token) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -2195,7 +2201,7 @@
     my $blog = $_[0]->stash('blog');
     if ($blog->moderate_unreg_comments || $blog->manual_approve_commenters) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -2204,7 +2210,7 @@
     my $blog = $_[0]->stash('blog');
     if ($blog->allow_reg_comments && $blog->commenter_authenticators) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -2214,7 +2220,7 @@
     if ( $blog->allow_reg_comments && $blog->commenter_authenticators
         && ! $blog->allow_unreg_comments ) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -2224,7 +2230,7 @@
     if ($blog->allow_reg_comments && $blog->commenter_authenticators
         && $blog->allow_unreg_comments) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -2241,7 +2247,7 @@
         (($blog->allow_reg_comments && $blog->effective_remote_auth_token)
          || $blog->allow_unreg_comments)) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -2384,4 +2390,5 @@
 
     # Try to read from cache
+    my $cache_expire_type = $tmpl->cache_expire_type || 0;
     my $cache_enabled =
          $blog
@@ -2391,5 +2398,5 @@
         || $arg->{key}
         || ( exists $arg->{ttl} )
-        || ( $tmpl->cache_expire_type != 0 ) ) ? 1 : 0;
+        || ( $cache_expire_type != 0 ) ) ? 1 : 0;
     my $cache_key =
         ($arg->{cache_key} || $arg->{key})
@@ -2398,9 +2405,9 @@
     my $ttl =
       exists $arg->{ttl} ? $arg->{ttl}
-          : ( $tmpl->cache_expire_type == 1 ) ? $tmpl->cache_expire_interval
-              : ( $tmpl->cache_expire_type == 2 ) ? 0
+          : ( $cache_expire_type == 1 ) ? $tmpl->cache_expire_interval
+              : ( $cache_expire_type == 2 ) ? 0
                   :   60 * 60;    # default 60 min.
 
-    if ( $tmpl->cache_expire_type == 2 ) {
+    if ( $cache_expire_type == 2 ) {
         my @types = split /,/, ($tmpl->cache_expire_event || '');
         if (@types) {
@@ -2736,7 +2743,7 @@
     }
     if (defined($value) && $value ne '') { # want to include "0" here
-        _hdlr_pass_tokens($ctx, $args, $cond);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else($ctx, undef, $cond);
+        return 0;
     }
 }
@@ -2761,7 +2768,7 @@
     }
     if (defined($value) && $value) {
-        _hdlr_pass_tokens($ctx, $args, $cond);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else($ctx, undef, $cond);
+        return 0;
     }
 }
@@ -4049,4 +4056,6 @@
                 }
                 $no_resort = 0;
+            } elsif ($class->is_meta_column($args->{sort_by})) {
+                $no_resort = 0;
             }
         }
@@ -4107,4 +4116,17 @@
                 if (my $def = $class->column_def($col)) {
                     if ($def->{type} =~ m/^integer|float$/) {
+                        @$entries = $so eq 'ascend' ?
+                            sort { $a->$col() <=> $b->$col() } @$entries :
+                            sort { $b->$col() <=> $a->$col() } @$entries;
+                    } else {
+                        @$entries = $so eq 'ascend' ?
+                            sort { $a->$col() cmp $b->$col() } @$entries :
+                            sort { $b->$col() cmp $a->$col() } @$entries;
+                    }
+                    $no_resort = 1;
+                } elsif ($class->is_meta_column($col)) {
+                    my $type = MT::Meta->metadata_by_name($class, $col);
+                    no warnings;
+                    if ($type->{type} =~ m/integer|float/) {
                         @$entries = $so eq 'ascend' ?
                             sort { $a->$col() <=> $b->$col() } @$entries :
@@ -4226,4 +4248,16 @@
             if (my $def = $class->column_def($col)) {
                 if ($def->{type} =~ m/^integer|float$/) {
+                    @entries = $so eq 'ascend' ?
+                        sort { $a->$col() <=> $b->$col() } @entries :
+                        sort { $b->$col() <=> $a->$col() } @entries;
+                } else {
+                    @entries = $so eq 'ascend' ?
+                        sort { $a->$col() cmp $b->$col() } @entries :
+                        sort { $b->$col() cmp $a->$col() } @entries;
+                }
+            } elsif ($class->is_meta_column($col)) {
+                my $type = MT::Meta->metadata_by_name($class, $col);
+                no warnings;
+                if ($type->{type} =~ m/integer|float/) {
                     @entries = $so eq 'ascend' ?
                         sort { $a->$col() <=> $b->$col() } @entries :
@@ -4788,5 +4822,5 @@
     my $builder = $ctx->stash('builder');
     my $tokens = $ctx->stash('tokens');
-    my $res;
+    my $res = '';
     my $glue = $args->{glue};
     for my $cat (@$cats) {
@@ -4808,4 +4842,42 @@
     my $tp_token = $blog->effective_remote_auth_token();
     return $tp_token;
+}
+
+sub _hdlr_sign_in_link {
+    my ($ctx, $args) = @_;    
+    my $cfg = $ctx->{config};
+    my $blog = $ctx->stash('blog');
+    my $path = _hdlr_cgi_path($ctx);
+    $path .= '/' unless $path =~ m!/$!;
+    my $comment_script = $cfg->CommentScript;
+    my $static_arg = $args->{static} ? "&static=" . $args->{static} : "&static=0";
+    my $e = $ctx->stash('entry');
+    return "$path$comment_script?__mode=login$static_arg" .
+        ($blog ? '&blog_id=' . $blog->id : '') .
+        ($e ? '&entry_id=' . $e->id : '');
+}
+
+sub _hdlr_sign_out_link {
+    my ($ctx, $args) = @_;
+    my $cfg = $ctx->{config};
+    my $path = _hdlr_cgi_path($ctx);
+    $path .= '/' unless $path =~ m!/$!;
+    my $comment_script = $cfg->CommentScript;
+    my $static_arg;
+    if ($args->{no_static}) {
+        $static_arg = q();
+    } else {
+        my $url = $args->{static};
+        if ($url && ($url ne '1')) {
+            $static_arg = "&static=" . MT::Util::encode_url($url);
+        } elsif ($url) {
+            $static_arg = "&static=1";
+        } else {
+            $static_arg = "&static=0";
+        }
+    }
+    my $e = $_[0]->stash('entry');
+    return "$path$comment_script?__mode=handle_sign_in$static_arg&logout=1" .
+        ($e ? "&amp;entry_id=" . $e->id : '');
 }
 
@@ -4997,4 +5069,15 @@
         if ($r eq 'js') {
             # output javascript here to render relative date
+            my($y, $mo, $d, $h, $m, $s) = $ts =~ /(\d\d\d\d)[^\d]?(\d\d)[^\d]?(\d\d)[^\d]?(\d\d)[^\d]?(\d\d)[^\d]?(\d\d)/;
+            $mo--;
+            my $fds = format_ts($args->{'format'}, $ts, $blog, $lang);
+            my $js = <<EOT;
+<script type="text/javascript">
+/* <![CDATA[ */
+document.write(mtRelativeDate(new Date($y,$mo,$d,$h,$m,$s), '$fds'));
+/* ]]> */
+</script><noscript>$fds</noscript>
+EOT
+            return $js;
         } else {
             my $old_lang = MT->current_language;
@@ -5346,7 +5429,7 @@
         or return $_[0]->_no_comment_error('MTCommentIfModerated');
     if ($c->visible) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -5528,6 +5611,7 @@
     my $label = $args->{label} || $args->{text} || MT->translate('Reply');
     my $comment_author = MT::Util::encode_js($comment->author);
-
-    return sprintf(qq(<a title="%s" href="javascript:void(0);" onclick="replyComment(%d, '%s')">%s</a>),
+    my $onclick = $args->{onclick} || 'mtReplyCommentOnClick';
+
+    return sprintf(qq(<a title="%s" href="javascript:void(0);" onclick="$onclick(%d, '%s')">%s</a>),
                    $label, $comment->id, $comment_author, $label);
 }
@@ -5535,6 +5619,5 @@
 sub _hdlr_comment_parent_id {
     my $args = $_[1];
-    my $c = $_[0]->stash('comment')
-        or return $_[0]->_no_comment_error('MTCommentParentID');
+    my $c = $_[0]->stash('comment') or return '';
     my $id = $c->parent_id || 0;
     $args && $args->{pad} ? (sprintf "%06d", $id) : ($id ? $id : '');
@@ -5745,7 +5828,7 @@
     return '' unless $a;
     if ($a->is_trusted($ctx->stash('blog_id'))) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -5754,6 +5837,5 @@
     my ($ctx, $args, $cond) = @_;
     my $a = $ctx->stash('commenter');
-    return _hdlr_pass_tokens_else(@_)
-      unless $a;
+    return 0 unless $a;
     if ($a->type == MT::Author::AUTHOR()) {
         my $tag = lc $ctx->stash('tag');
@@ -5763,12 +5845,12 @@
             if ($e) {
                 if ($e->author_id == $a->id) {
-                    return _hdlr_pass_tokens(@_);
+                    return 1;
                 }
             }
         } else {
-            return _hdlr_pass_tokens(@_);
-        }
-    }
-    return _hdlr_pass_tokens_else(@_);
+            return 1;
+        }
+    }
+    return 0;
 }
 
@@ -6378,5 +6460,5 @@
     my $entry_class = MT->model(
         $class_type eq 'category' ? 'entry' : 'page');
-    
+
     my $iter = $class->load_iter(\%terms, \%args);
     my $res = '';
@@ -6578,8 +6660,8 @@
     my $cat = $_[0]->stash('category') || $_[0]->stash('archive_category');
     if ($cat->allow_pings) {
-        _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        _hdlr_pass_tokens_else(@_);
-    }                                 
+        return 0;
+    }
 }
 
@@ -6706,5 +6788,5 @@
     my $builder = $ctx->stash('builder');
     my $tokens = $ctx->stash('tokens');
-    my $res;
+    my $res = '';
     my $glue = $args->{glue};
     for my $cat (@$cats) {
@@ -6858,7 +6940,7 @@
     return '' unless $blog;
     if ($blog->allow_comment_html) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6872,7 +6954,7 @@
                                   && $blog->effective_remote_auth_token))))
         && $cfg->AllowComments) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6892,7 +6974,7 @@
     }
     if ($active) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6907,7 +6989,7 @@
     $accepted = 0 if $entry && !$entry->allow_comments;
     if ($accepted) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6923,7 +7005,7 @@
     $active = 1 if !$active && $entry && $entry->ping_count;
     if ($active) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6933,7 +7015,7 @@
     my $blog = $ctx->stash('blog');
     if ($blog->moderate_pings) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6948,7 +7030,7 @@
     $accepted = 0 if $entry && !$entry->allow_pings;
     if ($accepted) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6959,7 +7041,7 @@
     my $cfg = $ctx->{config};
     if ($blog->allow_pings && $cfg->AllowPings) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6970,7 +7052,7 @@
     my $cfg = $ctx->{config};
     if ($blog->require_comment_emails) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6978,9 +7060,12 @@
 sub _hdlr_entry_if_allow_comments {
     my ($ctx, $args, $cond) = @_;
+    my $blog = $ctx->stash('blog');
+    my $cfg = $ctx->{config};
+    my $blog_comments_accepted = $blog->accepts_comments && $cfg->AllowComments;
     my $entry = $ctx->stash('entry');
-    if ($entry->allow_comments) {
-        return _hdlr_pass_tokens(@_);
+    if ($blog_comments_accepted && $entry->allow_comments) {
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -6989,20 +7074,24 @@
     my ($ctx, $args, $cond) = @_;
     my $blog = $ctx->stash('blog');
+    my $cfg = $ctx->{config};
+    my $blog_comments_accepted = $blog->accepts_comments && $cfg->AllowComments;
     my $entry = $ctx->stash('entry');
+    if ($entry && $blog_comments_accepted && $entry->allow_comments && $entry->allow_comments eq '1') {
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+sub _hdlr_entry_if_allow_pings {
+    my ($ctx, $args, $cond) = @_;
+    my $entry = $ctx->stash('entry');
+    my $blog = $ctx->stash('blog');
     my $cfg = $ctx->{config};
-    if ($entry && $entry->allow_comments && $entry->allow_comments eq '1') {
-        return _hdlr_pass_tokens(@_);
+    my $blog_pings_accepted = 1 if $cfg->AllowPings && $blog->allow_pings;
+    if ($blog_pings_accepted && $entry->allow_pings) {
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
-    }
-}
-
-sub _hdlr_entry_if_allow_pings {
-    my ($ctx, $args, $cond) = @_;
-    my $entry = $ctx->stash('entry');
-    if ($entry->allow_pings) {
-        return _hdlr_pass_tokens(@_);
-    } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -7018,10 +7107,11 @@
     }
     if ($more ne '') {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
-    }
-}
-
+        return 0;
+    }
+}
+
+# FIXME: Unused?
 sub _hdlr_if_commenter_pending {
     my ($ctx, $args, $cond) = @_;
@@ -7029,7 +7119,7 @@
     my $blog = $ctx->stash('blog');
     if ($cmtr && $blog && $cmtr->commenter_status($blog->id) == MT::Author::PENDING()) {
-        return _hdlr_pass_tokens(@_);
+        return 1;
     } else {
-        return _hdlr_pass_tokens_else(@_);
+        return 0;
     }
 }
@@ -7272,5 +7362,5 @@
     my @cats = $cat->parent_categories;
     @cats = ($cat, @cats) unless ($exclude_current);
-  
+
     # Start from the top and work our way down
     while (my $c = pop @cats) {
Index: /branches/release-36/lib/MT/App/Comments.pm
===================================================================
--- /branches/release-36/lib/MT/App/Comments.pm (revision 1924)
+++ /branches/release-36/lib/MT/App/Comments.pm (revision 2062)
@@ -34,10 +34,13 @@
         post             => \&post,
         handle_sign_in   => \&handle_sign_in,
-        cmtr_name_js     => \&commenter_name_js,
-        cmtr_status_js   => \&commenter_status_js,
+        session_js       => \&session_js,
         edit_profile     => \&edit_commenter_profile,
         save_profile     => \&save_commenter_profile,
         red              => \&do_red,
         generate_captcha => \&generate_captcha,
+
+        # deprecated
+        cmtr_name_js     => \&commenter_name_js,
+        cmtr_status_js   => \&commenter_status_js,
     );
     $app->{template_dir} = 'comment';
@@ -88,5 +91,5 @@
 
 #
-# $app->_get_commenter_session() #
+# $app->_get_commenter_session()
 # Creates a commenter record based on the cookies in the $app, if
 # one already exists corresponding to the browser's session.
@@ -103,6 +106,14 @@
     my $session_key;
 
+    # First, check for a real MT user login. If one exists,
+    # return that as the commenter identity
+    my ($user, $first_time) = $app->SUPER::login();
+    if ( $user ) {
+        my $sess = $app->session;
+        return ( $sess->id, $user );
+    }
+
     my %cookies = $app->cookies();
-    my $cookie_name = MT::App::COMMENTER_COOKIE_NAME();
+    my $cookie_name = $app->commenter_cookie;
     if ( !$cookies{$cookie_name} ) {
         return ( undef, undef );
@@ -115,5 +126,5 @@
     my $timeout = $cfg->CommentSessionTimeout;
     my $user;
-
+    
     if ( $sess_obj
         && ( $user = MT::Author->load( { name => $sess_obj->name } ) ) )
@@ -123,6 +134,4 @@
     if (   !$sess_obj
         || ( $sess_obj->start() + $timeout < time )
-        || ( $q->param('email') && ( $sess_obj->email ne $q->param('email') ) )
-        || ( $q->param('author') && ( $user->nickname ne $q->param('author') ) )
       )
     {
@@ -131,5 +140,4 @@
     }
     else {
-
         # session is valid!
         return ( $session_key, $user );
@@ -283,9 +291,8 @@
         MT::Auth->new_login( $app, $commenter );
         if ( $app->_check_commenter_author( $commenter, $blog_id ) ) {
-            $app->_make_commenter_session( $app->make_magic_token,
+            $app->make_commenter_session( $app->make_magic_token,
                 $commenter->email, $commenter->name,
                 ($commenter->nickname || $app->translate('(Display Name not set)')),
                 $commenter->id, undef, $ctx->{permanent} ? '+10y' : 0, $blog_id );
-            #$app->start_session( $commenter, $ctx->{permanent} ? 1 : 0 );
             return $app->redirect_to_target;
         }
@@ -766,5 +773,5 @@
       if $app->request_method() ne 'POST';
 
-    my $entry_id = $q->param('entry_id')
+    my $entry_id = int($q->param('entry_id'))
       or return $app->error( $app->translate("No entry_id") );
     require MT::Entry;
@@ -787,5 +794,20 @@
         if ( $app->remote_ip =~ /$banned_ip/ ) {
             return $app->handle_error(
-                $app->translate("You are not allowed to add comments.") );
+                $app->translate("Invalid request") );
+        }
+    }
+
+    my $blog = $app->model('blog')->load( $entry->blog_id )
+        or return $app->error($app->translate('Can\'t load blog #[_1].', $entry->blog_id));
+
+    my $armor = $q->param('armor');
+    if (defined $armor) {
+        # For this to work, we must create a site path exactly like
+        # <MTBlogSitePath> does.
+        my $path = $blog->site_path;
+        $path .= '/' unless $path =~ m!/$!;
+        my $site_path_sha1 = MT::Util::perl_sha1_digest_hex($path);
+        if ($armor ne $site_path_sha1) {
+            return $app->handle_error($app->translate("Invalid request; $armor != $site_path_sha1"));
         }
     }
@@ -813,7 +835,4 @@
             $app->translate("Comments are not allowed on this entry.") );
     }
-
-    my $blog = $app->model('blog')->load( $entry->blog_id )
-        or return $app->error($app->translate('Can\'t load blog #[_1].', $entry->blog_id));
 
     my $text = $q->param('text') || '';
@@ -923,22 +942,4 @@
         );
     }
-    if ($commenter) {
-        $commenter->url( $comment->url )
-          if $comment->url && $commenter->type != MT::Author::COMMENTER();
-        $commenter->save
-          or $app->log(
-            {
-                message => $app->translate(
-                    "Commenter save failed with [_1]",
-                    $commenter->errstr
-                ),
-                class   => 'system',
-                blog_id => $blog->id,
-                level   => MT::Log::ERROR()
-            }
-          );
-    }
-
-    #    return $app->handle_error($app->errstr()) unless $comment;
 
     # Form a link to the comment
@@ -947,5 +948,4 @@
         my $url = $app->base . $app->uri;
         $url .= '?entry_id=' . $q->param('entry_id');
-        $url .= '&static=0&arch=1' if ( $q->param('arch') );
         $comment_link = $url;
     }
@@ -953,5 +953,4 @@
         my $static = $q->param('static');
         if ( $static eq '1' ) {
-
             # I think what we really want is the individual archive.
             $comment_link = $entry->permalink;
@@ -959,5 +958,5 @@
         else {
             $static =~ s/[\r\n].*$//s;
-            $comment_link = $static . '#' . $comment->id;
+            $comment_link = $static . '#comment-' . $comment->id;
         }
     }
@@ -968,5 +967,5 @@
         # redirected to the indiv. page it will be up-to-date.
         $app->rebuild_entry( Entry => $entry->id )
-          or return $app->error(
+          or return $app->handle_error(
             $app->translate( "Publish failed: [_1]", $app->errstr ) );
     }
@@ -1001,5 +1000,5 @@
             require MT::DefaultTemplates;
             $tmpl = MT::DefaultTemplates->load({ type => 'comment_response' })
-                or return $app->error($app->translate("Can\'t load template"));
+                or return $app->handle_error($app->translate("Can\'t load template"));
             $tmpl->text( $app->translate_templatized( $tmpl->text ) );
         }
@@ -1097,5 +1096,5 @@
     my %param       = @_;
     my %cookies     = $app->cookies();
-    my $cookie_name = MT::App::COMMENTER_COOKIE_NAME();
+    my $cookie_name = $app->commenter_cookie_name;
     my $session_key = $cookies{$cookie_name}->value() || "";
     $session_key =~ y/+/ /;
@@ -1141,4 +1140,5 @@
     # INACTIVE == BANNED
     return 0 if $status == MT::Author::BANNED();
+    return 0 if $commenter->status == MT::Author::BANNED();
 
     # NOT using $status for this test, since $status may be
@@ -1168,28 +1168,7 @@
                 or return $app->error($app->translate('Can\'t load blog #[_1].', $blog_id));
             if ( $registration->{Allow} && $blog->allow_commenter_regist ) {
-                my $perm = $commenter->blog_perm($blog_id);
-                return 0 unless $perm->is_empty;
-                require MT::Role;
-                require MT::Association;
-                my $role = MT::Role->load_same( undef, undef, 1, 'comment' );
-                if ( $role && $blog ) {
-                    MT::Association->link( $commenter => $role => $blog );
-                }
-                else {
-                    # FIXME: In this case, we should probably return 0
-                    # here, since no permission was actually granted.
-                    $app->log(
-                        {
-                            message => MT->translate(
-"Error assigning commenting rights to user '[_1] (ID: [_2])' for weblog '[_3] (ID: [_4])'. No suitable commenting role was found.",
-                                $commenter->name, $commenter->id,
-                                $blog->name,      $blog->id,
-                            ),
-                            level    => MT::Log::ERROR(),
-                            class    => 'system',
-                            category => 'new'
-                        }
-                    );
-                }
+                # By policy, this blog permits this type of user
+                # and they are not banned (as they have no blog perms/
+                # restrictions, so permit this comment)
                 return 1;
             }
@@ -1368,23 +1347,21 @@
     if ( $q->param('logout') ) {
         my ( $s, $commenter ) = $app->_get_commenter_session();
-        #if ($commenter) {
-        #    require MT::Auth;
-        #    my $ctx = MT::Auth->fetch_credentials( { app => $app } );
-        #    my $cmntr_sess =
-        #      $app->session_user( $commenter, $ctx->{session_id},
-        #        permanent => $ctx->{permanent} );
-        #    if ($cmntr_sess) {
-        #        $app->user($commenter);
-        #        MT::Auth->invalidate_credentials( { app => $app } );
-        #    }
-        #}
+
+        # invalidate credentials in auth layer
+        if ($commenter) {
+           require MT::Auth;
+           my $ctx = MT::Auth->fetch_credentials( { app => $app } );
+           my $cmntr_sess =
+             $app->session_user( $commenter, $ctx->{session_id},
+               permanent => $ctx->{permanent} );
+           if ($cmntr_sess) {
+               $app->user($commenter);
+               MT::Auth->invalidate_credentials( { app => $app } );
+           }
+        }
 
         my %cookies = $app->cookies();
         $app->_invalidate_commenter_session( \%cookies );
-        if ( $commenter && ( 'TypeKey' ne $commenter->auth_type ) ) {
-            # Remove logout parameter so MT does not go to TypeKey
-            # when unnecessary.
-            $app->param( 'logout', 0 );
-        }
+        $app->user($commenter) if $commenter;
         $result = 1;
     }
@@ -1415,33 +1392,28 @@
     my $target;
     require MT::Util;
-    if ( $q->param('static') ) {
-        if ( $q->param('static') eq 1 ) {
-            require MT::Entry;
-            my $entry = MT::Entry->load( $q->param('entry_id') )
-                or return $app->error($app->translate('Can\'t load entry #[_1].', $q->param('entry_id')));
-            $target = $entry->archive_url;
-            my $blog = MT::Blog->load( $entry->blog_id );
-            $target = MT::Util::strip_index( $target, $blog );
-        }
-        else {
-            $target = $q->param('static');
-        }
-    }
-    else {
-        $target =
-          (     $cfg->CGIPath
-              . $cfg->CommentScript
-              . "?entry_id="
-              . $q->param('entry_id')
-              . ( $q->param('arch') ? '&static=0&arch=1' : '' ) );
+    my $static = $q->param('static') || '';
+
+    if ( ($static eq '') || ($static eq 1) ) {
+        require MT::Entry;
+        my $entry = MT::Entry->load( $q->param('entry_id') || 0 )
+            or return $app->error($app->translate('Can\'t load entry #[_1].', $q->param('entry_id')));
+        $target = $entry->archive_url;
+        my $blog = MT::Blog->load( $entry->blog_id );
+        $target = MT::Util::strip_index( $target, $blog );
+    }
+    elsif ($static ne '') {
+        $target = $static;
     }
     if ( $q->param('logout') ) {
-        return $app->redirect(
-            $cfg->SignOffURL . "&_return=" . MT::Util::encode_url($target),
-            UseMeta => 1 );
-    }
-    else {
-        return $app->redirect( $target, UseMeta => 1 );
-    }
+        if ( $app->user &&
+            ( 'TypeKey' eq $app->user->auth_type ) ) {
+            return $app->redirect(
+                $cfg->SignOffURL . "&_return=" .
+                MT::Util::encode_url($target . '#_logout'),
+                UseMeta => 1 );
+        }
+    }
+    return $app->redirect( $target . '#_' .
+        ($q->param('logout') ? 'logout' :  'login'), UseMeta => 1 );
 }
 
@@ -1485,4 +1457,70 @@
 }
 
+sub session_js {
+    my $app = shift;
+    my $blog_id = int($app->param('blog_id'));
+    my $blog = MT::Blog->load( $blog_id ) if $blog_id;
+    my $jsonp = $app->param('jsonp');
+    $jsonp = undef if $jsonp !~ m/^\w+$/;
+
+    my $c;
+    if ( $jsonp && $blog_id && $blog ) {
+        my ( $session, $commenter ) = $app->_get_commenter_session();
+        if ( $session && $commenter ) {
+            my $blog_perms = $commenter->blog_perm($blog_id);
+            my $banned = $commenter->is_banned($blog_id) ? "1" : "0";
+            $banned = 0 if $blog_perms && $blog_perms->can_administer;
+            $banned ||= 1 if $commenter->status == MT::Author::BANNED();
+
+            my $sessobj = MT::Session->load($session);
+            if ($banned) {
+                $sessobj->remove;
+            } else {
+                $sessobj->start( time +
+                    $app->config->CommentSessionTimeout); # extend by timeou
+                $sessobj->save();
+            }
+
+            my $can_comment = $banned ? 0 : 1;
+            $can_comment = 0 unless $blog->allow_unreg_comments || $blog->allow_reg_comments;
+            my $can_post = ($blog_perms && $blog_perms->can_create_post) ? "1" : "0";
+            $c = {
+                name => $commenter->nickname,
+                url => $commenter->url,
+                email => $commenter->email,
+                userpic => scalar $commenter->userpic_url,
+                profile => "", # profile link url
+                is_authenticated => "1",
+                is_trusted => ($commenter->is_trusted() ? "1" : "0"),
+                is_author => ($commenter->type == MT::Author::AUTHOR() ? "1" : "0"),
+                is_anonymous => "0",
+                is_banned => $banned,
+                can_comment => $can_comment,
+                can_post => $can_post,
+            };
+        }
+    }
+
+    unless ($c) {
+        my $can_comment = $blog->allow_anon_comments ? "1" : "0";
+        $c = {
+            is_authenticated => "0",
+            is_trusted => "0",
+            is_anonymous => "1",
+            can_post => "0", # no anonymous posts
+            can_comment => $can_comment,
+            is_banned => "0",
+        };
+    }
+
+    require JSON;
+    $app->{no_print_body} = 1;
+    $app->send_http_header("text/javascript");
+    my $json = JSON::objToJson($c);
+    $app->print("$jsonp(" . $json . ");\n");
+    return undef;
+}
+
+# deprecated
 sub commenter_status_js {
     local $SIG{__WARN__} = sub { };
@@ -1506,4 +1544,5 @@
 }
 
+# deprecated
 sub commenter_name_js {
     local $SIG{__WARN__} = sub { };
@@ -1656,22 +1695,18 @@
     my $app = shift;
 
-    my $id = $app->param('commenter');
-    return $app->handle_error( $app->translate('Invalid commenter ID') )
-      unless $id =~ /\d+/;
-
-    my $url;
-    my $entry_id = $app->param('entry_id');
-    if ($entry_id) {
-        my $entry = MT::Entry->load($entry_id);
-        return $app->handle_error( $app->translate("No entry ID provided") )
-          unless $entry;
-        $url = $entry->permalink;
-    }
-    else {
-        $url = is_valid_url( $app->param('static') );
-    }
-
     my ( $session, $commenter ) = $app->_get_commenter_session();
     if ($commenter) {
+        my $url;
+        my $entry_id = $app->param('entry_id');
+        if ($entry_id) {
+            my $entry = MT::Entry->load($entry_id);
+            return $app->handle_error( $app->translate("Invalid entry ID provided") )
+              unless $entry;
+            $url = $entry->permalink;
+        }
+        else {
+            $url = is_valid_url( $app->param('static') );
+        }
+
         #require MT::Auth;
         #my $ctx = MT::Auth->fetch_credentials( { app => $app } );
@@ -1683,7 +1718,4 @@
 
         my $blog_id = $app->param('blog_id');
-        return $app->handle_error( $app->translate('Permission denied') )
-          unless $commenter->blog_perm($blog_id)->can_comment;
-
         $app->user($commenter);
         my $param = {
@@ -1696,5 +1728,5 @@
             $entry_id ? ( entry_url => $url ) : ( return_url => $url ),
         };
-        $param->{ 'auth_mode_' . $app->config->AuthenticationModule } = 1;
+        $param->{ 'auth_mode_' . $commenter->auth_type } = 1;
         require MT::Auth;
         $param->{'email_required'} = MT::Auth->can_recover_password ? 1 : 0;
@@ -1711,5 +1743,4 @@
       map { $_ => scalar( $q->param($_) ) }
       qw( id name nickname email password pass_verify hint url entry_url return_url external_auth);
-    $param{ 'auth_mode_' . $app->config->AuthenticationModule } = 1;
 
     unless ( $param{id} =~ /\d+/ ) {
@@ -1724,10 +1755,12 @@
     }
 
-    #require MT::Auth;
-    #my $ctx = MT::Auth->fetch_credentials( { app => $app } );
-    #my $cmntr_sess =
+    $param{ 'auth_mode_' . $cmntr->auth_type } = 1;
+
+    # require MT::Auth;
+    # my $ctx = MT::Auth->fetch_credentials( { app => $app } );
+    # my $cmntr_sess =
     #  $app->session_user( $cmntr, $ctx->{session_id},
     #    permanent => $ctx->{permanent} );
-    #return $app->handle_error( $app->translate('Invalid login') )
+    # return $app->handle_error( $app->translate('Invalid login') )
     #  unless $cmntr_sess;
 
@@ -1774,11 +1807,10 @@
     }
     if ($renew_session) {
-        $app->_make_commenter_session( $app->make_magic_token, $cmntr->email,
+        $app->make_commenter_session( $app->make_magic_token, $cmntr->email,
             $cmntr->name,
             ($cmntr->nickname || $app->translate('(Display Name not set)')),
             $cmntr->id );
-        #    $app->start_session( $cmntr, $ctx->{permanent} );
-    }
-    $param{ 'auth_mode_' . $app->config->AuthenticationModule } = 1;
+    }
+
     return $app->build_page( 'profile.tmpl', \%param );
 }
Index: /branches/release-36/tmpl/comment/profile.tmpl
===================================================================
--- /branches/release-36/tmpl/comment/profile.tmpl (revision 1101)
+++ /branches/release-36/tmpl/comment/profile.tmpl (revision 2062)
@@ -94,7 +94,7 @@
 
 <mt:if name="entry_url">
-<p><__trans phrase="Return to the <a href="[_1]">original entry</a>." params="<mt:var name="entry_url">"></p>
+<p><__trans phrase="Return to the <a href="[_1]">original entry</a>." params="<mt:var name="entry_url">#_login"></p>
 <mt:else>
-<p><__trans phrase="Return to the <a href="[_1]">original page</a>." params="<mt:var name="return_url">"></p>
+<p><__trans phrase="Return to the <a href="[_1]">original page</a>." params="<mt:var name="return_url">#_login"></p>
 </mt:else></mt:if>
 
